package api import ( "net/http" "sakura/engine" "slices" "uuid" "github.com/gorilla/websocket" ) type Conn struct { Socket *websocket.Conn } var upgrader = websocket.Upgrader{} var games = make(map[uuid.UUID]*engine.Game) var connections = make(map[uuid.UUID][]*Conn) func GameCreate(w http.ResponseWriter, r *http.Request) { id := uuid.NewV7() games[id] = engine.NewGame() w.Write([]byte(id.String())) } func GameConnect(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") uid, err := uuid.Parse(id) if err != nil { http.Error(w, "unable to parse game uuid "+err.Error(), http.StatusBadRequest) return } game := games[uid] if game == nil { http.Error(w, "game not found", http.StatusNotFound) return } wsConn, err := upgrader.Upgrade(w, r, nil) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if wsConn == nil { http.Error(w, "unable to initialize websocket", http.StatusInternalServerError) return } conn := &Conn{wsConn} connections[uid] = append(connections[uid], conn) wsConn.SetCloseHandler(func(code int, text string) error { connections[uid] = slices.DeleteFunc(connections[uid], func(potential *Conn) bool { return potential == conn }) return nil }) err = wsConn.WriteJSON(game) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } go PumpRead(uid, game, wsConn) } func Update(id uuid.UUID, g *engine.Game) { for _, c := range connections[id] { _ = c.Socket.WriteJSON(g) } } func PumpRead(id uuid.UUID, g *engine.Game, conn *websocket.Conn) { var interaction engine.InteractionID for { err := conn.ReadJSON(&interaction) if err != nil { break } a := g.Actions[interaction] if a == nil { continue } a.Then(g) g.ActionToHistory(a) Update(id, g) } }