From 3578ca28b5e43fd8aeddf1086cd4f49bc8cecb7e Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 3 Jul 2023 17:20:24 +1200 Subject: [PATCH] glue --- ...register-webhook.js => channel-webhook.js} | 13 ++++++ m2d/actions/send-event.js | 43 +++++++++++++++++++ m2d/actions/send-message.js | 23 ---------- m2d/event-dispatcher.js | 31 +++++++++++-- types.d.ts | 12 +++++- 5 files changed, 94 insertions(+), 28 deletions(-) rename m2d/actions/{register-webhook.js => channel-webhook.js} (77%) create mode 100644 m2d/actions/send-event.js delete mode 100644 m2d/actions/send-message.js diff --git a/m2d/actions/register-webhook.js b/m2d/actions/channel-webhook.js similarity index 77% rename from m2d/actions/register-webhook.js rename to m2d/actions/channel-webhook.js index 511029b..5e56859 100644 --- a/m2d/actions/register-webhook.js +++ b/m2d/actions/channel-webhook.js @@ -1,6 +1,7 @@ // @ts-check const assert = require("assert").strict +const DiscordTypes = require("discord-api-types/v10") const passthrough = require("../../passthrough") const {discord, db} = passthrough @@ -46,5 +47,17 @@ async function withWebhook(channelID, callback) { }) } +/** + * @param {string} channelID + * @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]}[]} data + */ +async function sendMessageWithWebhook(channelID, data) { + const result = await withWebhook(channelID, async webhook => { + return discord.snow.webhook.executeWebhook(webhook.id, webhook.token, data, {wait: true, disableEveryone: true}) + }) + return result +} + module.exports.ensureWebhook = ensureWebhook module.exports.withWebhook = withWebhook +module.exports.sendMessageWithWebhook = sendMessageWithWebhook diff --git a/m2d/actions/send-event.js b/m2d/actions/send-event.js new file mode 100644 index 0000000..5eb8c04 --- /dev/null +++ b/m2d/actions/send-event.js @@ -0,0 +1,43 @@ +// @ts-check + +const assert = require("assert").strict +const DiscordTypes = require("discord-api-types/v10") +const passthrough = require("../../passthrough") +const {sync, discord, db} = passthrough + +/** @type {import("./channel-webhook")} */ +const channelWebhook = sync.require("./channel-webhook") +/** @type {import("../converters/event-to-message")} */ +const eventToMessage = sync.require("../converters/event-to-message") + +/** @param {import("../../types").Event.Outer} event */ +async function sendEvent(event) { + // TODO: matrix equivalents... + const roomID = await createRoom.ensureRoom(message.channel_id) + // TODO: no need to sync the member to the other side... right? + let senderMxid = null + if (!message.webhook_id) { + assert(message.member) + senderMxid = await registerUser.ensureSimJoined(message.author, roomID) + await registerUser.syncUser(message.author, message.member, message.guild_id, roomID) + } + + const messages = eventToMessage.eventToMessage(event) + assert(Array.isArray(messages)) + + /** @type {DiscordTypes.APIMessage[]} */ + const messageResponses = [] + let eventPart = 0 // 0 is primary, 1 is supporting + for (const message of messages) { + const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message) + // TODO: are you sure about that? many to many? and we don't need to store which side it originated from? + db.prepare("INSERT INTO event_message (event_id, message_id, part) VALUES (?, ?, ?)").run(event.event_id, messageResponse.id, eventPart) + + eventPart = 1 // TODO: use more intelligent algorithm to determine whether primary or supporting + messageResponses.push(messageResponse) + } + + return messageResponses +} + +module.exports.sendEvent = sendEvent diff --git a/m2d/actions/send-message.js b/m2d/actions/send-message.js deleted file mode 100644 index 3505b60..0000000 --- a/m2d/actions/send-message.js +++ /dev/null @@ -1,23 +0,0 @@ -// @ts-check - -const assert = require("assert").strict -const DiscordTypes = require("discord-api-types/v10") -const passthrough = require("../../passthrough") -const {sync, discord, db} = passthrough - -/** @type {import("./register-webhook")} */ -const registerWebhook = sync.require("./register-webhook") - -/** - * @param {string} channelID - * @param {DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]}[]} data - */ -// param {DiscordTypes.RESTPostAPIWebhookWithTokenQuery & {wait: true, disableEveryone?: boolean}} options -async function sendMessage(channelID, data) { - const result = await registerWebhook.withWebhook(channelID, async webhook => { - return discord.snow.webhook.executeWebhook(webhook.id, webhook.token, data, {wait: true, disableEveryone: true}) - }) - return result -} - -module.exports.sendMessage = sendMessage diff --git a/m2d/event-dispatcher.js b/m2d/event-dispatcher.js index 789d9ed..b8bfacf 100644 --- a/m2d/event-dispatcher.js +++ b/m2d/event-dispatcher.js @@ -1,12 +1,37 @@ // @ts-check +/** + * Grab Matrix events we care about, check them, and bridge them. + */ + const assert = require("assert").strict const {sync, as} = require("../passthrough") +const reg = require("../matrix/read-registration") +/** @type {import("./actions/send-event")} */ +const sendEvent = sync.require("./actions/send-event") -// Grab Matrix events we care about for the bridge, check them, and pass them on +const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex)) +/** + * Determine whether an event is the bridged representation of a discord message. + * Such messages shouldn't be bridged again. + * @param {import("../types").Event.Outer} event + */ +function eventOriginatedFromDiscord(event) { + if ( + // If it's from a user in the bridge's namespace... + userRegex.some(x => event.sender.match(x)) + // ...not counting the appservice's own user... + && !event.sender.startsWith(`@${reg.sender_localpart}:`) + ) { + // ...then it originated from discord + return true + } + + return false +} sync.addTemporaryListener(as, "type:m.room.message", event => { console.log(event) - // TODO: filter out events that were bridged discord messages (i.e. sent by OOYE) - // TODO: call sendMessage + if (eventOriginatedFromDiscord(event)) return + const messageResponses = sendEvent.sendEvent(event) }) diff --git a/types.d.ts b/types.d.ts index 2181793..19ef1f2 100644 --- a/types.d.ts +++ b/types.d.ts @@ -5,6 +5,16 @@ export type AppServiceRegistrationConfig = { url: string sender_localpart: string namespace_prefix: string + namespaces: { + users: { + exclusive: boolean + regex: string + }[] + aliases: { + exclusive: boolean + regex: string + }[] + } protocols: [string] rate_limited: boolean } @@ -23,8 +33,6 @@ namespace Event { origin_server_ts: number unsigned: any event_id: string - user_id: string - age: number } export type BaseStateEvent = {