Documentation
¶
Index ¶
- Constants
- Variables
- func ActiveDeadlines(lb *Leaderboard, now time.Time) (startActive, endActive, expiry int64)
- func ArchiveRecordsForExpiry(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, ...) (int64, error)
- func CalculateExpiry(lb *Leaderboard, overrideExpiry int64, now time.Time) (int64, bool)
- func CalculatePrevReset(currentTime time.Time, startTime int64, resetSchedule *cronexpr.Expression) int64
- func CalculateTournamentDeadlines(startTime, endTime, duration int64, resetSchedule *cronexpr.Expression, ...) (int64, int64, int64)
- func ConfigureRankCacheBlacklist(csv string)
- func CreateLeaderboard(ctx context.Context, pool *pgxpool.Pool, lb *Leaderboard) error
- func DeleteLeaderboard(ctx context.Context, pool *pgxpool.Pool, id string) error
- func DeleteRecord(ctx context.Context, pool *pgxpool.Pool, leaderboardID, ownerID string) error
- func DeleteRecordForExpiry(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, ...) error
- func DisableRanks(ctx context.Context, pool *pgxpool.Pool, id string, tournament bool) error
- func EncodeCursor(c *RecordListCursor) (string, error)
- func IsRankCacheBlacklisted(leaderboardID string) bool
- func ManualReset(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, archive bool) (int64, error)
- func MustParseResetSchedule(expr string) *cronexpr.Expression
- func ParseResetSchedule(expr string) (*cronexpr.Expression, error)
- func PruneExpiredRecords(ctx context.Context, pool *pgxpool.Pool, now time.Time) (int64, error)
- func RecordsDeleteAll(ctx context.Context, pool *pgxpool.Pool, ownerID string) error
- func RecordsListCursorFromRank(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, ...) (string, error)
- func ResolveExpiryTime(expiryUnix int64) time.Time
- func StartInvalidationListener(ctx context.Context, rdb *redis.Client)
- func StartRankCacheTrimmer(stop <-chan struct{})
- func ValidateLeaderboardID(id string) error
- func ValidateMetadata(metadata string) error
- type ConfigCache
- func (c *ConfigCache) Delete(id string)
- func (c *ConfigCache) Get(id string) *Leaderboard
- func (c *ConfigCache) InvalidateAge(_ time.Duration)
- func (c *ConfigCache) ListAll() []*Leaderboard
- func (c *ConfigCache) ListLeaderboardsCached() []*Leaderboard
- func (c *ConfigCache) ListTournamentsCached() []*Leaderboard
- func (c *ConfigCache) LoadAll(lbs []*Leaderboard)
- func (c *ConfigCache) Put(lb *Leaderboard)
- type GlobalRankCache
- func (g *GlobalRankCache) Delete(leaderboardID string, expiryUnix int64, ownerID string)
- func (g *GlobalRankCache) DeleteLeaderboard(leaderboardID string)
- func (g *GlobalRankCache) EvictPartition(leaderboardID string, expiryUnix int64)
- func (g *GlobalRankCache) FillRanks(leaderboardID string, expiryUnix int64, records []*LeaderboardRecord, ...)
- func (g *GlobalRankCache) GetDataByRank(leaderboardID string, expiryUnix, rank int64) (ownerID string, score, subscore int64, ok bool)
- func (g *GlobalRankCache) GetRank(leaderboardID string, expiryUnix int64, ownerID string) int64
- func (g *GlobalRankCache) Insert(leaderboardID string, sortOrder int, score, subscore int64, expiryUnix int64, ...) int64
- func (g *GlobalRankCache) LoadFromRecords(leaderboardID string, expiryUnix int64, sortOrder int, enableRanks bool, ...)
- func (g *GlobalRankCache) TrimExpired(nowUnix int64)
- type InvalidationPayload
- type Leaderboard
- func GetLeaderboard(ctx context.Context, pool *pgxpool.Pool, id string) (*Leaderboard, error)
- func LeaderboardsGetId(ctx context.Context, pool *pgxpool.Pool, ids []string) ([]*Leaderboard, error)
- func ListLeaderboards(ctx context.Context, pool *pgxpool.Pool, limit int, cursor string) ([]*Leaderboard, string, error)
- func LoadAllLeaderboards(ctx context.Context, pool *pgxpool.Pool) ([]*Leaderboard, error)
- func ResolveCurrentExpiry(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, ...) (time.Time, *Leaderboard, error)
- func TournamentsGetId(ctx context.Context, pool *pgxpool.Pool, ids []string) ([]*Leaderboard, error)
- type LeaderboardRecord
- func GetLeaderboardRecords(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, ...) ([]*LeaderboardRecord, string, error)
- func GetLeaderboardRecordsAroundPlayer(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, ...) ([]*LeaderboardRecord, error)
- func GetLeaderboardRecordsPaged(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, limit int, ...) ([]*LeaderboardRecord, string, string, error)
- func GetOwnerRecords(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, ...) ([]*LeaderboardRecord, error)
- func ListArchivedRecords(ctx context.Context, pool *pgxpool.Pool, leaderboardID, seasonKey string, ...) ([]*LeaderboardRecord, error)
- func RecordsHaystack(ctx context.Context, pool *pgxpool.Pool, leaderboardID, ownerID string, ...) ([]*LeaderboardRecord, string, string, error)
- func RecordsReadAll(ctx context.Context, pool *pgxpool.Pool, ownerID string) ([]*LeaderboardRecord, error)
- func SubmitScore(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, ...) (*LeaderboardRecord, error)
- type RankCache
- type RankEntry
- type RecordListCursor
- type SeasonStat
- type SkipListRankCache
Constants ¶
const ( SortOrderAscending = 0 SortOrderDescending = 1 OperatorBest = 0 OperatorSet = 1 OperatorIncrement = 2 OperatorDecrement = 3 MaxMetadataBytes = 2 * 1024 MaxPageSize = 1000 ScoreSubmissionsPerMin = 10 )
const OperatorNoOverride = -1
OperatorNoOverride sentinel for SubmitScore override (use board operator).
Variables ¶
var ( ErrLeaderboardNotFound = errors.New("leaderboard not found") ErrAuthoritative = errors.New("leaderboard is authoritative and rejects client submissions") ErrMaxAttemptsReached = errors.New("max score submission attempts reached") ErrInvalidOperator = errors.New("invalid score operator") ErrJoinRequired = errors.New("join required before submitting score") ErrInvalidLeaderboardID = errors.New("invalid leaderboard id") ErrMetadataTooLarge = errors.New("metadata exceeds max size") ErrRateLimited = errors.New("score submission rate limit exceeded") ErrInvalidCursor = errors.New("leaderboard cursor invalid") ErrNoRecordsPossible = errors.New("no records available for current expiry") )
byID: make(map[string]*Leaderboard), }
SharedConfigCache is the process-wide leaderboard config cache.
cache: make(map[leaderboardExpiryKey]*RankCache), }
SharedRankCache is the process-wide rank cache instance.
Functions ¶
func ActiveDeadlines ¶
func ActiveDeadlines(lb *Leaderboard, now time.Time) (startActive, endActive, expiry int64)
ActiveDeadlines returns start/end active and expiry for the given leaderboard at now.
func ArchiveRecordsForExpiry ¶
func ArchiveRecordsForExpiry(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, expiryTime time.Time, seasonKey string) (int64, error)
ArchiveRecordsForExpiry copies active records for an expiry partition into the archive table.
func CalculateExpiry ¶
CalculateExpiry resolves the current expiry partition for a leaderboard. overrideExpiry of 0 means "use current occurrence". Returns (expiryUnix, recordsPossible).
func CalculatePrevReset ¶
func CalculatePrevReset(currentTime time.Time, startTime int64, resetSchedule *cronexpr.Expression) int64
CalculatePrevReset returns the previous reset unix time, or 0.
func CalculateTournamentDeadlines ¶
func CalculateTournamentDeadlines(startTime, endTime, duration int64, resetSchedule *cronexpr.Expression, t time.Time) (int64, int64, int64)
CalculateTournamentDeadlines mirrors the reference engine semantics. Returns startActiveUnix, endActiveUnix, expiryUnix.
func ConfigureRankCacheBlacklist ¶
func ConfigureRankCacheBlacklist(csv string)
ConfigureRankCacheBlacklist configures blacklist from a comma-separated list. Use "*" to disable rank cache for all leaderboards.
func CreateLeaderboard ¶
CreateLeaderboard inserts a new leaderboard configuration.
func DeleteLeaderboard ¶
DeleteLeaderboard deletes a leaderboard configuration and all its records.
func DeleteRecord ¶
DeleteRecord deletes a specific leaderboard record for a user across all expiries for the board.
func DeleteRecordForExpiry ¶
func DeleteRecordForExpiry(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, leaderboardID, ownerID string, expiryUnix int64) error
DeleteRecordForExpiry deletes a record for a specific expiry partition.
func DisableRanks ¶
DisableRanks sets enable_ranks=false for a leaderboard or tournament.
func EncodeCursor ¶
func EncodeCursor(c *RecordListCursor) (string, error)
EncodeCursor serializes a pagination cursor to a URL-safe string.
func IsRankCacheBlacklisted ¶
IsRankCacheBlacklisted reports whether rank cache is disabled for the given board.
func ManualReset ¶
func ManualReset(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, archive bool) (int64, error)
ManualReset archives the current expiry partition (optional), clears those records, and fires cache eviction.
func MustParseResetSchedule ¶
func MustParseResetSchedule(expr string) *cronexpr.Expression
MustParseResetSchedule parses a cron expression, returning nil on empty or error.
func ParseResetSchedule ¶
func ParseResetSchedule(expr string) (*cronexpr.Expression, error)
ParseResetSchedule parses a 5–7 field cron expression. Empty string returns nil.
func PruneExpiredRecords ¶
PruneExpiredRecords deletes records whose expiry_time has passed (and is not epoch).
func RecordsDeleteAll ¶
RecordsDeleteAll deletes all leaderboard records for a user and clears rank cache entries.
func RecordsListCursorFromRank ¶
func RecordsListCursorFromRank(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, rank, expiryOverride int64) (string, error)
RecordsListCursorFromRank builds a list cursor that starts just before the given 1-based rank.
func ResolveExpiryTime ¶
ResolveExpiryTime converts expiry unix to timestamptz for DB queries.
func StartInvalidationListener ¶
StartInvalidationListener subscribes to Redis Pub/Sub and evicts local caches.
func StartRankCacheTrimmer ¶
func StartRankCacheTrimmer(stop <-chan struct{})
StartRankCacheTrimmer runs hourly expiry trim in the background.
func ValidateLeaderboardID ¶
func ValidateMetadata ¶
Types ¶
type ConfigCache ¶
type ConfigCache struct {
// contains filtered or unexported fields
}
ConfigCache is an in-memory cache of leaderboard configurations.
func (*ConfigCache) Delete ¶
func (c *ConfigCache) Delete(id string)
Delete removes a leaderboard from the cache.
func (*ConfigCache) Get ¶
func (c *ConfigCache) Get(id string) *Leaderboard
Get returns a cached leaderboard by ID (nil if missing).
func (*ConfigCache) InvalidateAge ¶
func (c *ConfigCache) InvalidateAge(_ time.Duration)
InvalidateAge is unused placeholder for future TTL policies.
func (*ConfigCache) ListAll ¶
func (c *ConfigCache) ListAll() []*Leaderboard
ListAll returns all cached configs (copy).
func (*ConfigCache) ListLeaderboardsCached ¶
func (c *ConfigCache) ListLeaderboardsCached() []*Leaderboard
ListLeaderboardsCached returns non-tournament leaderboards from cache.
func (*ConfigCache) ListTournamentsCached ¶
func (c *ConfigCache) ListTournamentsCached() []*Leaderboard
ListTournamentsCached returns tournament configs from cache.
func (*ConfigCache) LoadAll ¶
func (c *ConfigCache) LoadAll(lbs []*Leaderboard)
LoadAll loads all leaderboard rows from the database into the cache.
func (*ConfigCache) Put ¶
func (c *ConfigCache) Put(lb *Leaderboard)
Put inserts or replaces a leaderboard config.
type GlobalRankCache ¶
type GlobalRankCache struct {
// contains filtered or unexported fields
}
GlobalRankCache manages per-partition rank caches with incremental updates.
func (*GlobalRankCache) Delete ¶
func (g *GlobalRankCache) Delete(leaderboardID string, expiryUnix int64, ownerID string)
Delete removes an owner from the rank cache.
func (*GlobalRankCache) DeleteLeaderboard ¶
func (g *GlobalRankCache) DeleteLeaderboard(leaderboardID string)
DeleteLeaderboard removes all partitions for a leaderboard.
func (*GlobalRankCache) EvictPartition ¶
func (g *GlobalRankCache) EvictPartition(leaderboardID string, expiryUnix int64)
EvictPartition removes one expiry partition.
func (*GlobalRankCache) FillRanks ¶
func (g *GlobalRankCache) FillRanks(leaderboardID string, expiryUnix int64, records []*LeaderboardRecord, enableRanks bool)
FillRanks assigns Rank fields on records using the cache when available.
func (*GlobalRankCache) GetDataByRank ¶
func (g *GlobalRankCache) GetDataByRank(leaderboardID string, expiryUnix, rank int64) (ownerID string, score, subscore int64, ok bool)
GetDataByRank returns owner/score at 1-based rank for a partition.
func (*GlobalRankCache) GetRank ¶
func (g *GlobalRankCache) GetRank(leaderboardID string, expiryUnix int64, ownerID string) int64
GetRank returns 1-based rank for owner, or 0 if disabled/missing.
func (*GlobalRankCache) Insert ¶
func (g *GlobalRankCache) Insert(leaderboardID string, sortOrder int, score, subscore int64, expiryUnix int64, ownerID string, enableRanks bool) int64
Insert upserts a score and returns the new 1-based rank (0 if ranks disabled).
func (*GlobalRankCache) LoadFromRecords ¶
func (g *GlobalRankCache) LoadFromRecords(leaderboardID string, expiryUnix int64, sortOrder int, enableRanks bool, records []*LeaderboardRecord)
LoadFromRecords seeds the cache from a full sorted record slice.
func (*GlobalRankCache) TrimExpired ¶
func (g *GlobalRankCache) TrimExpired(nowUnix int64)
TrimExpired removes partitions with expiryUnix <= nowUnix (non-zero expiries only).
type InvalidationPayload ¶
type InvalidationPayload struct {
LeaderboardID string `json:"leaderboard_id"`
ExpiryTime int64 `json:"expiry_time"`
}
InvalidationPayload is published to Redis Pub/Sub on score updates.
type Leaderboard ¶
type Leaderboard struct {
ID string `json:"id"`
Authoritative bool `json:"authoritative"`
SortOrder int `json:"sort_order"`
Operator int `json:"operator"`
ResetSchedule string `json:"reset_schedule"`
Metadata string `json:"metadata"`
CreateTime time.Time `json:"create_time"`
Category int `json:"category"`
Description string `json:"description"`
Duration int `json:"duration"`
EndTime time.Time `json:"end_time"`
JoinRequired bool `json:"join_required"`
MaxSize int `json:"max_size"`
MaxNumScore int `json:"max_num_score"`
Title string `json:"title"`
Size int `json:"size"`
StartTime time.Time `json:"start_time"`
EnableRanks bool `json:"enable_ranks"`
}
Leaderboard represents a leaderboard configuration.
func GetLeaderboard ¶
GetLeaderboard fetches a leaderboard config.
func LeaderboardsGetId ¶
func LeaderboardsGetId(ctx context.Context, pool *pgxpool.Pool, ids []string) ([]*Leaderboard, error)
LeaderboardsGetId returns non-tournament leaderboards by ID.
func ListLeaderboards ¶
func ListLeaderboards(ctx context.Context, pool *pgxpool.Pool, limit int, cursor string) ([]*Leaderboard, string, error)
ListLeaderboards returns paginated leaderboard configs (non-tournament first-class list).
func LoadAllLeaderboards ¶
LoadAllLeaderboards loads every leaderboard config (for cache warmup).
func ResolveCurrentExpiry ¶
func ResolveCurrentExpiry(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, overrideExpiry int64) (time.Time, *Leaderboard, error)
ResolveCurrentExpiry loads the leaderboard and returns the active expiry time.
func TournamentsGetId ¶
func TournamentsGetId(ctx context.Context, pool *pgxpool.Pool, ids []string) ([]*Leaderboard, error)
TournamentsGetId returns tournament configs by ID.
func (*Leaderboard) IsTournament ¶
func (lb *Leaderboard) IsTournament() bool
IsTournament returns true when duration > 0 (tournament-backed leaderboard).
type LeaderboardRecord ¶
type LeaderboardRecord struct {
LeaderboardID string `json:"leaderboard_id"`
OwnerID string `json:"owner_id"`
Username string `json:"username"`
Score int64 `json:"score"`
Subscore int64 `json:"subscore"`
NumScore int `json:"num_score"`
MaxNumScore int `json:"max_num_score"`
Metadata string `json:"metadata"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
ExpiryTime time.Time `json:"expiry_time"`
Rank int64 `json:"rank"`
}
LeaderboardRecord represents a score entry.
func GetLeaderboardRecords ¶
func GetLeaderboardRecords(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, leaderboardID string, limit int, cursor string, expiryTime time.Time) ([]*LeaderboardRecord, string, error)
GetLeaderboardRecords retrieves sorted, paginated records with keyset cursors.
func GetLeaderboardRecordsAroundPlayer ¶
func GetLeaderboardRecordsAroundPlayer(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, leaderboardID, ownerID string, limit int, expiryTime time.Time) ([]*LeaderboardRecord, error)
GetLeaderboardRecordsAroundPlayer retrieves records centered around the target player.
func GetLeaderboardRecordsPaged ¶
func GetLeaderboardRecordsPaged(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, limit int, cursor string, expiryTime time.Time, overrideExpiry int64) ([]*LeaderboardRecord, string, string, error)
GetLeaderboardRecordsPaged returns next and prev cursors.
func GetOwnerRecords ¶
func GetOwnerRecords(ctx context.Context, pool *pgxpool.Pool, leaderboardID string, ownerIDs []string, expiryTime time.Time) ([]*LeaderboardRecord, error)
GetOwnerRecords fetches specific owners' records for a leaderboard expiry.
func ListArchivedRecords ¶
func ListArchivedRecords(ctx context.Context, pool *pgxpool.Pool, leaderboardID, seasonKey string, limit int) ([]*LeaderboardRecord, error)
ListArchivedRecords returns archived records for a leaderboard season.
func RecordsHaystack ¶
func RecordsHaystack(ctx context.Context, pool *pgxpool.Pool, leaderboardID, ownerID string, limit int, cursor string, expiryOverride int64) ([]*LeaderboardRecord, string, string, error)
RecordsHaystack returns records around an owner with optional cursor pagination.
func RecordsReadAll ¶
func RecordsReadAll(ctx context.Context, pool *pgxpool.Pool, ownerID string) ([]*LeaderboardRecord, error)
RecordsReadAll returns all leaderboard records owned by a user.
func SubmitScore ¶
func SubmitScore(ctx context.Context, pool *pgxpool.Pool, rdb *redis.Client, leaderboardID, ownerID, username string, score, subscore int64, metadata string, byPlayer bool, overrideOp ...int) (*LeaderboardRecord, error)
SubmitScore writes a player score, enforcing constraints and operators. Optional overrideOp: when provided and != OperatorNoOverride / when first element >= 0, overrides the leaderboard's configured operator (BEST/SET/INCREMENT/DECREMENT).
type RankCache ¶
type RankCache struct {
// contains filtered or unexported fields
}
RankCache holds ordered ranks for one leaderboard+expiry partition using a skip list.
type RecordListCursor ¶
type RecordListCursor struct {
IsNext bool
LeaderboardID string
ExpiryUnix int64
Score int64
Subscore int64
OwnerID string
Rank int64
}
RecordListCursor encodes keyset pagination state.
func DecodeCursor ¶
func DecodeCursor(s string) (*RecordListCursor, error)
DecodeCursor deserializes a pagination cursor.
type SeasonStat ¶
type SeasonStat struct {
TournamentID string `json:"tournament_id"`
SeasonKey string `json:"season_key"`
OwnerID string `json:"owner_id"`
Participations int `json:"participations"`
BestScore int64 `json:"best_score"`
BestSubscore int64 `json:"best_subscore"`
TotalRewards int64 `json:"total_rewards"`
UpdateTime time.Time `json:"update_time"`
}
SeasonStat is per-player season aggregate for a tournament.
func ListSeasonStats ¶
func ListSeasonStats(ctx context.Context, pool *pgxpool.Pool, tournamentID, seasonKey string, limit int) ([]*SeasonStat, error)
ListSeasonStats returns season stats for a tournament.
type SkipListRankCache ¶
type SkipListRankCache struct {
// contains filtered or unexported fields
}
SkipListRankCache is an O(log n) ordered rank structure per partition.
func (*SkipListRankCache) Delete ¶
func (s *SkipListRankCache) Delete(ownerID string)
func (*SkipListRankCache) GetDataByRank ¶
func (s *SkipListRankCache) GetDataByRank(rank int64) (RankEntry, bool)
func (*SkipListRankCache) GetRank ¶
func (s *SkipListRankCache) GetRank(ownerID string) int64
func (*SkipListRankCache) Insert ¶
func (s *SkipListRankCache) Insert(entry RankEntry) int64
func (*SkipListRankCache) Size ¶
func (s *SkipListRankCache) Size() int