feat: game lobby service
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"galaxy/lobby/internal/domain/common"
|
||||
)
|
||||
|
||||
// ErrGMUnavailable signals that a Game Master call could not be
|
||||
// completed because the upstream service was unreachable, returned an
|
||||
// error response, or timed out. treats every non-success
|
||||
// outcome of GMClient.RegisterGame uniformly: the start flow transitions
|
||||
// to `paused` and an admin notification is published.
|
||||
var ErrGMUnavailable = errors.New("game master unavailable")
|
||||
|
||||
// GMClient executes synchronous calls to Game Master. introduced
|
||||
// the registration call; added the liveness probe used by the
|
||||
// voluntary resume flow.
|
||||
type GMClient interface {
|
||||
// RegisterGame registers a running game with Game Master after a
|
||||
// successful container start and runtime binding persistence. A
|
||||
// non-nil error is returned for any non-success outcome (transport
|
||||
// error, timeout, non-2xx response). Implementations wrap such
|
||||
// failures with ErrGMUnavailable so callers can branch with
|
||||
// errors.Is.
|
||||
RegisterGame(ctx context.Context, request RegisterGameRequest) error
|
||||
|
||||
// Ping performs a synchronous liveness probe against Game Master.
|
||||
// Implementations return nil when GM is reachable and healthy and
|
||||
// wrap every other outcome (transport error, timeout, non-2xx
|
||||
// response) with ErrGMUnavailable so callers can
|
||||
// branch with errors.Is.
|
||||
Ping(ctx context.Context) error
|
||||
}
|
||||
|
||||
// RegisterGameRequest stores the parameters required to register one
|
||||
// running game with Game Master. The shape mirrors the JSON body sent
|
||||
// by the HTTP adapter and is independent of the GM-side schema so the
|
||||
// adapter and the consumer can reason about it without leaking
|
||||
// transport details.
|
||||
type RegisterGameRequest struct {
|
||||
// GameID identifies the running game.
|
||||
GameID common.GameID
|
||||
|
||||
// ContainerID identifies the engine container assigned by Runtime
|
||||
// Manager.
|
||||
ContainerID string
|
||||
|
||||
// EngineEndpoint stores the network address Game Master uses to
|
||||
// reach the engine container.
|
||||
EngineEndpoint string
|
||||
|
||||
// TargetEngineVersion stores the semver of the engine version that
|
||||
// was launched (copied from the game record at registration time).
|
||||
TargetEngineVersion string
|
||||
|
||||
// TurnSchedule stores the cron expression that drives turn
|
||||
// generation (copied from the game record at registration time).
|
||||
TurnSchedule string
|
||||
}
|
||||
|
||||
// Validate reports whether request stores the structurally valid
|
||||
// arguments required for Game Master registration.
|
||||
func (request RegisterGameRequest) Validate() error {
|
||||
if err := request.GameID.Validate(); err != nil {
|
||||
return fmt.Errorf("register game: game id: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(request.ContainerID) == "" {
|
||||
return fmt.Errorf("register game: container id must not be empty")
|
||||
}
|
||||
if strings.TrimSpace(request.EngineEndpoint) == "" {
|
||||
return fmt.Errorf("register game: engine endpoint must not be empty")
|
||||
}
|
||||
if strings.TrimSpace(request.TargetEngineVersion) == "" {
|
||||
return fmt.Errorf("register game: target engine version must not be empty")
|
||||
}
|
||||
if strings.TrimSpace(request.TurnSchedule) == "" {
|
||||
return fmt.Errorf("register game: turn schedule must not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user