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 }