155 lines
No EOL
4.3 KiB
TypeScript
155 lines
No EOL
4.3 KiB
TypeScript
import { client } from "../../db";
|
|
import { Client } from "./Client";
|
|
import { Participiant } from "./Participiant";
|
|
|
|
import {exists} from "fs/promises";
|
|
|
|
export class Room {
|
|
participiants: Map<string, Participiant> = new Map();
|
|
name: string;
|
|
hidden: boolean;
|
|
messageHistory: {
|
|
userID: string;
|
|
content: string;
|
|
images?: string[] | undefined;
|
|
username: string;
|
|
time: number;
|
|
}[] = [];
|
|
|
|
timeout?: number;
|
|
|
|
constructor(name: string, hidden: boolean) {
|
|
this.name = name;
|
|
this.hidden = hidden;
|
|
}
|
|
|
|
async addMessage(
|
|
message: { message: string; images: string[] },
|
|
part: Participiant
|
|
) {
|
|
if (message.message.length > 200) return;
|
|
if (message.message.length < 1) return;
|
|
let validImages: string[] = [];
|
|
|
|
for (const image of message.images) {
|
|
if (!/^[a-z0-9]{1,16}$/gm.test(image)) continue;
|
|
if (await exists("static/images/" + image)) {
|
|
validImages.push(image);
|
|
}
|
|
}
|
|
|
|
const punishments = await client.punishment.findMany({
|
|
where: {
|
|
punishedUserId: part.user.id,
|
|
type: "mute",
|
|
},
|
|
});
|
|
|
|
for (const punishment of punishments) {
|
|
if (punishment.time == -1) punishment.time = Infinity;
|
|
const diff =
|
|
punishment.at.getTime() + punishment.time - new Date().getTime();
|
|
|
|
if (diff > 0) {
|
|
// punishment is valid
|
|
const punishedBy = await client.user.findFirst({
|
|
where: {
|
|
id: punishment.staffId,
|
|
},
|
|
});
|
|
|
|
part.broadcast({
|
|
type: "notification",
|
|
message: `You've been muted by ${punishedBy?.username}. There are ${diff}ms left in your mute. You were muted at ${punishment.at}. The reason you were muted is "${punishment.reason}"`,
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
const msg = {
|
|
content: message.message,
|
|
images: validImages,
|
|
time: Date.now(),
|
|
userID: part.user.id,
|
|
username: part.user.username,
|
|
};
|
|
|
|
for (const part of this.participiants) {
|
|
part[1].broadcast({
|
|
type: "message",
|
|
message: msg,
|
|
});
|
|
}
|
|
|
|
this.messageHistory.push(msg);
|
|
}
|
|
addClient(client: Client) {
|
|
let part = this.participiants.get(client.userId);
|
|
if (part) {
|
|
part.room = this.name;
|
|
part.addClient(client);
|
|
} else {
|
|
part = client.makeParticipiant();
|
|
part.room = this.name;
|
|
part.addClient(client);
|
|
this.participiants.set(part.user.id, part);
|
|
}
|
|
if (this.timeout) {
|
|
clearTimeout(this.timeout);
|
|
this.timeout = undefined;
|
|
client.send({
|
|
type: "notification",
|
|
message: `You saved ${this.name}! Thank you!`,
|
|
});
|
|
}
|
|
client.send({
|
|
type: "history",
|
|
messages: this.messageHistory,
|
|
});
|
|
client.send({
|
|
type: "room",
|
|
room: this.name,
|
|
});
|
|
|
|
this.updatePeople();
|
|
}
|
|
|
|
removeClient(client: Client, timeoutFunction: () => void) {
|
|
let part = this.participiants.get(client.userId);
|
|
if (!part) return;
|
|
part.clients = part.clients.filter((z) => z.id !== client.id);
|
|
if (part.clients.length == 0) {
|
|
this.participiants.delete(client.userId);
|
|
}
|
|
if (this.participiants.size == 0) {
|
|
client.send({
|
|
type: "notification",
|
|
message:
|
|
this.name +
|
|
" has 0 users left! If nobody joins in 15 seconds, the room's history will be deleted.",
|
|
});
|
|
|
|
this.timeout = setTimeout(timeoutFunction, 15000) as unknown as number;
|
|
}
|
|
this.updatePeople();
|
|
return part.clients.length == 0;
|
|
}
|
|
sendPeople(z: Client) {
|
|
z.send({
|
|
type: "people",
|
|
people: [...this.participiants.values()].map((z) => {
|
|
return { username: z.user?.username, id: z.user?.id, status: z.user?.status };
|
|
}),
|
|
});
|
|
}
|
|
updatePeople() {
|
|
this.participiants.forEach((z) => {
|
|
z.broadcast({
|
|
type: "people",
|
|
people: [...this.participiants.values()].map((z) => {
|
|
return { username: z.user?.username, id: z.user?.id, status: z.user?.status };
|
|
}),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|