mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
feat(multiplayer): cap websocket connections per player
This commit is contained in:
+21
-7
@@ -19,12 +19,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
maxWebSocketFrame = 64 << 10
|
||||
eventQueueCapacity = 32
|
||||
webSocketIdleLimit = 2 * time.Minute
|
||||
webSocketMessageLimit = 120
|
||||
webSocketMessageWindow = time.Minute
|
||||
webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
maxWebSocketFrame = 64 << 10
|
||||
eventQueueCapacity = 32
|
||||
webSocketIdleLimit = 2 * time.Minute
|
||||
webSocketMessageLimit = 120
|
||||
webSocketMessageWindow = time.Minute
|
||||
maxEventConnectionsPerPlayer = 2
|
||||
)
|
||||
|
||||
// ControlPlaneEvent is the server-to-client envelope defined by the v1
|
||||
@@ -56,8 +57,18 @@ func newEventHub() *eventHub {
|
||||
}
|
||||
|
||||
func (h *eventHub) subscribe(playerID string) *eventSubscriber {
|
||||
subscriber := &eventSubscriber{playerID: playerID, queue: make(chan []byte, eventQueueCapacity)}
|
||||
h.mu.Lock()
|
||||
connections := 0
|
||||
for subscriber := range h.subscribers {
|
||||
if subscriber.playerID == playerID {
|
||||
connections++
|
||||
}
|
||||
}
|
||||
if connections >= maxEventConnectionsPerPlayer {
|
||||
h.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
subscriber := &eventSubscriber{playerID: playerID, queue: make(chan []byte, eventQueueCapacity)}
|
||||
h.subscribers[subscriber] = struct{}{}
|
||||
h.mu.Unlock()
|
||||
return subscriber
|
||||
@@ -168,6 +179,9 @@ func (s *Service) controlPlaneEvent(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
subscriber := s.getEventHub().subscribe(playerID)
|
||||
if subscriber == nil {
|
||||
return
|
||||
}
|
||||
defer s.getEventHub().unsubscribe(subscriber)
|
||||
|
||||
var writeMu sync.Mutex
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEventHubCapsConnectionsPerPlayerAndReleasesCapacity(t *testing.T) {
|
||||
hub := newEventHub()
|
||||
first := hub.subscribe("player-1")
|
||||
second := hub.subscribe("player-1")
|
||||
if first == nil || second == nil {
|
||||
t.Fatal("connection within per-player cap was rejected")
|
||||
}
|
||||
if third := hub.subscribe("player-1"); third != nil {
|
||||
t.Fatal("connection over per-player cap was accepted")
|
||||
}
|
||||
hub.unsubscribe(first)
|
||||
if third := hub.subscribe("player-1"); third == nil {
|
||||
t.Fatal("released connection capacity was not reusable")
|
||||
} else {
|
||||
hub.unsubscribe(third)
|
||||
}
|
||||
hub.unsubscribe(second)
|
||||
}
|
||||
Reference in New Issue
Block a user