feat(multiplayer): deliver allocated server rosters

This commit is contained in:
Josh Creek
2026-09-01 15:54:07 +01:00
parent 863cf61f1a
commit 68e76b5feb
10 changed files with 267 additions and 22 deletions
@@ -5,11 +5,13 @@ package supervisor
import (
"context"
"database/sql"
"encoding/base64"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
@@ -78,7 +80,7 @@ func TestRealSupervisorRegistersAllocatedServerThroughControlPlane(t *testing.T)
if err := store.SaveAssignment(ctx, db, store.DurableAssignment{
MatchID: "supervisor-live-match", PlayerID: player, AllocationID: request.AllocationID, ServerID: "supervisor-live-server", Slot: index,
Region: "EU", ClientBuild: "build-1", ProtocolVersion: 1, Transport: "enet", Endpoint: "127.0.0.1:7777",
JoinAuthorisation: "join-" + player, ManifestDigest: []byte{0, 1, 2, 3}, ExpiresAt: now.Add(time.Hour), Revision: 1,
JoinAuthorisation: base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"authorisation":{"match_id":"supervisor-live-match","server_id":"supervisor-live-server","player_id":%q},"signature":"sig"}`, player))), ManifestDigest: []byte{0, 1, 2, 3}, ExpiresAt: now.Add(time.Hour), Revision: 1,
}); err != nil {
t.Fatal(err)
}
@@ -99,13 +101,16 @@ func TestRealSupervisorRegistersAllocatedServerThroughControlPlane(t *testing.T)
}
}))
defer sdk.Close()
service := &api.Service{ServerRegistrar: api.ServerRegistrarFromStore(db), WorkloadVerify: api.WorkloadVerifierFromSignedToken(secret, db), Now: func() time.Time { return now }}
rosterPath := filepath.Join(t.TempDir(), "join-roster.json")
service := &api.Service{ServerRegistrar: api.ServerRegistrarFromStore(db), WorkloadVerify: api.WorkloadVerifierFromSignedToken(secret, db), Roster: func(ctx context.Context, binding domain.WorkloadBinding, at time.Time) ([][]byte, error) {
return store.GetAssignmentRoster(ctx, db, binding.MatchID, binding.ServerID, at)
}, Now: func() time.Time { return now }}
control := httptest.NewServer(service.Handler())
defer control.Close()
supervisor, err := New(Config{
Command: []string{"/bin/sh", "-c", "true"}, SDKBaseURL: sdk.URL, ReadyURL: sdk.URL + "/ready-probe", ControlPlaneURL: control.URL,
ServerID: "supervisor-live-server", ProtocolVersion: 1, ImageDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
ReadyTimeout: time.Second, PollInterval: time.Millisecond, AssignmentReadyAttempts: 1,
ReadyTimeout: time.Second, PollInterval: time.Millisecond, AssignmentReadyAttempts: 1, RosterPath: rosterPath,
})
if err != nil {
t.Fatal(err)
@@ -116,6 +121,10 @@ func TestRealSupervisorRegistersAllocatedServerThroughControlPlane(t *testing.T)
if err := supervisor.Wait(); err != nil {
t.Fatal(err)
}
roster, err := os.ReadFile(rosterPath)
if err != nil || !strings.Contains(string(roster), "supervisor-live-a") || !strings.Contains(string(roster), "supervisor-live-b") {
t.Fatalf("materialized live roster=%q err=%v", roster, err)
}
var matchState, ticketState string
if err := db.QueryRowContext(ctx, `SELECT state FROM matches WHERE match_id = 'supervisor-live-match'`).Scan(&matchState); err != nil {
t.Fatal(err)