53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import type { RudderContext } from '../core/context.js';
|
|
import { api } from '../generated/api.js';
|
|
import type { RankEntry } from '../generated/leaderboards.js';
|
|
|
|
/**
|
|
* A cached handle for a specific leaderboard.
|
|
*
|
|
* Created by `LeaderboardsService.findBySlug()` — subsequent calls with
|
|
* the same slug return the same handle, avoiding redundant fetches.
|
|
*/
|
|
export class LeaderboardHandle {
|
|
private entries: RankEntry[] = [];
|
|
|
|
constructor(
|
|
public readonly slug: string,
|
|
private readonly ctx: RudderContext,
|
|
) {}
|
|
|
|
getEntries(): readonly RankEntry[] {
|
|
return this.entries;
|
|
}
|
|
|
|
async submit(score: number): Promise<void> {
|
|
return api.submitScore(this.ctx, { slug: this.slug }, { slug: this.slug, score });
|
|
}
|
|
|
|
async list(limit = 100): Promise<readonly RankEntry[]> {
|
|
const response = await api.getRanking(
|
|
this.ctx,
|
|
{ slug: this.slug },
|
|
{ limit: limit > 0 ? limit : undefined },
|
|
);
|
|
this.entries = response.entries ?? [];
|
|
return this.entries;
|
|
}
|
|
}
|
|
|
|
export class LeaderboardsService {
|
|
private readonly cache = new Map<string, LeaderboardHandle>();
|
|
|
|
constructor(private readonly ctx: RudderContext) {}
|
|
|
|
/** Returns a cached handle for the given leaderboard slug. */
|
|
findBySlug(slug: string): LeaderboardHandle {
|
|
let handle = this.cache.get(slug);
|
|
if (!handle) {
|
|
handle = new LeaderboardHandle(slug, this.ctx);
|
|
this.cache.set(slug, handle);
|
|
}
|
|
return handle;
|
|
}
|
|
}
|