bridgecord/WatchedGuild.js
hippoz e33f6f7cfd
Add GatewayServer and GatewayClient(frontend)
This commit adds a websocket server that clients
can connect and authenticate to. Once they're
authenticated, they will start to receive
relevant events. One issue is that the server
does not ping for dead connections yet
and the fact that new listeners for the guild
are added for each connection. There is also
the bug in WatchedGuild that prevents other
bridge users from seeing eachother's
messages.
2022-02-06 03:48:28 +02:00

104 lines
3.4 KiB
JavaScript

import { EventEmitter } from "events";
import { wait } from "./common.js";
class WatchedGuild extends EventEmitter {
constructor() {
super();
this.knownWebhooks = new Map();
this.upstreamGuildId = null;
}
pushEvent(e) {
this.emit("pushed", e);
}
holdForEvent(timeout) {
return new Promise((outerResolve, outerReject) => {
let handler;
Promise.race([
new Promise((resolve, reject) => {
// potential memory leak here when too many promises are created and waiting
handler = (event) => {
resolve(event);
};
this.once("pushed", handler);
}),
wait(timeout, true)
]).then((result) => {
if (handler)
this.removeListener("pushed", handler);
outerResolve(result);
}).catch(() => {
if (handler)
this.removeListener("pushed", handler);
outerResolve(null);
});
});
}
discordConnect(bot) {
this.bot = bot;
this.guildObject = this.bot.guilds.find(e => e.id === this.upstreamGuildId);
if (!this.guildObject) {
throw new Error("Could not find guild object from bot cache by id (is the upstreamGuildId valid and does the bot have access to it?)");
}
this.bot.on("GUILD_CREATE", (guild) => {
if (guild.id === this.upstreamGuildId)
this.guildObject = guild;
});
this.bot.on("GUILD_UPDATE", (guild) => {
if (guild.id === this.upstreamGuildId)
this.guildObject = guild;
});
this.bot.on("MESSAGE_CREATE", (message) => {
if (message.guild_id !== this.upstreamGuildId)
return;
// TODOOOOOO: bridge user's wont get message events from other bridge users in the same channel
const maybeKnownWebhook = this.knownWebhooks.get(message.channel_id);
if (maybeKnownWebhook && maybeKnownWebhook.id === message.webhook_id)
return; // ignore messages coming from our webhook
this.pushEvent({
eventType: "MESSAGE_CREATE",
message: message
});
});
}
userFacingChannelList() {
return this.guildObject.channels.map(channel => ({ id: channel.id, name: channel.name, position: channel.position, type: channel.type, nsfw: channel.nsfw }));
}
async discordSendMessage(content, channelId, username, avatarURL=undefined) {
let webhook = this.knownWebhooks.get(channelId);
if (!webhook) {
webhook = (await this.bot.api(["GET", `/channels/${channelId}/webhooks`]))
.find(e => e.name === "well_known__bridge");
if (!webhook)
webhook = await this.bot.api(["POST", `/channels/${channelId}/webhooks`], {
name: "well_known__bridge"
});
this.knownWebhooks.set(channelId, webhook);
}
await this.bot.api(["POST", `/webhooks/${webhook.id}/${webhook.token}?wait=true`], {
content,
username,
avatar_url: avatarURL,
tts: false,
allowed_mentions: {
parse: ["users"]
}
});
}
}
export default WatchedGuild;