From 6eb24636e56d0567061a100f80e190f214b3bf20 Mon Sep 17 00:00:00 2001 From: Steve Date: Mon, 26 Jul 2021 13:02:00 -0400 Subject: [PATCH] add broadcasts --- cmd/client/main.go | 48 ++++++++++++++++++---- cmd/server/server.go | 8 +++- internal/coordinator/coordinator.go | 62 +++++++++++++++++++++++++++++ internal/coordinator/session.go | 50 ++++++++++++++--------- 4 files changed, 139 insertions(+), 29 deletions(-) diff --git a/cmd/client/main.go b/cmd/client/main.go index 5999f73..65830e5 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -31,17 +31,19 @@ func receiveHandler(connection *websocket.Conn, output chan string) { if err != nil { log.Println("Error in receive:", err) } - if resp.Result == coordinator.SessionRespJoined1 { + switch resp.Result { + case coordinator.SessionRespJoined1: pid = game.SentinalID output <- "joined as sentinal" - } else if resp.Result == coordinator.SessionRespJoined2 { + case coordinator.SessionRespJoined2: pid = game.ScourgeID output <- "joined as scourge" - } else if resp.Result == coordinator.SessionRespFound { + case coordinator.SessionRespFound: matchID = resp.MatchID output <- "game found" - } else if resp.Result == coordinator.SessionRespPlayed { + case coordinator.SessionRespPlayed: if resp.GameResult != nil { + output <- "played succesfully" switch resp.GameResult.ResultType { case game.ActCmd: output <- resp.GameResult.ActionResult.String() @@ -50,12 +52,27 @@ func receiveHandler(connection *websocket.Conn, output chan string) { case game.DebugCmd: output <- resp.GameResult.DebugResult.String() } + } else { + output <- "error playing" } - } else if resp.Result == coordinator.SessionRespLeft { + case coordinator.SessionRespLeft: output <- "game left" break - } else if resp.Result == coordinator.SessionRespPlayed { - output <- "played succesfully" + case coordinator.SessionRespBroadcastSenTurn: + output <- "Sentinal may take their turn" + case coordinator.SessionRespBroadcastScoTrun: + output <- "Scourge may take their turn" + case coordinator.SessionRespBroadcastSenWin: + output <- "Sentinal wins!" + case coordinator.SessionRespBroadcastScoWin: + output <- "Scourge wins!" + case coordinator.SessionRespBroadcastNone: + + case coordinator.SessionRespError: + output <- "generic error" + + default: + output <- "Received a server response we don't know how to handle" } } } @@ -82,7 +99,7 @@ func main() { defer conn.Close() go receiveHandler(conn, output) go GetCommand(id, cmd) - + ticker := time.NewTicker(1 * time.Second) // Our main loop for the client // We send our relevant packets here for { @@ -95,6 +112,9 @@ func main() { log.Println("Error during writing to websocket:", err) return } + if c.Command == coordinator.SessionCmdLeave { + break + } case o = <-output: fmt.Println(o) case <-interrupt: @@ -118,6 +138,18 @@ func main() { log.Println("Timeout in closing receiving channel. Exiting....") } return + case <-ticker.C: + if matchID != uuid.Nil { + err := conn.WriteJSON(coordinator.SessionCommand{ + ID: id, + MatchID: matchID, + Command: coordinator.SessionCmdPoll, + }) + if err != nil { + log.Println("Error writing to websocket:", err) + return + } + } } } } diff --git a/cmd/server/server.go b/cmd/server/server.go index e5d3b36..749a780 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -37,12 +37,16 @@ func serveWs(c *coordinator.Coordinator, w http.ResponseWriter, r *http.Request) log.Println("Error during message reading:", err) break } - log.Printf("Received: %s", cmd) + if cmd.Command != coordinator.SessionCmdPoll { + log.Printf("Received: %s", cmd) + } resp := c.Coordinate(&cmd) if err != nil { panic(err) } - log.Printf("sending: %v", resp) + if cmd.Command != coordinator.SessionCmdPoll { + log.Printf("sending: %v", resp) + } err = conn.WriteJSON(resp) if err != nil { log.Println("Error during message writing:", err) diff --git a/internal/coordinator/coordinator.go b/internal/coordinator/coordinator.go index 7fb855e..a1941ba 100644 --- a/internal/coordinator/coordinator.go +++ b/internal/coordinator/coordinator.go @@ -42,6 +42,7 @@ func (c *Coordinator) Start() { c.MatchLock.Unlock() c.CallbackChan[p1] <- m.ID c.CallbackChan[p2] <- m.ID + go MatchWatcher(m) } }() go func() { @@ -52,6 +53,7 @@ func (c *Coordinator) Start() { if v.Game == nil && v.Active { log.Println("clearing match with no game") delete(c.Matches, v.ID) + v.Watcher <- true } } c.MatchLock.Unlock() @@ -117,6 +119,24 @@ func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult { Result: SessionRespPlayed, GameResult: resp, } + case SessionCmdPoll: + m, exists := c.Matches[cmd.MatchID] + if exists { + select { + case res := <-m.Broadcasts[cmd.ID]: + return &SessionCommandResult{ + ID: cmd.ID, + MatchID: m.ID, + Result: res, + } + default: + return &SessionCommandResult{ + ID: cmd.ID, + MatchID: m.ID, + Result: SessionRespBroadcastNone, + } + } + } } return &SessionCommandResult{ ID: cmd.ID, @@ -124,3 +144,45 @@ func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult { Result: SessionRespError, } } + +func MatchWatcher(m *Session) { + ticker := time.NewTicker(1 * time.Second) + old_turn := -1 + for { + select { + case <-ticker.C: + if m.Active && m.Game != nil { + if m.Game.Status == game.StatusSentinalWin { + for _, v := range m.Broadcasts { + v <- SessionRespBroadcastSenWin + } + } + if m.Game.Status == game.StatusScourgeWin { + for _, v := range m.Broadcasts { + v <- SessionRespBroadcastScoWin + } + } + if old_turn != m.Game.CurrentTurn { + old_turn = m.Game.CurrentTurn + if old_turn == game.SentinalID { + for k, v := range m.pMap { + if v == game.SentinalID { + m.Broadcasts[k] <- SessionRespBroadcastSenTurn + } + } + } else if old_turn == game.ScourgeID { + for k, v := range m.pMap { + if v == game.ScourgeID { + m.Broadcasts[k] <- SessionRespBroadcastScoTrun + } + } + } + } + } + + case <-m.Watcher: + close(m.Watcher) + return + } + } +} diff --git a/internal/coordinator/session.go b/internal/coordinator/session.go index 56abc30..0675bc8 100644 --- a/internal/coordinator/session.go +++ b/internal/coordinator/session.go @@ -15,35 +15,45 @@ const ( SessionCmdJoin = "join" SessionCmdLeave = "leave" SessionCmdPlay = "play" + SessionCmdPoll = "poll" ) const ( - SessionRespFound SessionResp = "found" - SessionRespJoined1 = "joined p1" - SessionRespJoined2 = "joined p2" - SessionRespJoinError = "join error" - SessionRespLeft = "left" - SessionRespPlayed = "played" - SessionRespError = "generic error" + SessionRespFound SessionResp = "found" + SessionRespJoined1 = "joined p1" + SessionRespJoined2 = "joined p2" + SessionRespJoinError = "join error" + SessionRespLeft = "left" + SessionRespPlayed = "played" + SessionRespError = "generic error" + SessionRespBroadcastSenTurn = "Sentinal turn" + SessionRespBroadcastScoTrun = "Scourge turn" + SessionRespBroadcastSenWin = "Sentinal wins" + SessionRespBroadcastScoWin = "Scourge wins" + SessionRespBroadcastNone = "" ) type Session struct { - ID uuid.UUID - p1 uuid.UUID - p2 uuid.UUID - pMap map[uuid.UUID]int - Active bool - Game *game.Game + ID uuid.UUID + p1 uuid.UUID + p2 uuid.UUID + pMap map[uuid.UUID]int + Active bool + Game *game.Game + Watcher chan bool + Broadcasts map[uuid.UUID]chan SessionResp } func NewSession() *Session { return &Session{ - ID: uuid.New(), - p1: uuid.Nil, - p2: uuid.Nil, - pMap: make(map[uuid.UUID]int), - Active: false, - Game: nil, + ID: uuid.New(), + p1: uuid.Nil, + p2: uuid.Nil, + pMap: make(map[uuid.UUID]int), + Active: false, + Game: nil, + Watcher: make(chan bool), + Broadcasts: make(map[uuid.UUID]chan SessionResp), } } @@ -51,10 +61,12 @@ func (s *Session) Join(id uuid.UUID) SessionResp { if s.p1 == uuid.Nil { s.p1 = id s.pMap[id] = game.SentinalID + s.Broadcasts[id] = make(chan SessionResp) return SessionRespJoined1 } else if s.p2 == uuid.Nil { s.p2 = id s.pMap[id] = game.ScourgeID + s.Broadcasts[id] = make(chan SessionResp) return SessionRespJoined2 } else { return SessionRespJoinError