diff --git a/src/state/fsm/lobby/events.go b/src/state/fsm/lobby/events.go index 4afec46..0891180 100644 --- a/src/state/fsm/lobby/events.go +++ b/src/state/fsm/lobby/events.go @@ -2,11 +2,20 @@ package lobby import ( "context" + "gitea/price-is-wrong/src/lib/db" lobby "gitea/price-is-wrong/src/state/fsm/lobby/internal" - "io" + "slices" ) -func (l *Lobby) withEvent(ctx context.Context, e lobby.Event) error { +func (l *Lobby) Join(ctx context.Context, id int) error { + return l.upsertEvent(ctx, lobby.PlayerJoin{ID: id}) +} + +func (l *Lobby) Leave(ctx context.Context, id int) error { + return l.upsertEvent(ctx, lobby.PlayerLeave{ID: id}) +} + +func (l *Lobby) upsertEvent(ctx context.Context, e lobby.Event) error { if err := upsertEvent(ctx, l.id, e); err != nil { return err } @@ -25,6 +34,21 @@ func upsertEvent(ctx context.Context, lobbyID int, e lobby.Event) error { if err != nil { return err } - _ = b - return io.EOF + + _, err = db.From(ctx).ExecContext(ctx, ` + INSERT INTO lobby_events (lobby_id, payload) VALUES (?, ?) + `, lobbyID, b) + return err +} + +func (l *Lobby) apply(e lobby.Event) error { + switch e := e.(type) { + case lobby.PlayerJoin: + if !slices.Contains(l.Players, e.ID) { + l.Players = append(l.Players, e.ID) + } + case lobby.PlayerLeave: + l.Players = slices.DeleteFunc(l.Players, func(id int) bool { return id == e.ID }) + } + return nil } diff --git a/src/state/fsm/lobby/lobby_test.go b/src/state/fsm/lobby/lobby_test.go index 9c443aa..4588fc8 100644 --- a/src/state/fsm/lobby/lobby_test.go +++ b/src/state/fsm/lobby/lobby_test.go @@ -7,9 +7,41 @@ import ( ) func TestOpen(t *testing.T) { - l, err := lobby.Open(lib.NewTestCtx(t), "id") + ctx := lib.NewTestCtx(t) + + l, err := lobby.Open(ctx, "id") if err != nil { t.Fatal(err) } t.Logf("%+v", l) + + if len(l.Players) != 0 { + t.Errorf("new lobby has players: %+v", l.Players) + } + + if err := l.Join(ctx, 1); err != nil { + t.Fatal("failed to join:", err) + } else if len(l.Players) != 1 { + t.Errorf("wrong number of players after first join: %+v", l.Players) + } + + if err := l.Leave(ctx, 1); err != nil { + t.Fatal("failed to join:", err) + } else if len(l.Players) != 0 { + t.Errorf("wrong number of players after only leaves: %+v", l.Players) + } + + if err := l.Join(ctx, 1); err != nil { + t.Fatal("failed to join:", err) + } else if err := l.Join(ctx, 1); err != nil { + t.Fatal("failed to join redundant:", err) + } else if len(l.Players) != 1 { + t.Errorf("redundant join yielded wrong players: %+v", l.Players) + } + + if err := l.Join(ctx, 2); err != nil { + t.Fatal("failed to second join:", err) + } else if len(l.Players) != 2 { + t.Errorf("second join yielded wrong players: %+v", l.Players) + } } diff --git a/src/state/fsm/lobby/open.go b/src/state/fsm/lobby/open.go index 13f25aa..834a32b 100644 --- a/src/state/fsm/lobby/open.go +++ b/src/state/fsm/lobby/open.go @@ -6,7 +6,6 @@ import ( "fmt" "gitea/price-is-wrong/src/lib/db" lobby "gitea/price-is-wrong/src/state/fsm/lobby/internal" - "slices" ) type Lobby struct { @@ -61,7 +60,7 @@ func openID(ctx context.Context, id int) (*Lobby, error) { rows, err := db.From(ctx).QueryContext(ctx, ` SELECT payload FROM lobby_events - WHERE lobby_events.lobby_id=(SELECT id FROM lobbies WHERE name=?) + WHERE lobby_events.lobby_id=? ORDER BY id `, id) if err != nil { @@ -79,11 +78,8 @@ func openID(ctx context.Context, id int) (*Lobby, error) { if err != nil { return nil, fmt.Errorf("failed to parse event: %w", err) } - switch e := event.(type) { - case lobby.PlayerJoin: - result.Players = append(result.Players, e.ID) - case lobby.PlayerLeave: - result.Players = slices.DeleteFunc(result.Players, func(id int) bool { return id == e.ID }) + if err := result.apply(event); err != nil { + return nil, fmt.Errorf("failed to apply event %s: %w", b, err) } } diff --git a/src/state/fsm/lobby/players.go b/src/state/fsm/lobby/players.go deleted file mode 100644 index 73c348d..0000000 --- a/src/state/fsm/lobby/players.go +++ /dev/null @@ -1,14 +0,0 @@ -package lobby - -import ( - "context" - lobby "gitea/price-is-wrong/src/state/fsm/lobby/internal" -) - -func (l *Lobby) Join(ctx context.Context, id int) error { - return l.withEvent(ctx, lobby.PlayerJoin{ID: id}) -} - -func (l *Lobby) Leave(ctx context.Context, id int) error { - return l.withEvent(ctx, lobby.PlayerLeave{ID: id}) -}