mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-13 02:42:03 +00:00
feat(multiplayer): bind admissions to durable leases
This commit is contained in:
+15
-5
@@ -669,9 +669,9 @@ func (s *Service) serverMutation(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if parts[1] == "connect" || parts[1] == "disconnect" {
|
||||
var input struct {
|
||||
PlayerID string `json:"player_id"`
|
||||
Generation uint64 `json:"generation,omitempty"`
|
||||
ExpectedGeneration uint64 `json:"expected_generation,omitempty"`
|
||||
PlayerID string `json:"player_id"`
|
||||
Generation uint64 `json:"generation,omitempty"`
|
||||
ExpectedGeneration *uint64 `json:"expected_generation,omitempty"`
|
||||
}
|
||||
if !decodeBody(w, r, &input) {
|
||||
return
|
||||
@@ -687,9 +687,13 @@ func (s *Service) serverMutation(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusUnprocessableEntity, "invalid_request")
|
||||
return
|
||||
}
|
||||
generation, err = s.ServerConnections.ClaimPlayerConnection(r.Context(), binding, input.PlayerID, input.ExpectedGeneration, key, now)
|
||||
expectedGeneration := uint64(0)
|
||||
if input.ExpectedGeneration != nil {
|
||||
expectedGeneration = *input.ExpectedGeneration
|
||||
}
|
||||
generation, err = s.ServerConnections.ClaimPlayerConnection(r.Context(), binding, input.PlayerID, expectedGeneration, key, now)
|
||||
} else {
|
||||
if input.Generation == 0 || input.ExpectedGeneration != 0 {
|
||||
if input.Generation == 0 || input.ExpectedGeneration != nil {
|
||||
writeError(w, http.StatusUnprocessableEntity, "invalid_request")
|
||||
return
|
||||
}
|
||||
@@ -717,6 +721,12 @@ func (s *Service) serverMutation(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
if input.ExpectedGeneration == nil {
|
||||
// Rolling-upgrade compatibility for the pre-lease reporter. New
|
||||
// servers always send expected_generation and consume the JSON lease.
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]uint64{"generation": generation})
|
||||
return
|
||||
|
||||
@@ -1513,13 +1513,16 @@ func TestServerConnectionAPIRequiresBoundWorkloadAndOpaqueAssignedPlayer(t *test
|
||||
if recorder.connectCalls != 1 || recorder.binding != binding || recorder.playerID != "player-123456789" || recorder.expectedGeneration != 0 || recorder.key != "connect-player-123456789" {
|
||||
t.Fatalf("connection receipt = %+v", recorder)
|
||||
}
|
||||
if got, body := request("connect", binding.ServerID, "player-legacy-123456", "workload-token", "connect-legacy-123456", ""); got != http.StatusNoContent || body != "" {
|
||||
t.Fatalf("legacy connection status=%d body=%q", got, body)
|
||||
}
|
||||
if got, _ := request("connect", "server-000000000", "player-123456789", "workload-token", "connect-player-123456789", ""); got != http.StatusUnauthorized {
|
||||
t.Fatalf("wrong server status = %d", got)
|
||||
}
|
||||
if got, _ := request("connect", binding.ServerID, "short", "workload-token", "connect-player-short-123", ""); got != http.StatusUnprocessableEntity {
|
||||
t.Fatalf("short player status = %d", got)
|
||||
}
|
||||
if recorder.connectCalls != 1 {
|
||||
if recorder.connectCalls != 2 {
|
||||
t.Fatalf("invalid receipts reached backend: %d", recorder.connectCalls)
|
||||
}
|
||||
if got, _ := request("disconnect", binding.ServerID, "player-123456789", "workload-token", "disconnect-player-123456789", `,"generation":1`); got != http.StatusNoContent {
|
||||
|
||||
Reference in New Issue
Block a user