From ea18f74503652cffe59ea5db0de6bae6fb19a937 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Wed, 2 Feb 2022 23:48:18 +0200 Subject: [PATCH] add endpoint to poll all guilds the user has access to --- DiscordClient.js | 10 ++++++++- WatchedGuild.js | 2 +- frontend/src/api/APIClient.js | 2 +- frontend/src/components/App.svelte | 35 ++++++++++++++++++++---------- routes/api.js | 24 ++++++++++++++++++++ 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/DiscordClient.js b/DiscordClient.js index d9a16b3..70de801 100644 --- a/DiscordClient.js +++ b/DiscordClient.js @@ -210,7 +210,15 @@ class DiscordClient extends EventEmitter { reason = reason.toString(); this.emit("close", code, reason); console.error(`DiscordClient: on \`close\`: disconnected from gateway: code \`${code}\`, reason \`${reason}\``); - }) + }); + + ws.on("error", (e) => { + console.error("DiscordClient: websocket error:", e); + console.log("DiscordClient: reconnecting in a couple of miliseconds"); + setTimeout(() => { + this.connect(); + }, 400); + }); } async api([method, path], body=undefined, throwOnError=true) { diff --git a/WatchedGuild.js b/WatchedGuild.js index 2a7fc4f..505acc0 100644 --- a/WatchedGuild.js +++ b/WatchedGuild.js @@ -60,7 +60,7 @@ class WatchedGuild extends EventEmitter { return; const maybeKnownWebhook = this.knownWebhooks.get(message.channel_id); - if (maybeKnownWebhook.id === message.webhook_id) + if (maybeKnownWebhook && maybeKnownWebhook.id === message.webhook_id) return; // ignore messages coming from our webhook this.pushEvent({ diff --git a/frontend/src/api/APIClient.js b/frontend/src/api/APIClient.js index 337ee63..f02e6e2 100644 --- a/frontend/src/api/APIClient.js +++ b/frontend/src/api/APIClient.js @@ -36,7 +36,7 @@ class APIClient { let shouldContinue = true; const poll = async () => { - this.getRequest(`/guilds/${guildId}/events/poll`) + this.getRequest(guildId ? `/guilds/${guildId}/events/poll` : "/events/poll") .then((result) => { if (result.event) { callback(result); diff --git a/frontend/src/components/App.svelte b/frontend/src/components/App.svelte index b293cab..b265a29 100644 --- a/frontend/src/components/App.svelte +++ b/frontend/src/components/App.svelte @@ -30,18 +30,24 @@ selectedChannel = guilds[0].channels[0]; } - const { poll } = apiClient.createPollingListener(selectedGuild.id, ({ event }) => { + const { poll } = apiClient.createPollingListener(null, ({ event }) => { if (event.eventType === "MESSAGE_CREATE") { - if (!messageStore[selectedGuild.id]) { - messageStore[selectedGuild.id] = []; + const guildId = event.message.guild_id; + const channelId = event.message.channel_id; + + if (!messageStore[guildId]) { + messageStore[guildId] = {}; } - messageStore[selectedGuild.id] = [...messageStore[selectedGuild.id], event.message]; + if (!messageStore[guildId][channelId]) { + messageStore[guildId][channelId] = []; + } + messageStore[guildId][channelId] = [...messageStore[guildId][channelId], event.message]; } }); poll(); }); - $: selectedGuildMessages = selectedGuild ? (messageStore[selectedGuild.id] || []) : []; + $: selectedChannelMessages = selectedGuild ? ((messageStore[selectedGuild.id] || [])[selectedChannel.id] || []) : []; function onTextEntryMessage(event) { if (!selectedGuild || !selectedChannel) { @@ -49,8 +55,15 @@ } const nonce = Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER - 10)); - messageStore[selectedGuild.id] = [ - ...messageStore[selectedGuild.id] || [], + if (!messageStore[selectedGuild.id]) + messageStore[selectedGuild.id] = {}; + + // this looks horrible, however directly accessing the values without + // using a variable for readability is the only way i can get + // reactivity to work + // :( + messageStore[selectedGuild.id][selectedChannel.id] = [ + ...messageStore[selectedGuild.id][selectedChannel.id] || [], { channel_id: selectedChannel.id, content: event.detail, @@ -62,14 +75,14 @@ } ]; // we could just get the length and subtract 1 but that might introduce some race conditions - const thisMessageIndex = messageStore[selectedGuild.id].findIndex(e => e._nonce === nonce); + const thisMessageIndex = messageStore[selectedGuild.id][selectedChannel.id].findIndex(e => e._nonce === nonce); apiClient.postRequest(`/guilds/${selectedGuild.id}/channels/${selectedChannel.id}/messages/create`, { content: event.detail }).then(() => { - messageStore[selectedGuild.id][thisMessageIndex]._pendingStatus = "success"; + messageStore[selectedGuild.id][selectedChannel.id][thisMessageIndex]._pendingStatus = "success"; }).catch(() => { - messageStore[selectedGuild.id][thisMessageIndex]._pendingStatus = "error"; + messageStore[selectedGuild.id][selectedChannel.id][thisMessageIndex]._pendingStatus = "error"; }); } @@ -100,7 +113,7 @@
- +
diff --git a/routes/api.js b/routes/api.js index aa5a493..cbdca10 100644 --- a/routes/api.js +++ b/routes/api.js @@ -127,4 +127,28 @@ router.get("/guilds/:guildId/events/poll", checkAuth(async (req, res) => { } })); +router.get("/events/poll", checkAuth(async (req, res) => { + const { guildAccess } = req.user; + + try { + // note: probably not very optimal + const promises = []; + guildAccess.forEach((guildId) => { + const guild = guildMap.get(guildId); + if (guild) { + promises.push(guild.holdForEvent(15000)); + } + }); + + // note: if 2 guild events happen at the same time, one of them may be dropped + Promise.race(promises) + .then(e => { + res.status(200).send({ error: false, event: e }) + }); + } catch(e) { + console.error("server main: api: guild poll events: error: ", e); + res.status(500).send({ error: true, message: "ERROR_POLL_FAILURE" }); + } +})); + export default router;