th3w1zard1's picture
Deploy GPTR trask-http from community-bots local CI
3a25f97 verified
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
const cloneWallet = (wallet) => ({ ...wallet });
const createWallet = (userId, displayName, startingBalance) => {
return {
userId,
displayName,
balance: startingBalance,
wins: 0,
losses: 0,
streak: 0,
bestStreak: 0,
lastDailyAt: null,
rivalries: {},
updatedAt: new Date().toISOString(),
};
};
export const resolveDataFile = (rootDir, fileName) => {
return path.resolve(rootDir, fileName);
};
export class JsonWalletRepository {
filePath;
startingBalance;
state;
constructor(filePath, startingBalance) {
this.filePath = filePath;
this.startingBalance = startingBalance;
}
async getWallet(userId, displayName) {
const state = await this.ensureState();
const wallet = state.wallets[userId] ?? this.upsertWallet(state, userId, displayName);
return cloneWallet(wallet);
}
async canCover(userId, displayName, amount) {
const wallet = await this.getWallet(userId, displayName);
return wallet.balance >= amount;
}
async listWallets() {
const state = await this.ensureState();
return Object.values(state.wallets)
.map(cloneWallet)
.sort((left, right) => right.balance - left.balance || right.wins - left.wins || left.losses - right.losses);
}
async claimDailyBonus(userId, displayName, bonusAmount, cooldownMs) {
const state = await this.ensureState();
const wallet = this.upsertWallet(state, userId, displayName);
const now = Date.now();
const lastDaily = wallet.lastDailyAt ? new Date(wallet.lastDailyAt).getTime() : 0;
if (now - lastDaily < cooldownMs) {
return { credited: false, amount: 0, nextEligibleAt: lastDaily + cooldownMs };
}
wallet.balance += bonusAmount;
wallet.lastDailyAt = new Date().toISOString();
wallet.updatedAt = new Date().toISOString();
await this.persist(state);
return { credited: true, amount: bonusAmount, nextEligibleAt: now + cooldownMs };
}
async recordMatch(options) {
const state = await this.ensureState();
const winner = this.upsertWallet(state, options.winnerId, options.winnerName);
const loser = this.upsertWallet(state, options.loserId, options.loserName);
loser.balance = Math.max(0, loser.balance - options.wager);
loser.losses += 1;
loser.streak = 0;
loser.updatedAt = new Date().toISOString();
winner.balance += options.wager;
winner.wins += 1;
winner.streak += 1;
winner.bestStreak = Math.max(winner.bestStreak, winner.streak);
winner.updatedAt = new Date().toISOString();
this.upsertRivalry(winner, options.loserId, options.loserName, "win");
this.upsertRivalry(loser, options.winnerId, options.winnerName, "loss");
await this.persist(state);
return {
winner: cloneWallet(winner),
loser: cloneWallet(loser),
};
}
topRivalry(wallet) {
const entries = Object.values(wallet.rivalries);
if (entries.length === 0)
return undefined;
return entries.reduce((best, entry) => {
const bestTotal = best.wins + best.losses;
const entryTotal = entry.wins + entry.losses;
return entryTotal > bestTotal ? entry : best;
});
}
allRivalries(wallet) {
return Object.values(wallet.rivalries).sort((a, b) => (b.wins + b.losses) - (a.wins + a.losses));
}
/**
* Directly adjust a wallet balance by a signed delta (positive = add, negative = subtract).
* Balance is floored at 0. Returns the updated wallet record.
*/
async adjustBalance(userId, displayName, delta) {
const state = await this.ensureState();
const wallet = this.upsertWallet(state, userId, displayName);
wallet.balance = Math.max(0, wallet.balance + delta);
wallet.updatedAt = new Date().toISOString();
await this.persist(state);
return cloneWallet(wallet);
}
async ensureState() {
if (this.state) {
return this.state;
}
await mkdir(path.dirname(this.filePath), { recursive: true });
try {
const raw = await readFile(this.filePath, "utf8");
this.state = JSON.parse(raw);
}
catch {
this.state = {
version: 1,
wallets: {},
};
await this.persist(this.state);
}
return this.state;
}
upsertWallet(state, userId, displayName) {
const existing = state.wallets[userId];
if (existing) {
existing.displayName = displayName;
return existing;
}
const created = createWallet(userId, displayName, this.startingBalance);
state.wallets[userId] = created;
return created;
}
upsertRivalry(wallet, opponentId, opponentName, outcome) {
const existing = wallet.rivalries[opponentId];
if (existing) {
existing.opponentName = opponentName;
if (outcome === "win")
existing.wins += 1;
else
existing.losses += 1;
return;
}
wallet.rivalries[opponentId] = {
opponentId,
opponentName,
wins: outcome === "win" ? 1 : 0,
losses: outcome === "loss" ? 1 : 0,
};
}
async persist(state) {
await writeFile(this.filePath, JSON.stringify(state, null, 2), "utf8");
}
}
const presetKey = (guildId, userId) => `${guildId}:${userId}`;
export class JsonDesignationPresetRepository {
filePath;
state;
constructor(filePath) {
this.filePath = filePath;
}
async getPreset(guildId, userId) {
const state = await this.ensureState();
return state.presets[presetKey(guildId, userId)]?.roleIds;
}
async savePreset(guildId, userId, roleIds) {
const state = await this.ensureState();
state.presets[presetKey(guildId, userId)] = {
userId,
guildId,
roleIds: [...roleIds],
updatedAt: new Date().toISOString(),
};
await this.persist(state);
}
async ensureState() {
if (this.state) {
return this.state;
}
await mkdir(path.dirname(this.filePath), { recursive: true });
try {
const raw = await readFile(this.filePath, "utf8");
this.state = JSON.parse(raw);
}
catch {
this.state = { version: 1, presets: {} };
await this.persist(this.state);
}
return this.state;
}
async persist(state) {
await writeFile(this.filePath, JSON.stringify(state, null, 2), "utf8");
}
}
//# sourceMappingURL=index.js.map