gosora/common/ws_user.go

246 lines
5.8 KiB
Go
Raw Permalink Normal View History

package common
import (
2022-02-21 03:32:53 +00:00
"errors"
"sync"
"time"
2022-02-21 03:32:53 +00:00
"github.com/gorilla/websocket"
)
var ErrNoneOnPage = errors.New("This user isn't on that page")
var ErrInvalidSocket = errors.New("That's not a valid WebSocket Connection")
type WSUser struct {
2022-02-21 03:32:53 +00:00
User *User
Sockets []*WSUserSocket
sync.Mutex
}
type WSUserSocket struct {
2022-02-21 03:32:53 +00:00
conn *websocket.Conn
Page string
}
func (u *WSUser) Ping() error {
2022-02-21 03:32:53 +00:00
var sockets []*WSUserSocket
var del int
func() {
u.Lock()
defer u.Unlock()
for i, s := range u.Sockets {
if s == nil || s.conn == nil {
del++
u.Sockets[i] = u.Sockets[len(u.Sockets)-del]
continue
}
sockets = append(sockets, s)
}
}()
if del > 0 {
// TODO: Resize the capacity to release memory more eagerly?
u.Sockets = u.Sockets[:len(u.Sockets)-del]
}
for _, s := range sockets {
_ = s.conn.SetWriteDeadline(time.Now().Add(time.Minute))
e := s.conn.WriteMessage(websocket.PingMessage, nil)
if e != nil {
s.conn.Close()
u.Lock()
s.conn = nil
u.Unlock()
}
}
return nil
Client templates can now be overriden like every other template. The client templates load earlier now for a smoother user experience. Added a setting for setting a Google Site Verification meta tag without editing header.html Added support for favicons. /static/favicon.ico will be mapped to favicon.ico, if it exists. The parent forum is now visible on the topics list for Nox. Language headers which contain the wildcard character are no longer considered unknowns. Meta descriptions and open graph descriptions are no longer emitted for logged in users. Slimmed down topics_topic slightly for Nox. Pre-parsed widgets are now minified. Stale WebSockets connections should be cleaned up far quicker now. Template generation is now logged separately. Commented out some obsolete template logic. Marked a few template generator fields as unexported. Fixed the styling for the ban page in the profile for Nox. Fixed the styling for colline for Cosora and Tempra Simple. Fixed the sidebar overflowing outside of the box on Nox. Fixed the meta description text overflowing the box in the Setting Manager on Nox. Fixed excessive padding in the Page Manager. Fixed a few missing border on the profiles for Tempra Simple. Fixed the sidebar appearing in places it shouldn't on Tempra Simple. Fixed the status code emitted by NotFoundJS Fixed a bug where Gosora kept falling back to interpreted templates. Fixed a bug where WebSockets connections weren't getting closed properly if the user cache overflowed. Fixed a bug where WebSocket connections weren't getting initialised for guests. Fixed a bug where template overrides weren't always getting applied. Fixed a bug where root template overrides weren't always getting applied. Added the google_site_verify setting. Added the google_site_verify phrase. You will need to run the patcher or updater for this commit.
2019-02-28 07:28:17 +00:00
}
func (u *WSUser) WriteAll(msg string) error {
2022-02-21 03:32:53 +00:00
msgbytes := []byte(msg)
for _, socket := range u.Sockets {
if socket == nil {
continue
}
w, e := socket.conn.NextWriter(websocket.TextMessage)
if e != nil {
return e
}
_, _ = w.Write(msgbytes)
w.Close()
}
return nil
}
2020-02-05 02:48:35 +00:00
func (u *WSUser) WriteToPage(msg, page string) error {
2022-02-21 03:32:53 +00:00
return u.WriteToPageBytes([]byte(msg), page)
}
// Inefficient as it looks for sockets for a page even if there are none
func (u *WSUser) WriteToPageBytes(msg []byte, page string) error {
2022-02-21 03:32:53 +00:00
var success bool
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page != page {
continue
}
w, e := socket.conn.NextWriter(websocket.TextMessage)
if e != nil {
continue // Skip dead sockets, a dedicated goroutine handles those
}
_, _ = w.Write(msg)
w.Close()
success = true
}
if !success {
return ErrNoneOnPage
}
return nil
}
2020-07-16 10:51:34 +00:00
// Inefficient as it looks for sockets for a page even if there are none
func (u *WSUser) WriteToPageBytesMulti(msgs [][]byte, page string) error {
2022-02-21 03:32:53 +00:00
var success bool
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page != page {
continue
}
w, e := socket.conn.NextWriter(websocket.TextMessage)
if e != nil {
continue // Skip dead sockets, a dedicated goroutine handles those
}
for _, msg := range msgs {
_, _ = w.Write(msg)
}
w.Close()
success = true
}
if !success {
return ErrNoneOnPage
}
return nil
2020-07-16 10:51:34 +00:00
}
func (u *WSUser) CountSockets() int {
2022-02-21 03:32:53 +00:00
u.Lock()
defer u.Unlock()
return len(u.Sockets)
}
func (u *WSUser) AddSocket(conn *websocket.Conn, page string) {
2022-02-21 03:32:53 +00:00
u.Lock()
// If the number of the sockets is small, then we can keep the size of the slice mostly static and just walk through it looking for empty slots
/*if len(u.Sockets) < 6 {
for i, socket := range u.Sockets {
if socket == nil {
u.Sockets[i] = &WSUserSocket{conn, page}
u.Unlock()
//fmt.Printf("%+v\n", u.Sockets)
return
}
}
}*/
u.Sockets = append(u.Sockets, &WSUserSocket{conn, page})
//fmt.Printf("%+v\n", u.Sockets)
u.Unlock()
}
func (u *WSUser) RemoveSocket(conn *websocket.Conn) {
2022-02-21 03:32:53 +00:00
var del int
u.Lock()
defer u.Unlock()
for i, socket := range u.Sockets {
if socket == nil || socket.conn == nil {
del++
u.Sockets[i] = u.Sockets[len(u.Sockets)-del]
} else if socket.conn == conn {
del++
u.Sockets[i] = u.Sockets[len(u.Sockets)-del]
//break
}
}
//Logf("%+v\n", u.Sockets)
//Log("del: ", del)
if del > 0 {
// TODO: Resize the capacity to release memory more eagerly?
u.Sockets = u.Sockets[:len(u.Sockets)-del]
}
//Logf("%+v\n", u.Sockets)
return
if len(u.Sockets) < 6 {
for i, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.conn == conn {
u.Sockets[i] = nil
//fmt.Printf("%+v\n", wsUser.Sockets)
return
}
}
}
var key int
for i, socket := range u.Sockets {
if socket.conn == conn {
key = i
break
}
}
u.Sockets = append(u.Sockets[:key], u.Sockets[key+1:]...)
//fmt.Printf("%+v\n", u.Sockets)
}
func (u *WSUser) SetPageForSocket(conn *websocket.Conn, page string) error {
2022-02-21 03:32:53 +00:00
if conn == nil {
return ErrInvalidSocket
}
u.Lock()
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.conn == conn {
socket.Page = page
}
}
u.Unlock()
return nil
}
func (u *WSUser) InPage(page string) bool {
2022-02-21 03:32:53 +00:00
u.Lock()
defer u.Unlock()
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page == page {
return true
}
}
return false
}
WIP forum action code. Currently disabled. Add Http Conn Count tracking. Move more panel phrases into the panel namespace. Use a string builder in hookgen. Use Countf() in a couple of places to eliminate boilerplate. Reduce prepared stmt boilerplate in forum store with a lambda. Reduce prepared stmt boilerplate in topic.go with a lambda. Reduce prepared stmt boilerplate in group.go with a lambda. Add TestSetCreatedAt method to *Topic. Add DateOlderThanQ method to *accDeleteBuilder and *accUpdateBuilder. Add Stmt method to *accUpdateBuilder and *AccSelectBuilder. Add AccBuilder interface. Shorten variable names. Shorten extractPerm name to ep. Add avatar_visibility setting stub. Implementation coming in a later commit. Don't set an IP for installer generated posts. Add counters_perf_tick_row hook. Add avatar_visibility phrase. Add avatar_visibility_label phrase. Rename forums_no_description to forums_no_desc. Rename panel.forums_create_description_label to panel.forums_create_desc_label. Rename panel.forums_create_description to panel.forums_create_desc. Rename panel_forum_description to panel.forum_desc. Rename panel_forum_description_placeholder to panel.forum_desc_placeholder. Add panel_debug_http_conns_label phrase. Add panel.forum_actions_head phrase. Add panel.forum_actions_create_head phrase. Add panel.forum_action_run_on_topic_creation phrase. Add panel.forum_action_run_days_after_topic_creation phrase. Add panel.forum_action_run_days_after_topic_last_reply phrase. Add panel.forum_action_action phrase. Add panel.forum_action_action_delete phrase. Add panel.forum_action_action_lock phrase. Add panel.forum_action_action_unlock phrase. Add panel.forum_action_action_move phrase. Add panel.forum_action_extra phrase. Add panel.forum_action_create_button phrase. You will need to run the patcher / updater for this commit.
2021-04-07 14:23:11 +00:00
func (u *WSUser) FinalizePage(page string, h func()) {
2022-02-21 03:32:53 +00:00
u.Lock()
defer u.Unlock()
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page == page {
return
}
}
h()
}