Files
LargeHadronCollider/api/ws/main.go
2026-01-07 00:16:15 -06:00

129 lines
2.6 KiB
Go

package ws
import (
"errors"
"fmt"
"log"
"net"
"net/http"
"strings"
"github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil"
"zomo.dev/largehadroncollider/db"
"zomo.dev/largehadroncollider/ttv"
"zomo.dev/largehadroncollider/util"
)
func InitWSServer(conf *util.Config, dbConn *db.DBConn, twitchConn *ttv.TwitchConn) (*WSServer, error) {
return &WSServer{conf, dbConn, twitchConn}, nil
}
type WSServer struct {
conf *util.Config
db *db.DBConn
twitch *ttv.TwitchConn
}
type WSConn struct {
conf *util.Config
c net.Conn
events []string
authrorized bool
}
func (wsServer *WSServer) Handle(w http.ResponseWriter, r *http.Request) error {
conn, _, _, err := ws.UpgradeHTTP(r, w)
if err != nil {
return err
}
wsconn := &WSConn{}
go wsconn.handleThread(wsServer.conf, conn)
return nil
}
func (conn *WSConn) handleThread(conf *util.Config, c net.Conn) {
conn.conf = conf
conn.c = c
defer c.Close()
for {
msg, _, err := wsutil.ReadClientData(conn.c)
if err != nil {
// TODO handle error better, print more conn info
log.Printf("Error reading data from ws connection %v", err)
continue
}
cmd, err := parseCommand(string(msg))
if err != nil {
log.Printf("Error parsing command data from ws connection %v", err)
continue
}
log.Printf("%+v", cmd)
err = conn.runCommand(cmd)
if err != nil {
_, err := fmt.Fprintf(conn.c, "error running command: %s: %v", cmd.Command, err)
if err != nil {
// TODO better print
log.Printf("ERROR: unable to send error to client: %v", err)
log.Printf("ERROR: client details: %+v", conn)
log.Printf("ERROR: command details: %+v", cmd)
return
}
}
}
}
func (conn *WSConn) runCommand(cmd *Command) error {
switch strings.ToLower(cmd.Command) {
case "ping":
return conn.runCommandPing(cmd.Args)
case "authorization":
return conn.runCommandAuthorization(cmd.Args)
case "events-add":
return conn.runCommandEventsAdd(cmd.Args)
default:
return fmt.Errorf("invalid command: %s", cmd.Command)
}
}
func (conn *WSConn) runCommandPing(_ []string) error {
_, err := fmt.Fprint(conn.c, "pong")
return err
}
func (conn *WSConn) runCommandAuthorization(args []string) error {
if conn.authrorized {
return errors.New("connection already authorized")
}
if len(args) < 1 {
return errors.New("no authorization key given")
}
key := args[0]
if key != conn.conf.WSAuthorization {
return errors.New("invalid authorization key")
}
conn.authrorized = true
return nil
}
func (conn *WSConn) runCommandEventsAdd(args []string) error {
if !conn.authrorized {
return errors.New("unauthorized")
}
// TODO subscribe
return nil
}