exchange syncing persons in matchmaking
This commit is contained in:
parent
82aba814e6
commit
658634c0db
8
game.go
8
game.go
@ -98,7 +98,6 @@ func gameActor(ctx context.Context, g *game.Match, dealer, chall person, join <-
|
||||
broadcast(ctx, g, dealer, chall, obs, dl)
|
||||
if g.MatchWinner() != nil {
|
||||
gameOver(ctx, dealer, chall, obs)
|
||||
// TODO(zeph): server needs to know the players are gone
|
||||
return
|
||||
}
|
||||
g.NextRound()
|
||||
@ -161,14 +160,12 @@ func playerActor(ctx context.Context, p person, actions chan<- action) {
|
||||
}
|
||||
|
||||
func broadcast(ctx context.Context, g *game.Match, dealer, chall person, obs []observer, deadline time.Time) {
|
||||
// TODO(zeph): this probably should return an error or some other signal
|
||||
// if a player drops so that the actor knows to quit
|
||||
// NOTE(zeph): If our sends to players fail, then the socket will close,
|
||||
// causing the readers to fail and send concede messages. No leak.
|
||||
if err := wsjson.Write(ctx, dealer.conn, g.DTO(dealer.id, deadline)); err != nil {
|
||||
// TODO(zeph): concede, but we need to be careful not to recurse
|
||||
slog.WarnContext(ctx, "lost dealer", "player", dealer.id, "err", err.Error())
|
||||
}
|
||||
if err := wsjson.Write(ctx, chall.conn, g.DTO(chall.id, deadline)); err != nil {
|
||||
// TODO(zeph): concede, but we need to be careful not to recurse
|
||||
slog.WarnContext(ctx, "lost challenger", "player", chall.id, "err", err.Error())
|
||||
}
|
||||
if len(obs) == 0 {
|
||||
@ -183,7 +180,6 @@ func broadcast(ctx context.Context, g *game.Match, dealer, chall person, obs []o
|
||||
}
|
||||
|
||||
func gameOver(ctx context.Context, dealer, chall person, obs []observer) {
|
||||
// TODO(zeph): need to communicate to the server that these have gone away
|
||||
go dealer.conn.Close(websocket.StatusNormalClosure, "match ended")
|
||||
go chall.conn.Close(websocket.StatusNormalClosure, "match ended")
|
||||
for _, p := range obs {
|
||||
|
5
main.go
5
main.go
@ -10,7 +10,6 @@ import (
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/google/uuid"
|
||||
"gitlab.com/zephyrtronium/sq"
|
||||
"nhooyr.io/websocket"
|
||||
|
||||
"git.sunturtle.xyz/studio/shotgun/lobby"
|
||||
"git.sunturtle.xyz/studio/shotgun/player"
|
||||
@ -43,11 +42,9 @@ func main() {
|
||||
return
|
||||
}
|
||||
s := Server{
|
||||
l: lobby.New[uuid.UUID, player.ID](),
|
||||
l: lobby.New[uuid.UUID, matchingPerson](),
|
||||
creds: db,
|
||||
sessions: db,
|
||||
pp: map[player.ID]*websocket.Conn{},
|
||||
j: map[uuid.UUID]chan person{},
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
58
server.go
58
server.go
@ -6,7 +6,6 @@ import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@ -20,14 +19,10 @@ import (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
l *lobby.Lobby[uuid.UUID, player.ID]
|
||||
l *lobby.Lobby[uuid.UUID, matchingPerson]
|
||||
|
||||
creds db
|
||||
sessions db
|
||||
|
||||
mu sync.Mutex
|
||||
pp map[player.ID]*websocket.Conn
|
||||
j map[uuid.UUID]chan person
|
||||
}
|
||||
|
||||
type db interface {
|
||||
@ -40,10 +35,9 @@ type person struct {
|
||||
id player.ID
|
||||
}
|
||||
|
||||
func (s *Server) person(p player.ID) person {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return person{conn: s.pp[p], id: p}
|
||||
type matchingPerson struct {
|
||||
sync chan struct{}
|
||||
person
|
||||
}
|
||||
|
||||
func (s *Server) accept(w http.ResponseWriter, r *http.Request, p player.ID) (person, error) {
|
||||
@ -52,27 +46,9 @@ func (s *Server) accept(w http.ResponseWriter, r *http.Request, p player.ID) (pe
|
||||
return person{}, err
|
||||
}
|
||||
slog.Debug("upgraded", "player", p)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.pp[p] = conn
|
||||
return person{conn: conn, id: p}, nil
|
||||
}
|
||||
|
||||
func (s *Server) left(p player.ID) {
|
||||
s.mu.Lock()
|
||||
// NOTE(zeph): neither map index nor map delete can panic, so this critical
|
||||
// section does not need a defer
|
||||
c := s.pp[p]
|
||||
delete(s.pp, p)
|
||||
s.mu.Unlock()
|
||||
if c != nil {
|
||||
// We don't care about the error here since the connection is leaving.
|
||||
// It's probably already closed anyway.
|
||||
slog.Debug("leaving", "player", p)
|
||||
c.Close(websocket.StatusNormalClosure, "bye")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Register(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
slog := slog.With(
|
||||
@ -208,8 +184,10 @@ func (s *Server) joinAndServe(p person) {
|
||||
stop()
|
||||
}
|
||||
}()
|
||||
id, chall, deal := s.l.Queue(ctx, uuid.New, p.id)
|
||||
mp := matchingPerson{sync: make(chan struct{}), person: p}
|
||||
id, chall, deal := s.l.Queue(ctx, uuid.New, mp)
|
||||
<-ch
|
||||
close(mp.sync)
|
||||
stop()
|
||||
if id == uuid.Nil {
|
||||
// Context canceled.
|
||||
@ -218,24 +196,10 @@ func (s *Server) joinAndServe(p person) {
|
||||
}
|
||||
if deal {
|
||||
ch := make(chan person, 2)
|
||||
s.mu.Lock()
|
||||
s.j[id] = ch
|
||||
s.mu.Unlock()
|
||||
g := game.New(p.id, chall)
|
||||
other := s.person(chall)
|
||||
go gameActor(context.TODO(), g, p, other, ch)
|
||||
g := game.New(p.id, chall.id)
|
||||
<-chall.sync
|
||||
go gameActor(context.TODO(), g, p, chall.person, ch)
|
||||
ch <- p
|
||||
} else {
|
||||
// very gross, but i just want this to exist
|
||||
for {
|
||||
s.mu.Lock()
|
||||
ch := s.j[id]
|
||||
s.mu.Unlock()
|
||||
if ch != nil {
|
||||
ch <- p
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reply with the game ID so they can share.
|
||||
r := serve.GameStart{
|
||||
@ -244,7 +208,7 @@ func (s *Server) joinAndServe(p person) {
|
||||
}
|
||||
if err := wsjson.Write(context.TODO(), p.conn, r); err != nil {
|
||||
slog.WarnContext(ctx, "got a game but player dropped", "game", id, "player", p.id)
|
||||
s.left(p.id)
|
||||
p.conn.Close(websocket.StatusNormalClosure, "looks like you dropped")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user