drop observers who have left
This commit is contained in:
parent
245109883a
commit
f1f58a3893
32
game.go
32
game.go
@ -46,6 +46,11 @@ func applyAction(g *game.Match, a action) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type observer struct {
|
||||||
|
conn *websocket.Conn
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
// gameActor is an actor that updates a game's state and relays changes to all
|
// gameActor is an actor that updates a game's state and relays changes to all
|
||||||
// observers.
|
// observers.
|
||||||
func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-chan person) {
|
func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-chan person) {
|
||||||
@ -53,7 +58,7 @@ func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-
|
|||||||
// definitely expired.
|
// definitely expired.
|
||||||
ctx, stop := context.WithTimeoutCause(ctx, 4*time.Hour, errMatchExpired)
|
ctx, stop := context.WithTimeoutCause(ctx, 4*time.Hour, errMatchExpired)
|
||||||
defer stop()
|
defer stop()
|
||||||
var obs []person
|
var obs []observer
|
||||||
actions := make(chan action, 2)
|
actions := make(chan action, 2)
|
||||||
go playerActor(ctx, dealer, actions)
|
go playerActor(ctx, dealer, actions)
|
||||||
go playerActor(ctx, chall, actions)
|
go playerActor(ctx, chall, actions)
|
||||||
@ -72,10 +77,8 @@ func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-
|
|||||||
go p.conn.Close(websocket.StatusNormalClosure, "looks like you dropped")
|
go p.conn.Close(websocket.StatusNormalClosure, "looks like you dropped")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
obs = append(obs, p)
|
q := p.conn.CloseRead(ctx)
|
||||||
// TODO(zeph): CloseRead returns a context we can use to drop the
|
obs = append(obs, observer{conn: p.conn, ctx: q})
|
||||||
// observer when they disconnect
|
|
||||||
p.conn.CloseRead(ctx)
|
|
||||||
case a := <-actions:
|
case a := <-actions:
|
||||||
slog.DebugContext(ctx, "got action", "from", a.Player, "action", a.Action)
|
slog.DebugContext(ctx, "got action", "from", a.Player, "action", a.Action)
|
||||||
err := applyAction(g, a)
|
err := applyAction(g, a)
|
||||||
@ -102,6 +105,13 @@ func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-
|
|||||||
slog.ErrorContext(ctx, "action caused a mystery error", "from", a.Player, "action", a.Action, "err", err.Error())
|
slog.ErrorContext(ctx, "action caused a mystery error", "from", a.Player, "action", a.Action, "err", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clear observers who have left.
|
||||||
|
for k := len(obs) - 1; k >= 0; k-- {
|
||||||
|
if obs[k].ctx.Err() != nil {
|
||||||
|
obs[k], obs[len(obs)-1] = obs[len(obs)-1], observer{}
|
||||||
|
obs = obs[:len(obs)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +137,7 @@ func playerActor(ctx context.Context, p person, actions chan<- action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func broadcast(ctx context.Context, g *game.Match, dealer, chall person, obs []person) {
|
func broadcast(ctx context.Context, g *game.Match, dealer, chall person, obs []observer) {
|
||||||
// TODO(zeph): this probably should return an error or some other signal
|
// TODO(zeph): this probably should return an error or some other signal
|
||||||
// if a player drops so that the actor knows to quit
|
// if a player drops so that the actor knows to quit
|
||||||
if err := wsjson.Write(ctx, dealer.conn, g.DTO(dealer.id)); err != nil {
|
if err := wsjson.Write(ctx, dealer.conn, g.DTO(dealer.id)); err != nil {
|
||||||
@ -138,14 +148,18 @@ func broadcast(ctx context.Context, g *game.Match, dealer, chall person, obs []p
|
|||||||
// TODO(zeph): concede, but we need to be careful not to recurse
|
// TODO(zeph): concede, but we need to be careful not to recurse
|
||||||
slog.DebugContext(ctx, "lost challenger", "player", chall.id, "err", err.Error())
|
slog.DebugContext(ctx, "lost challenger", "player", chall.id, "err", err.Error())
|
||||||
}
|
}
|
||||||
|
if len(obs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d := g.DTO(player.ID{})
|
||||||
for _, p := range obs {
|
for _, p := range obs {
|
||||||
if err := wsjson.Write(ctx, p.conn, g.DTO(p.id)); err != nil {
|
if err := wsjson.Write(ctx, p.conn, &d); err != nil {
|
||||||
slog.DebugContext(ctx, "lost observer", "player", p.id, "err", err.Error())
|
slog.DebugContext(ctx, "lost observer", "err", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gameOver(ctx context.Context, dealer, chall person, obs []person) {
|
func gameOver(ctx context.Context, dealer, chall person, obs []observer) {
|
||||||
// TODO(zeph): need to communicate to the server that these have gone away
|
// TODO(zeph): need to communicate to the server that these have gone away
|
||||||
go dealer.conn.Close(websocket.StatusNormalClosure, "match ended")
|
go dealer.conn.Close(websocket.StatusNormalClosure, "match ended")
|
||||||
go chall.conn.Close(websocket.StatusNormalClosure, "match ended")
|
go chall.conn.Close(websocket.StatusNormalClosure, "match ended")
|
||||||
|
Loading…
Reference in New Issue
Block a user