Last active 3 weeks ago

history.ts Raw
1import fs from "fs";
2import path from "path";
3import { TGResult, TGScore, Nation } from "../types";
4import { oppositeNation } from "./nations";
5
6const HISTORY_DIR = path.join(__dirname, "../../data/tg-history");
7
8function historyKey(date: string, slot: number): string {
9 return `${date}-${String(slot).padStart(2, "0")}`;
10}
11
12function historyPath(key: string): string {
13 return path.join(HISTORY_DIR, `${key}.json`);
14}
15
16export function loadResult(date: string, slot: number): TGResult | null {
17 try {
18 return JSON.parse(fs.readFileSync(historyPath(historyKey(date, slot)), "utf8"));
19 } catch {
20 return null;
21 }
22}
23
24export function saveResult(result: TGResult): void {
25 if (!fs.existsSync(HISTORY_DIR)) fs.mkdirSync(HISTORY_DIR, { recursive: true });
26 const key = historyKey(result.date, result.slot);
27 fs.writeFileSync(historyPath(key), JSON.stringify(result, null, 2));
28}
29
30export function upsertScore(score: TGScore): void {
31 const result = loadResult(score.date, score.slot) ?? {
32 slot: score.slot,
33 date: score.date,
34 confirmed: false,
35 nationKD: {
36 source: "Procyon" as Nation,
37 capella: { k: 0, d: 0 },
38 procyon: { k: 0, d: 0 },
39 },
40 scores: [],
41 };
42
43 // Overwrite existing score for this player+slot
44 result.scores = result.scores.filter(
45 (s) => !(s.userKey === score.userKey && s.characterName === score.characterName && s.slot === score.slot && s.date === score.date)
46 );
47 result.scores.push(score);
48 saveResult(result);
49}
50
51export function setNationKD(
52 date: string,
53 slot: number,
54 sourceNation: Nation,
55 k: number,
56 d: number
57): TGResult {
58 const result = loadResult(date, slot) ?? {
59 slot,
60 date,
61 confirmed: false,
62 nationKD: { source: sourceNation, capella: { k: 0, d: 0 }, procyon: { k: 0, d: 0 } },
63 scores: [],
64 };
65
66 result.nationKD.source = sourceNation;
67 const other = oppositeNation(sourceNation);
68
69 result.nationKD[sourceNation.toLowerCase() as "capella" | "procyon"] = { k, d };
70 result.nationKD[other.toLowerCase() as "capella" | "procyon"] = { k: d, d: k };
71
72 saveResult(result);
73 return result;
74}
75
76export function listRecentResults(limit = 10): TGResult[] {
77 if (!fs.existsSync(HISTORY_DIR)) return [];
78 return fs.readdirSync(HISTORY_DIR)
79 .filter((f) => f.endsWith(".json"))
80 .sort()
81 .reverse()
82 .slice(0, limit)
83 .map((f) => {
84 try { return JSON.parse(fs.readFileSync(path.join(HISTORY_DIR, f), "utf8")) as TGResult; }
85 catch { return null; }
86 })
87 .filter(Boolean) as TGResult[];
88}
89
90export function todayString(): string {
91 return new Date().toISOString().slice(0, 10);
92}
93