saerro-go/cmd/ws/wsmanager/wsmanager.go

124 lines
3 KiB
Go

package wsmanager
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"time"
"git.sapphic.engineer/ps2.live/saerro-go/cmd/ws/eventhandler"
"git.sapphic.engineer/ps2.live/saerro-go/types"
"github.com/coder/websocket"
)
type WebsocketManager struct {
Conn *websocket.Conn
EventHandler eventhandler.EventHandler
Closed chan bool
}
func NewWebsocketManager(eh eventhandler.EventHandler) WebsocketManager {
return WebsocketManager{
EventHandler: eh,
Closed: make(chan bool, 1),
}
}
func (wsm *WebsocketManager) Connect(ctx context.Context, addr string) (err error) {
wsm.Conn, _, err = websocket.Dial(ctx, addr, nil)
if err != nil {
return fmt.Errorf("wsm: connect failed: %w", err)
}
log.Println("wsm: connected to", addr)
return
}
type ESSSubscription struct {
Action string `json:"action,omitempty"`
Worlds []string `json:"worlds,omitempty"`
EventNames []string `json:"eventNames,omitempty"`
Characters []string `json:"characters,omitempty"`
Service string `json:"service,omitempty"`
LogicalAndCharactersWithWorlds bool `json:"logicalAndCharactersWithWorlds,omitempty"`
}
func (wsm *WebsocketManager) Subscribe(ctx context.Context) error {
sub := ESSSubscription{
Action: "subscribe",
Service: "event",
Worlds: []string{"all"},
EventNames: getEventNames(),
Characters: []string{"all"},
LogicalAndCharactersWithWorlds: true,
}
var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(sub)
if err != nil {
return fmt.Errorf("wsm: subscribe: json encode failed: %w", err)
}
log.Printf("wsm: subscribe message: %s", buf.String())
err = wsm.Conn.Write(ctx, websocket.MessageText, buf.Bytes())
if err != nil {
return fmt.Errorf("wsm: subscribe: ws write failed: %w", err)
}
return nil
}
func (wsm *WebsocketManager) Start() {
go wsm.startWatchdog()
for {
ctx := context.Background()
var event types.ESSData
_, data, err := wsm.Conn.Read(ctx)
if err != nil {
log.Fatalln("wsm: read failed:", err)
}
log.Printf("raw event: %s", string(data))
err = json.Unmarshal(data, &event)
if err != nil {
log.Println("wsm: json unmarshal failed:", err)
log.Println("wsm: json unmarshal failed (payload)", string(data))
}
go wsm.EventHandler.HandleEvent(ctx, event.Payload)
}
}
func (wsm *WebsocketManager) startWatchdog() {
for {
time.Sleep(time.Second * 30)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
err := wsm.Conn.Ping(ctx)
if err != nil {
log.Println("wsm: watchdog failed")
wsm.Closed <- true
}
cancel()
}
}
func (wsm *WebsocketManager) Close() {
wsm.Conn.Close(websocket.StatusNormalClosure, "")
wsm.Closed <- true
}
func (wsm *WebsocketManager) FailClose() {
wsm.Conn.Close(websocket.StatusAbnormalClosure, "")
wsm.Closed <- true
}