feat: backend service
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// Package runtime owns the lifecycle of game-engine containers and the
|
||||
// engine-version registry on the platform side. It is the single
|
||||
// component permitted to talk to the Docker daemon
|
||||
// (`internal/dockerclient`) and to running engine HTTP listeners
|
||||
// (`internal/engineclient`); cross-cutting concerns such as the lobby
|
||||
// state machine, notification fan-out, or player-mapping persistence
|
||||
// live in their domain packages and reach into runtime through a
|
||||
// narrow interface set documented in `deps.go`.
|
||||
//
|
||||
// The package introduces the package on top of the The implementation lobby. The
|
||||
// lobby `RuntimeGateway` shifts from a logger-only no-op to a real
|
||||
// adapter backed by `*runtime.Service`; runtime publishes snapshots
|
||||
// back into lobby through `LobbyConsumer.OnRuntimeSnapshot`. The
|
||||
// engine-version registry CRUD endpoints under
|
||||
// `/api/v1/admin/engine-versions/*` and the runtime admin/user proxy
|
||||
// endpoints flip from 501 placeholders to real responses.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
// Runtime status vocabulary mirrors `runtime_records_status_chk` in
|
||||
// `backend/internal/postgres/migrations/00001_init.sql`.
|
||||
const (
|
||||
RuntimeStatusStarting = "starting"
|
||||
RuntimeStatusRunning = "running"
|
||||
RuntimeStatusGenerationInProgress = "generation_in_progress"
|
||||
RuntimeStatusGenerationFailed = "generation_failed"
|
||||
RuntimeStatusStopped = "stopped"
|
||||
RuntimeStatusEngineUnreachable = "engine_unreachable"
|
||||
RuntimeStatusFinished = "finished"
|
||||
RuntimeStatusRemoved = "removed"
|
||||
)
|
||||
|
||||
// Operation log vocabulary recorded into `runtime_operation_log.op` and
|
||||
// `runtime_operation_log.status`. Kept as exported constants so
|
||||
// runtime, admin handlers, and tests share the same wire values.
|
||||
const (
|
||||
OpStart = "start"
|
||||
OpStop = "stop"
|
||||
OpPause = "pause"
|
||||
OpResume = "resume"
|
||||
OpRestart = "restart"
|
||||
OpPatch = "patch"
|
||||
OpForceNextTurn = "force_next_turn"
|
||||
OpReconcile = "reconcile"
|
||||
OpTurn = "turn"
|
||||
|
||||
OpSourceLobby = "lobby"
|
||||
OpSourceAdmin = "admin"
|
||||
OpSourceScheduler = "scheduler"
|
||||
OpSourceReconciler = "reconciler"
|
||||
|
||||
OpStatusQueued = "queued"
|
||||
OpStatusRunning = "running"
|
||||
OpStatusSucceeded = "succeeded"
|
||||
OpStatusFailed = "failed"
|
||||
)
|
||||
|
||||
// Container naming convention. The hostname is the primary alias on
|
||||
// the user-defined Docker network; the engine endpoint URL is
|
||||
// synthesised by `dockerclient.Adapter.Run` as `http://{hostname}:8080`.
|
||||
const (
|
||||
containerNamePrefix = "galaxy-game-"
|
||||
containerHostPrefix = "galaxy-game-"
|
||||
)
|
||||
|
||||
// pgErrCodeUniqueViolation is the SQLSTATE Postgres emits on a UNIQUE
|
||||
// constraint violation. Kept locally so the runtime package does not
|
||||
// import `internal/admin` or `internal/lobby` for the constant.
|
||||
const pgErrCodeUniqueViolation = "23505"
|
||||
|
||||
// isUniqueViolation reports whether err is a Postgres UNIQUE
|
||||
// constraint violation, optionally restricted to a specific constraint
|
||||
// name. Empty constraintName matches any UNIQUE violation.
|
||||
func isUniqueViolation(err error, constraintName string) bool {
|
||||
var pgErr *pgconn.PgError
|
||||
if !errors.As(err, &pgErr) {
|
||||
return false
|
||||
}
|
||||
if pgErr.Code != pgErrCodeUniqueViolation {
|
||||
return false
|
||||
}
|
||||
if constraintName == "" {
|
||||
return true
|
||||
}
|
||||
return pgErr.ConstraintName == constraintName
|
||||
}
|
||||
|
||||
// ContainerName synthesises the Docker container / hostname for the
|
||||
// supplied game id. Exported so tests and the reconciler can resolve
|
||||
// the inverse mapping without duplicating the format string.
|
||||
func ContainerName(gameID string) string { return containerNamePrefix + gameID }
|
||||
|
||||
// HostName synthesises the in-network hostname for the supplied game
|
||||
// id. Mirrors ContainerName so the engine endpoint URL `http://{host}:8080`
|
||||
// resolves through Docker DNS on the user-defined network.
|
||||
func HostName(gameID string) string { return containerHostPrefix + gameID }
|
||||
Reference in New Issue
Block a user