-
Notifications
You must be signed in to change notification settings - Fork 2
/
StatsService.ts
146 lines (129 loc) · 4.06 KB
/
StatsService.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import "reflect-metadata";
import fsOld from "fs";
const fs = fsOld.promises;
import {
jsonObject,
jsonMember,
TypedJSON,
jsonMapMember,
jsonArrayMember,
} from "typedjson";
import crypto from "crypto";
@jsonObject
class StatsInfo {
constructor() {
this.slots = new Map<string, number>();
}
@jsonMapMember(String, Number)
public slots: Map<string, number>;
incrementSlot(slot: string) {
this.slots.set(slot, (this.slots.get(slot) || 0) + 1);
}
}
@jsonObject
export class StatsService {
constructor(slotCount: number, excludedIDs: string[]) {
this.slotCount = slotCount;
this.stats = new Map<string, StatsInfo>();
this.exludedIDs = excludedIDs;
}
private exludedIDs: string[];
private basePath: string | undefined;
private fileName: string | undefined;
@jsonMember
public slotCount: number;
@jsonMapMember(String, StatsInfo)
public stats: Map<string, StatsInfo>;
async increment(key: string, userID: string) {
if (this.exludedIDs.includes(userID)) {
return;
}
let fileName = StatsService.getFileName();
// If we are in a new day, reset the stats
if (this.fileName !== fileName) {
this.stats = new Map<string, StatsInfo>();
this.fileName = fileName;
}
let stats = this.stats.get(key);
if (stats === undefined) {
stats = new StatsInfo();
this.stats.set(key, stats);
}
// Use cypto to hash the userID
let hash = crypto.createHash("sha256");
hash.update(userID);
// Convert the hash to a hex number string
let hashDigest = hash.digest("hex");
// Get the last 10 digits of the hash and convert it to a number
let hashDigestNumber = parseInt(hashDigest.substr(-10), 16);
stats.incrementSlot(`${hashDigestNumber % this.slotCount}`);
if (this.basePath !== undefined) {
await this.save(this.basePath);
}
}
static async load(
basePath: string,
slotCount: number,
excludedIDs: string[]
): Promise<StatsService> {
// Get date as a dd-mm-yyyy string
let fileName = StatsService.getFileName();
let stats: StatsService | undefined;
// If the file exists load its content and create a StatsService from it
// using TypedJSON
try {
let statsFile = await fs.readFile(
basePath + "/" + fileName,
"utf8"
);
stats = TypedJSON.parse(statsFile, StatsService);
if (stats === undefined) {
throw new Error("Could not parse stats file");
}
stats.slotCount = slotCount;
stats.exludedIDs = excludedIDs;
stats.basePath = basePath;
stats.fileName = fileName;
} catch {
// If the file does not exist, create a new StatsService
stats = new StatsService(slotCount, excludedIDs);
// Save it to the file
await fs.writeFile(
basePath + "/" + fileName,
TypedJSON.stringify(stats, StatsService)
);
}
stats.basePath = basePath;
stats.fileName = fileName;
return stats;
}
async save(basePath: string) {
// Save file
await fs.writeFile(
basePath + "/" + this.fileName,
TypedJSON.stringify(this, StatsService)
);
}
getRawStatsCount(key: string): number {
let stats = this.stats.get(key);
if (stats === undefined) {
return 0;
}
// Sum up all the slot counts
let sum = 0;
for (let slot of stats.slots.values()) {
sum += slot;
}
return sum;
}
static getFileName(): string {
let date = new Date();
let dateString =
date.getDate() +
"-" +
(date.getMonth() + 1) +
"-" +
date.getFullYear();
return dateString + ".json";
}
}