Goでゲームのロビー機能のようなモノを作る〜宿題の提出1
はじめに
Go2 Advent Calendar 2020 9日目の記事の宿題の提出です。
この記事では、ゲームのマッチングを行うロビー機能をGoで作って紹介しました。
記事の時点ではWebSocketを管理するhubをpoolに戻す処理が未対応で宿題となっていました。
今回はこの部分を作ってきました。
サーバに/hubout
というハンドラを追加しています。
クライアントがアクセスするとhubからプレイヤー情報を削除します。
func main() { flag.Parse() http.HandleFunc("/", serveFront) http.HandleFunc("/lobby", serveLobby) http.HandleFunc("/play", servePlay) http.HandleFunc("/login", serveLoginHandler) http.HandleFunc("/ws", serveWebsocket) http.HandleFunc("/hubout", huboutHandler) // 追加 err := http.ListenAndServe(*addr, nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
huboutHandler()はCookieから自身のセッションIDを取得し、セッションIDをHubManagerから削除します。
func huboutHandler(w http.ResponseWriter, r *http.Request) { manager := sessions.NewManager() session, err := manager.Get(r, cookieName) if err != nil { fmt.Println(err) return } hubManger := websocket.NewManager() hubManger.Destroy(session.ID) // WebSocketのHubManagerから削除する }
HubManagerが管理しているデータは次の通り。
Destroy()はこれらのデータから対象となるキーを削除していきます。
type Manager struct { database map[string]*Hub pool []*Hub count map[*Hub]int users map[*Hub][]string }
プレイヤーを削除するごとにm.count
をデクリメントすると、クロスタイミングでhubを横取りされる可能性があるので
プレイヤー全員を削除したタイミングでm.count
も削除するようにしています。
最後に、使っていたhubをpoolに戻します。これで次のプレイヤーが新たにhubを使えるようになりました。
func (m *Manager) Destroy(key string) { if hub, exist := m.database[key]; exist { delete(m.database, key) users := m.Users(hub) for u := 0; u < len(users); u++ { if users[u] == key { m.users[hub] = remove(m.users[hub], u) users = m.users[hub] } } if 0 == len(users) { // ペアが解放されたらhubをpoolに戻す delete(m.count, hub) m.pool = append(m.pool, hub) } } }