diff --git a/cmd/server/games.go b/cmd/server/games.go index 6f257a0..d9b9e9b 100644 --- a/cmd/server/games.go +++ b/cmd/server/games.go @@ -61,6 +61,18 @@ func (games Games) GamesForUser(ctx context.Context, id string) ([]string, error return result, err } +func (games Games) UserName(ctx context.Context, id string) (string, error) { + result := "" + err := games.db.Query(ctx, func(rows *sql.Rows) error { + return rows.Scan(&result) + }, ` + SELECT users.name + FROM users + WHERE users.uuid=? + `, id) + return result, err +} + func (games Games) GameByName(ctx context.Context, uid, name string) (string, error) { var result string err := games.db.Query(ctx, func(rows *sql.Rows) error { @@ -80,6 +92,7 @@ func (games Games) GameByName(ctx context.Context, uid, name string) (string, er type ( GameState struct { + Started bool Completed time.Time Players map[string]PlayerState } @@ -183,6 +196,7 @@ func (games Games) GameState(ctx context.Context, id string) (GameState, error) result.Completed = timestamp return nil case AssignmentRotation: + result.Started = true var assignmentRotation EventAssignmentRotation if err := json.Unmarshal(payload, &assignmentRotation); err != nil { return err @@ -250,12 +264,21 @@ func (games Games) CreateGame(ctx context.Context, name string) (string, error) `, id, time.Now(), name) } -func (games Games) CreateEventPlayerJoin(ctx context.Context, id string, player string) error { +func (games Games) CreateEventPlayerJoin(ctx context.Context, id string, player, name string) error { + if err := games.db.Exec(ctx, ` + INSERT INTO users ( + uuid, + name + ) VALUES (?, ?) + ON CONFLICT DO UPDATE SET name=? WHERE uuid=?; + `, player, name, name, player); err != nil { + return err + } if err := games.db.Exec(ctx, ` INSERT INTO players ( game_uuid, user_uuid - ) VALUES (?, ?) + ) VALUES (?, ?); `, id, player); err != nil { return err } diff --git a/cmd/server/games_test.go b/cmd/server/games_test.go index 6fa07e4..97a1093 100644 --- a/cmd/server/games_test.go +++ b/cmd/server/games_test.go @@ -53,7 +53,7 @@ func TestGames(t *testing.T) { t.Fatal("redundant create game didnt return same id:", id2) } - if err := games.CreateEventPlayerJoin(ctx, id, "p0"); err != nil { + if err := games.CreateEventPlayerJoin(ctx, id, "p0", "player zero"); err != nil { t.Fatal("err creating event player join:", err) } else if err := games.CreateEventPlayerLeave(ctx, id, "p0"); err != nil { t.Fatal("err creating event player leave:", err) @@ -61,9 +61,14 @@ func TestGames(t *testing.T) { for i := 0; i < 4; i++ { p := fmt.Sprintf("p%d", i+1) - if err := games.CreateEventPlayerJoin(ctx, id, p); err != nil { + if err := games.CreateEventPlayerJoin(ctx, id, p, "player "+p); err != nil { t.Fatal(p, "err creating event player join", err) } + if name, err := games.UserName(ctx, p); err != nil { + t.Fatal(p, "err getting user name", err) + } else if name == "" { + t.Fatal("name empty") + } } if err := games.CreateEventAssignmentRotation(ctx, id, "", "", "", 1); err != nil { diff --git a/cmd/server/ws.go b/cmd/server/ws.go index 8a0750b..e2912cc 100644 --- a/cmd/server/ws.go +++ b/cmd/server/ws.go @@ -1,9 +1,13 @@ package main import ( + "context" + "encoding/json" "fmt" + "log" "net/http" "strings" + "time" "github.com/coder/websocket" ) @@ -12,18 +16,73 @@ func isWS(r *http.Request) bool { return r.URL.Path == "/ws" || strings.HasPrefix(r.URL.Path, "/ws/") } -func (s *S) serveWS(httpw http.ResponseWriter, httpr *http.Request) error { - ctx := httpr.Context() +func (s *S) serveWS(w http.ResponseWriter, r *http.Request) error { + ctx, can := context.WithCancel(r.Context()) + defer can() + r = r.WithContext(ctx) - c, err := websocket.Accept(httpw, httpr, nil) + session := s.Session(ctx) + games, err := s.games.GamesForUser(ctx, session.ID) + if err != nil { + return err + } + if len(games) == 0 { + return fmt.Errorf("user %s is in zero games", session.ID) + } + game := games[0] + + c, err := websocket.Accept(w, r, nil) if err != nil { return err } defer c.CloseNow() - if err := c.Write(ctx, 1, []byte("hello world")); err != nil { - return err + go func() { + defer can() + for { + _, b, err := c.Read(ctx) + if err != nil { + log.Println(err) + return + } + log.Printf("READ %s", b) + } + }() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(time.Second * 1): + } + + gameState, err := s.games.GameState(ctx, game) + if err != nil { + return err + } + + if gameState.Started { + break + } + + items := []map[string]any{} + for k := range gameState.Players { + name, err := s.games.UserName(ctx, k) + if err != nil { + return err + } + items = append(items, map[string]any{"name": name}) + } + msg := map[string]any{ + "page": "A", + "items": items, + } + + msgB, _ := json.Marshal(msg) + if err := c.Write(ctx, 1, msgB); err != nil { + return err + } } - return fmt.Errorf("not impl") + return fmt.Errorf("not impl: game started") }