Newer
Older
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
import { Socket } from "socket.io";
import { Logger } from "../lib/Logger";
import { prisma } from "../lib/prisma";
import { AuthSession } from "@sc07-canvas/lib/src/net";
interface IUserData {
sub: string;
lastPixelTime: Date;
pixelStack: number;
}
export class User {
static instances: Map<string, User> = new Map();
sub: string;
lastPixelTime: Date;
pixelStack: number;
authSession?: AuthSession;
sockets: Set<Socket> = new Set();
private _updatedAt: number;
private constructor(data: IUserData) {
Logger.debug("User class instansiated for " + data.sub);
this.sub = data.sub;
this.lastPixelTime = data.lastPixelTime;
this.pixelStack = data.pixelStack;
this._updatedAt = Date.now();
}
async update(force: boolean = false) {
if (this.isStale() && !force) return;
const userData = await prisma.user.findFirst({
where: {
sub: this.sub,
},
});
if (!userData) throw new UserNotFound();
this.lastPixelTime = userData.lastPixelTime;
this.pixelStack = userData.pixelStack;
}
async modifyStack(modifyBy: number): Promise<any> {
const updatedUser = await prisma.user.update({
where: { sub: this.sub },
data: {
pixelStack: { increment: modifyBy },
},
});
for (const socket of this.sockets) {
socket.emit("availablePixels", updatedUser.pixelStack);
}
// we just modified the user data, so we should force an update
await this.update(true);
}
/**
* Determine if this user data is stale and should be updated
* @see User#update
* @returns if this user data is stale
*/
private isStale() {
return Date.now() - this._updatedAt >= 1000 * 60;
}
static async fromAuthSession(auth: AuthSession): Promise<User | undefined> {
try {
const user = await this.fromSub(
auth.user.username + "@" + auth.service.instance.hostname
);
user.authSession = auth;
return user;
} catch (e) {
if (e instanceof UserNotFound) {
return undefined;
} else {
throw e;
}
}
}
static async fromSub(sub: string): Promise<User> {
if (this.instances.has(sub)) return this.instances.get(sub)!;
const userData = await prisma.user.findFirst({
where: {
sub,
},
});
if (!userData) throw new UserNotFound();
const newUser = new User(userData);
this.instances.set(sub, newUser);
return newUser;
}
}
export class UserNotFound extends Error {
constructor() {
super();
this.name = "UserNotFound";
}
}