leaderboard

package
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SortOrderAscending  = 0
	SortOrderDescending = 1

	OperatorBest      = 0
	OperatorSet       = 1
	OperatorIncrement = 2
	OperatorDecrement = 3

	MaxMetadataBytes       = 2 * 1024
	MaxPageSize            = 1000
	ScoreSubmissionsPerMin = 10
)
View Source
const OperatorNoOverride = -1

OperatorNoOverride sentinel for SubmitScore override (use board operator).

Variables

View Source
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")
)
View Source
var SharedConfigCache = &ConfigCache{
	byID: make(map[string]*Leaderboard),
}

SharedConfigCache is the process-wide leaderboard config cache.

View Source
var SharedRankCache = &GlobalRankCache{
	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

func CalculateExpiry(lb *Leaderboard, overrideExpiry int64, now time.Time) (int64, bool)

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

func CreateLeaderboard(ctx context.Context, pool *pgxpool.Pool, lb *Leaderboard) error

CreateLeaderboard inserts a new leaderboard configuration.

func DeleteLeaderboard

func DeleteLeaderboard(ctx context.Context, pool *pgxpool.Pool, id string) error

DeleteLeaderboard deletes a leaderboard configuration and all its records.

func DeleteRecord

func DeleteRecord(ctx context.Context, pool *pgxpool.Pool, leaderboardID, ownerID string) error

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

func DisableRanks(ctx context.Context, pool *pgxpool.Pool, id string, tournament bool) error

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

func IsRankCacheBlacklisted(leaderboardID string) bool

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

func PruneExpiredRecords(ctx context.Context, pool *pgxpool.Pool, now time.Time) (int64, error)

PruneExpiredRecords deletes records whose expiry_time has passed (and is not epoch).

func RecordsDeleteAll

func RecordsDeleteAll(ctx context.Context, pool *pgxpool.Pool, ownerID string) error

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

func ResolveExpiryTime(expiryUnix int64) time.Time

ResolveExpiryTime converts expiry unix to timestamptz for DB queries.

func StartInvalidationListener

func StartInvalidationListener(ctx context.Context, rdb *redis.Client)

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 ValidateLeaderboardID(id string) error

func ValidateMetadata

func ValidateMetadata(metadata string) error

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

func GetLeaderboard(ctx context.Context, pool *pgxpool.Pool, id string) (*Leaderboard, error)

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

func LoadAllLeaderboards(ctx context.Context, pool *pgxpool.Pool) ([]*Leaderboard, error)

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 RankEntry

type RankEntry struct {
	OwnerID  string
	Score    int64
	Subscore int64
}

RankEntry is a single ordered entry in the in-memory rank cache.

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL