69 lines
2.8 KiB
Go
69 lines
2.8 KiB
Go
package redisstate
|
|
|
|
import (
|
|
"encoding/base64"
|
|
|
|
"galaxy/lobby/internal/domain/common"
|
|
)
|
|
|
|
// defaultPrefix is the mandatory `lobby:` namespace prefix shared by every
|
|
// Game Lobby Redis key.
|
|
const defaultPrefix = "lobby:"
|
|
|
|
// Keyspace builds the Game Lobby Redis keys that survive the PG_PLAN.md
|
|
// §6A and §6B migrations: per-game ephemeral runtime aggregates,
|
|
// capability-evaluation guards, gap activation timestamps, and stream
|
|
// consumer offsets. The four core enrollment entities (game, application,
|
|
// invite, membership) and the Race Name Directory live in PostgreSQL —
|
|
// their previous keyspace methods are gone.
|
|
//
|
|
// All dynamic key segments are encoded with base64url so raw key structure
|
|
// does not depend on user-provided or caller-provided characters.
|
|
type Keyspace struct{}
|
|
|
|
// GapActivatedAt returns the Redis key that stores the gap-window
|
|
// activation timestamp for one game.
|
|
func (Keyspace) GapActivatedAt(gameID common.GameID) string {
|
|
return defaultPrefix + "gap_activated_at:" + encodeKeyComponent(gameID.String())
|
|
}
|
|
|
|
// StreamOffset returns the Redis key that stores the last successfully
|
|
// processed entry id for one Redis Stream consumer. The streamLabel is
|
|
// the short logical identifier of the consumer (e.g. `runtime_results`,
|
|
// `gm_events`, `user_lifecycle`), not the full stream name; it stays
|
|
// stable when the underlying stream key is renamed.
|
|
func (Keyspace) StreamOffset(streamLabel string) string {
|
|
return defaultPrefix + "stream_offsets:" + encodeKeyComponent(streamLabel)
|
|
}
|
|
|
|
// GameTurnStat returns the per-user Redis key that stores the
|
|
// initial/max stats aggregate for one game. keeps one key per
|
|
// user so the Lua-backed SaveInitial and UpdateMax scripts can operate
|
|
// on a single primary key without a secondary index.
|
|
func (Keyspace) GameTurnStat(gameID common.GameID, userID string) string {
|
|
return defaultPrefix + "game_turn_stats:" +
|
|
encodeKeyComponent(gameID.String()) + ":" +
|
|
encodeKeyComponent(userID)
|
|
}
|
|
|
|
// GameTurnStatsByGame returns the set key that stores every userID for
|
|
// which a GameTurnStat key exists for gameID. The set is the lookup
|
|
// index used by Load and Delete so they avoid a Redis SCAN over the
|
|
// whole keyspace.
|
|
func (Keyspace) GameTurnStatsByGame(gameID common.GameID) string {
|
|
return defaultPrefix + "game_turn_stats_by_game:" +
|
|
encodeKeyComponent(gameID.String())
|
|
}
|
|
|
|
// CapabilityEvaluationGuard returns the Redis key whose presence marks
|
|
// gameID as already evaluated by the The capability evaluator
|
|
// uses SETNX on this key to make replayed `game_finished` events safe.
|
|
func (Keyspace) CapabilityEvaluationGuard(gameID common.GameID) string {
|
|
return defaultPrefix + "capability_evaluation:done:" +
|
|
encodeKeyComponent(gameID.String())
|
|
}
|
|
|
|
func encodeKeyComponent(value string) string {
|
|
return base64.RawURLEncoding.EncodeToString([]byte(value))
|
|
}
|