From 29c3caea0e2b0f8a21c450be53fb115ca4ebaed9 Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Wed, 31 Jul 2024 19:01:09 -0400 Subject: [PATCH] Fix channel sending two update messages on join, delete chat history when room is destroyed --- src/channel/Channel.ts | 55 ++++--- src/data/history.ts | 4 + src/util/token.ts | 2 +- src/ws/events/user/handlers/hi.ts | 42 +++--- top | 243 ++++++++++++++++++++++++++++++ 5 files changed, 307 insertions(+), 39 deletions(-) create mode 100644 top diff --git a/src/channel/Channel.ts b/src/channel/Channel.ts index e33ddc6..beb797f 100755 --- a/src/channel/Channel.ts +++ b/src/channel/Channel.ts @@ -17,7 +17,7 @@ import Crown from "./Crown"; import { ChannelList } from "./ChannelList"; import { config } from "./config"; import { config as usersConfig } from "../ws/usersConfig"; -import { saveChatHistory, getChatHistory } from "../data/history"; +import { saveChatHistory, getChatHistory, deleteChatHistory } from "../data/history"; import { mixin, darken } from "../util/helpers"; import { User } from "@prisma/client"; import { heapStats } from "bun:jsc"; @@ -42,7 +42,18 @@ export class Channel extends EventEmitter { public chatHistory = new Array(); private async loadChatHistory() { - this.chatHistory = await getChatHistory(this.getID()); + try { + this.chatHistory = await getChatHistory(this.getID()); + + this.sendArray([{ + m: "c", + c: this.chatHistory + }]); + } catch (err) { } + } + + private async deleteChatHistory() { + await deleteChatHistory(this.getID()); } public logger: Logger; @@ -97,10 +108,8 @@ export class Channel extends EventEmitter { // ...and, possibly, an owner, too if (creator) { - // if (this.crown.canBeSetBy(creator)) { const part = creator.getParticipant(); - if (part) this.giveCrown(part); - // } + if (part) this.giveCrown(part, true, false); } } else { this.settings = config.lobbySettings; @@ -129,14 +138,13 @@ export class Channel extends EventEmitter { this.loadChatHistory(); this.logger.info("Loaded chat history"); - this.on("update", () => { - //this.logger.debug("-------- UPDATE START --------"); + this.on("update", (self, uuid) => { // Send updated info for (const socket of socketsBySocketID.values()) { for (const p of this.ppl) { - //if (socket.getParticipantID() == p.id) { - if (p.uuids.includes(socket.getUUID())) { - //this.logger.debug("sending to", socket.getUUID()) + const socketUUID = socket.getUUID(); + + if (p.uuids.includes(socketUUID) && socketUUID !== uuid) { socket.sendChannelUpdate( this.getInfo(), this.getParticipantList() @@ -276,6 +284,7 @@ export class Channel extends EventEmitter { ); } + //this.logger.debug("Update from user data update handler"); this.emit("update", this); } catch (err) { this.logger.error(err); @@ -328,6 +337,7 @@ export class Channel extends EventEmitter { // probably causes jank, but people can just reload their page or whatever // not sure what to do about the URL situation this._id = _id; + //this.logger.debug("Update from setID"); this.emit("update", this); } @@ -407,6 +417,7 @@ export class Channel extends EventEmitter { } */ + //this.logger.debug("Update from changeSettings"); this.emit("update", this); } @@ -486,7 +497,7 @@ export class Channel extends EventEmitter { p.uuids.push(socket.getUUID()) } - socket.sendChannelUpdate(this.getInfo(), this.getParticipantList()); + //socket.sendChannelUpdate(this.getInfo(), this.getParticipantList()); } else { // Add them to the channel hasChangedChannel = true; @@ -534,15 +545,13 @@ export class Channel extends EventEmitter { if (p) { // Give the crown back - this.giveCrown(p, true); + this.giveCrown(p, true, false); } } } } } - // Send our state data back - // TODO Does this go above? socket.sendArray([ // { // m: "ch", @@ -578,7 +587,9 @@ export class Channel extends EventEmitter { part.id ); - // Broadcast a channel update so everyone subscribed to the channel list can see us + // Broadcast a channel update so everyone subscribed to the channel list can see the new user count + //this.emit("update", this, socket.getUUID()); + //this.logger.debug("Update from join"); this.emit("update", this); //this.logger.debug("Settings:", this.settings); @@ -625,6 +636,7 @@ export class Channel extends EventEmitter { } ]); + //this.logger.debug("Update from leave"); this.emit("update", this); } else { for (const p of this.ppl) { @@ -789,6 +801,7 @@ export class Channel extends EventEmitter { } ChannelList.remove(this); + this.deleteChatHistory(); this.logger.info("Destroyed"); } @@ -819,7 +832,7 @@ export class Channel extends EventEmitter { * @param part Participant to give crown to * @param force Whether or not to force-create a crown (useful for lobbies) */ - public giveCrown(part: Participant, force = false) { + public giveCrown(part: Participant, force = false, update = true) { if (force) { if (!this.crown) this.crown = new Crown(); } @@ -828,7 +841,11 @@ export class Channel extends EventEmitter { this.crown.userId = part._id; this.crown.participantId = part.id; this.crown.time = Date.now(); - this.emit("update", this); + + if (update) { + //this.logger.debug("Update from giveCrown"); + this.emit("update", this); + } } } @@ -865,6 +882,7 @@ export class Channel extends EventEmitter { delete this.crown.participantId; + //this.logger.debug("Update from dropCrown"); this.emit("update", this); } } @@ -951,6 +969,7 @@ export class Channel extends EventEmitter { } if (shouldUpdate) { + //this.logger.debug("Update from kickban"); this.emit("update", this); if (typeof banner !== "undefined") { @@ -1149,7 +1168,7 @@ export class Channel extends EventEmitter { public printMemoryInChat() { const mem = heapStats(); - this.sendChatAdmin(`Size: ${(mem.heapSize / 1000 / 1000).toFixed(2)}M / Capacity: ${(mem.heapCapacity / 1000 / 1000).toFixed(2)}M`); + this.sendChatAdmin(`Used: ${(mem.heapSize / 1000 / 1000).toFixed(2)}M / Allocated: ${(mem.heapCapacity / 1000 / 1000).toFixed(2)}M`); } } diff --git a/src/data/history.ts b/src/data/history.ts index b769e27..0b68962 100755 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -27,3 +27,7 @@ export async function getChatHistory(_id: string) { return []; } } + +export async function deleteChatHistory(_id: string) { + await prisma.chatHistory.delete({ where: { id: _id } }); +} diff --git a/src/util/token.ts b/src/util/token.ts index 54d22af..4e7bf6f 100644 --- a/src/util/token.ts +++ b/src/util/token.ts @@ -50,7 +50,7 @@ export async function createToken(userID: string, gateway: Gateway) { let token = ""; if (config.tokenAuth == "uuid") { - token = crypto.randomUUID(); + token = userID + "." + crypto.randomUUID(); } else if (config.tokenAuth == "jwt") { token = generateJWT(userID, gateway); } diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts index 91067b1..964c2cb 100755 --- a/src/ws/events/user/handlers/hi.ts +++ b/src/ws/events/user/handlers/hi.ts @@ -32,28 +32,30 @@ export const hi: ServerEventListener<"hi"> = { let token: string | undefined; let generatedToken = false; - if (typeof msg.token !== "string") { - // Get a saved token - token = await getToken(socket.getUserID()); - if (typeof token !== "string") { - // Generate a new one - token = await createToken(socket.getUserID(), socket.gateway); - + if (config.tokenAuth !== "none") { + if (typeof msg.token !== "string") { + // Get a saved token + token = await getToken(socket.getUserID()); if (typeof token !== "string") { - logger.warn(`Unable to generate token for user ${socket.getUserID()}`); - } else { - generatedToken = true; - } - } - } else { - // Validate the token - const valid = await validateToken(socket.getUserID(), msg.token); - if (!valid) { - socket.ban(60000, "Invalid token"); - return; - } + // Generate a new one + token = await createToken(socket.getUserID(), socket.gateway); - token = msg.token; + if (typeof token !== "string") { + logger.warn(`Unable to generate token for user ${socket.getUserID()}`); + } else { + generatedToken = true; + } + } + } else { + // Validate the token + const valid = await validateToken(socket.getUserID(), msg.token); + if (!valid) { + socket.ban(60000, "Invalid token"); + return; + } + + token = msg.token; + } } let part = socket.getParticipant(); diff --git a/top b/top new file mode 100644 index 0000000..cf1fd81 --- /dev/null +++ b/top @@ -0,0 +1,243 @@ +diff --git a/src/channel/Channel.ts b/src/channel/Channel.ts +index e33ddc6..b6072be 100755 +--- a/src/channel/Channel.ts ++++ b/src/channel/Channel.ts +@@ -17,7 +17,7 @@ import Crown from "./Crown"; +import { ChannelList } from "./ChannelList"; +import { config } from "./config"; +import { config as usersConfig } from "../ws/usersConfig"; +import { saveChatHistory, [-getChatHistory-]{+getChatHistory, deleteChatHistory+} } from "../data/history"; +import { mixin, darken } from "../util/helpers"; +import { User } from "@prisma/client"; +import { heapStats } from "bun:jsc"; +@@ -42,7 +42,18 @@ export class Channel extends EventEmitter { + public chatHistory = new Array(); + + private async loadChatHistory() { + {+try {+} + this.chatHistory = await getChatHistory(this.getID()); + + {+this.sendArray([{+} +{+ m: "c",+} +{+ c: this.chatHistory+} +{+ }]);+} +{+ } catch (err) { }+} +{+ }+} + +{+ private async deleteChatHistory() {+} +{+ await deleteChatHistory(this.getID());+} + } + + public logger: Logger; +@@ -97,10 +108,8 @@ export class Channel extends EventEmitter { + + // ...and, possibly, an owner, too + if (creator) { +[- // if (this.crown.canBeSetBy(creator)) {-] + const part = creator.getParticipant(); + if (part) [-this.giveCrown(part);-] +[- // }-]{+this.giveCrown(part, true, false);+} + } + } else { + this.settings = config.lobbySettings; +@@ -129,14 +138,13 @@ export class Channel extends EventEmitter { + this.loadChatHistory(); + this.logger.info("Loaded chat history"); + + this.on("update", [-()-]{+(self, uuid)+} => {[-//this.logger.debug("-------- UPDATE START --------");-] + // Send updated info + for (const socket of socketsBySocketID.values()) { + for (const p of this.ppl) { + [-//if (socket.getParticipantID() == p.id) {-]{+const socketUUID = socket.getUUID();+} + + if [-(p.uuids.includes(socket.getUUID()))-]{+(p.uuids.includes(socketUUID) && socketUUID !== uuid)+} {[-//this.logger.debug("sending to", socket.getUUID())-] + socket.sendChannelUpdate( + this.getInfo(), + this.getParticipantList() +@@ -276,6 +284,7 @@ export class Channel extends EventEmitter { + ); + } + + {+this.logger.debug("Update from user data update handler");+} + this.emit("update", this); + } catch (err) { + this.logger.error(err); +@@ -328,6 +337,7 @@ export class Channel extends EventEmitter { + // probably causes jank, but people can just reload their page or whatever + // not sure what to do about the URL situation + this._id = _id; + {+this.logger.debug("Update from setID");+} + this.emit("update", this); + } + +@@ -407,6 +417,7 @@ export class Channel extends EventEmitter { + } + */ + + {+this.logger.debug("Update from changeSettings");+} + this.emit("update", this); + } + +@@ -486,7 +497,7 @@ export class Channel extends EventEmitter { + p.uuids.push(socket.getUUID()) + } + + [-socket.sendChannelUpdate(this.getInfo(),-]{+//socket.sendChannelUpdate(this.getInfo(),+} this.getParticipantList()); + } else { + // Add them to the channel + hasChangedChannel = true; +@@ -534,15 +545,13 @@ export class Channel extends EventEmitter { + + if (p) { + // Give the crown back + this.giveCrown(p, [-true);-]{+true, false);+} + } + } + } + } + } + +[- // Send our state data back-] +[- // TODO Does this go above?-] + socket.sendArray([ + // { + // m: "ch", +@@ -578,7 +587,9 @@ export class Channel extends EventEmitter { + part.id + ); + + // Broadcast a channel update so everyone subscribed to the channel list can see [-us-]{+the new user count+} +{+ //this.emit("update", this, socket.getUUID());+} +{+ this.logger.debug("Update from join");+} + this.emit("update", this); + + //this.logger.debug("Settings:", this.settings); +@@ -625,6 +636,7 @@ export class Channel extends EventEmitter { + } + ]); + + {+this.logger.debug("Update from leave");+} + this.emit("update", this); + } else { + for (const p of this.ppl) { +@@ -789,6 +801,7 @@ export class Channel extends EventEmitter { + } + + ChannelList.remove(this); + {+this.deleteChatHistory();+} + this.logger.info("Destroyed"); + } + +@@ -819,7 +832,7 @@ export class Channel extends EventEmitter { + * @param part Participant to give crown to + * @param force Whether or not to force-create a crown (useful for lobbies) + */ + public giveCrown(part: Participant, force = [-false)-]{+false, update = true)+} { + if (force) { + if (!this.crown) this.crown = new Crown(); + } +@@ -828,7 +841,11 @@ export class Channel extends EventEmitter { + this.crown.userId = part._id; + this.crown.participantId = part.id; + this.crown.time = Date.now(); + + {+if (update) {+} +{+ this.logger.debug("Update from giveCrown");+} + this.emit("update", this); + {+}+} + } + } + +@@ -865,6 +882,7 @@ export class Channel extends EventEmitter { + + delete this.crown.participantId; + + {+this.logger.debug("Update from dropCrown");+} + this.emit("update", this); + } + } +@@ -951,6 +969,7 @@ export class Channel extends EventEmitter { + } + + if (shouldUpdate) { + {+this.logger.debug("Update from kickban");+} + this.emit("update", this); + + if (typeof banner !== "undefined") { +@@ -1149,7 +1168,7 @@ export class Channel extends EventEmitter { + + public printMemoryInChat() { + const mem = heapStats(); + [-this.sendChatAdmin(`Size:-]{+this.sendChatAdmin(`Used:+} ${(mem.heapSize / 1000 / 1000).toFixed(2)}M / [-Capacity:-]{+Allocated:+} ${(mem.heapCapacity / 1000 / 1000).toFixed(2)}M`); + } +} + +diff --git a/src/data/history.ts b/src/data/history.ts +index b769e27..0b68962 100755 +--- a/src/data/history.ts ++++ b/src/data/history.ts +@@ -27,3 +27,7 @@ export async function getChatHistory(_id: string) { + return []; + } +} + +{+export async function deleteChatHistory(_id: string) {+} +{+ await prisma.chatHistory.delete({ where: { id: _id } });+} +{+}+} +diff --git a/src/util/token.ts b/src/util/token.ts +index 54d22af..4e7bf6f 100644 +--- a/src/util/token.ts ++++ b/src/util/token.ts +@@ -50,7 +50,7 @@ export async function createToken(userID: string, gateway: Gateway) { + let token = ""; + + if (config.tokenAuth == "uuid") { + token = {+userID + "." ++} crypto.randomUUID(); + } else if (config.tokenAuth == "jwt") { + token = generateJWT(userID, gateway); + } +diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts +index 91067b1..964c2cb 100755 +--- a/src/ws/events/user/handlers/hi.ts ++++ b/src/ws/events/user/handlers/hi.ts +@@ -32,28 +32,30 @@ export const hi: ServerEventListener<"hi"> = { + let token: string | undefined; + let generatedToken = false; + + if {+(config.tokenAuth !== "none") {+} +{+ if+} (typeof msg.token !== "string") { + // Get a saved token + token = await getToken(socket.getUserID());[-if (typeof token !== "string") {-] +[- // Generate a new one-] +[- token = await createToken(socket.getUserID(), socket.gateway);-] + if (typeof token !== "string") { + {+// Generate a new one+} +{+ token = await createToken(socket.getUserID(), socket.gateway);+} + +{+ if (typeof token !== "string") {+} + logger.warn(`Unable to generate token for user ${socket.getUserID()}`); + } else { + generatedToken = true; + {+}+} +{+ }+} +{+ } else {+} +{+ // Validate the token+} +{+ const valid = await validateToken(socket.getUserID(), msg.token);+} +{+ if (!valid) {+} +{+ socket.ban(60000, "Invalid token");+} +{+ return;+} + } +[- }-] +[- } else {-] +[- // Validate the token-] +[- const valid = await validateToken(socket.getUserID(), msg.token);-] +[- if (!valid) {-] +[- socket.ban(60000, "Invalid token");-] +[- return;-] +[- }-] + + token = msg.token; + {+}+} + } + + let part = socket.getParticipant();