// ws.go package main import ( "encoding/json" "log" "net/http" "time" "unicode/utf8" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, // okay while you're behind nginx/caddy CheckOrigin: func(r *http.Request) bool { return true }, } func wsHandler(hub *Hub) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("upgrade error: %v", err) return } // Expect first message to be auth _, firstMsg, err := conn.ReadMessage() if err != nil { log.Printf("failed to read auth message: %v", err) conn.Close() return } var auth IncomingMessage if err := json.Unmarshal(firstMsg, &auth); err != nil { log.Printf("invalid auth json: %v", err) _ = conn.WriteJSON(AuthError{Type: "auth_error", Error: "bad_json"}) conn.Close() return } if auth.Type != "auth" || auth.Token == "" { _ = conn.WriteJSON(AuthError{Type: "auth_error", Error: "missing_token"}) conn.Close() return } // Lookup token hub.mu.RLock() tc, ok := hub.tokens[auth.Token] hub.mu.RUnlock() if !ok || tc.Revoked { _ = conn.WriteJSON(AuthError{Type: "auth_error", Error: "invalid_token"}) conn.Close() return } if auth.ServerID == "" { auth.ServerID = "default" } if auth.Nick == "" { auth.Nick = tc.Name } // Enforce nickname length limit on initial/auth nick. if utf8.RuneCountInString(auth.Nick) > maxNickLen { log.Printf("auth nick %q too long, falling back to internal name %q", auth.Nick, tc.Name) auth.Nick = tc.Name } if utf8.RuneCountInString(auth.Nick) > maxNickLen { // still too long, truncate internal name log.Printf("internal name %q too long, truncating to %d runes", auth.Nick, maxNickLen) auth.Nick = truncateRunes(auth.Nick, maxNickLen) } client := &Client{ hub: hub, conn: conn, send: make(chan []byte, 32), token: tc, nick: auth.Nick, serverID: auth.ServerID, playerUUID: auth.PlayerUUID, lastSeen: time.Now(), } hub.register(client) if err := conn.WriteJSON(AuthOK{ Type: "auth_ok", InternalName: tc.Name, }); err != nil { log.Printf("failed to send auth_ok: %v", err) hub.unregister(client) conn.Close() return } go client.writePump() client.readPump() } }