gosora/common/ws_user.go

200 lines
3.8 KiB
Go

package common
import (
"errors"
"sync"
"time"
"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 {
User *User
Sockets []*WSUserSocket
sync.Mutex
}
type WSUserSocket struct {
conn *websocket.Conn
Page string
}
func (u *WSUser) Ping() error {
for _, socket := range u.Sockets {
if socket == nil {
continue
}
socket.conn.SetWriteDeadline(time.Now().Add(time.Minute))
err := socket.conn.WriteMessage(websocket.PingMessage, nil)
if err != nil {
socket.conn.Close()
}
}
return nil
}
func (u *WSUser) WriteAll(msg string) error {
msgbytes := []byte(msg)
for _, socket := range u.Sockets {
if socket == nil {
continue
}
w, err := socket.conn.NextWriter(websocket.TextMessage)
if err != nil {
return err
}
_, _ = w.Write(msgbytes)
w.Close()
}
return nil
}
func (u *WSUser) WriteToPage(msg, page string) error {
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 {
var success bool
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page != page {
continue
}
w, err := socket.conn.NextWriter(websocket.TextMessage)
if err != nil {
continue // Skip dead sockets, a dedicated goroutine handles those
}
_, _ = w.Write(msg)
w.Close()
success = true
}
if !success {
return ErrNoneOnPage
}
return nil
}
// Inefficient as it looks for sockets for a page even if there are none
func (u *WSUser) WriteToPageBytesMulti(msgs [][]byte, page string) error {
var success bool
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page != page {
continue
}
w, err := socket.conn.NextWriter(websocket.TextMessage)
if err != 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
}
func (u *WSUser) AddSocket(conn *websocket.Conn, page string) {
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) {
u.Lock()
defer u.Unlock()
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 {
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 {
u.Lock()
defer u.Unlock()
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page == page {
return true
}
}
return false
}
func (u *WSUser) FinalizePage(page string, handle func()) {
u.Lock()
defer u.Unlock()
for _, socket := range u.Sockets {
if socket == nil {
continue
}
if socket.Page == page {
return
}
}
handle()
}