From 7526d63690f5ab64450e82e95b246ae5d0a3f1ad Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Tue, 9 May 2023 08:03:57 +1200 Subject: [PATCH] get createRoom and ensureRoom interface working --- d2m/actions/create-room.js | 53 ++++++++++++++++++++++++++++++++----- d2m/actions/send-message.js | 4 ++- d2m/event-dispatcher.js | 1 + matrix/api.js | 8 +++++- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/d2m/actions/create-room.js b/d2m/actions/create-room.js index 7e9abed..b254951 100644 --- a/d2m/actions/create-room.js +++ b/d2m/actions/create-room.js @@ -124,13 +124,15 @@ async function channelToKState(channel, guild) { } /** + * Create a bridge room, store the relationship in the database, and add it to the guild's space. * @param {import("discord-api-types/v10").APIGuildTextChannel} channel * @param guild * @param {string} spaceID * @param {any} kstate + * @returns {Promise} room ID */ async function createRoom(channel, guild, spaceID, kstate) { - const root = await api.createRoom({ + const roomID = await api.createRoom({ name: channel.name, topic: channel.topic || undefined, preset: "private_chat", @@ -139,12 +141,14 @@ async function createRoom(channel, guild, spaceID, kstate) { initial_state: kstateToState(kstate) }) - db.prepare("INSERT INTO channel_room (channel_id, room_id) VALUES (?, ?)").run(channel.id, root.room_id) + db.prepare("INSERT INTO channel_room (channel_id, room_id) VALUES (?, ?)").run(channel.id, roomID) // Put the newly created child into the space - await api.sendState(spaceID, "m.space.child", root.room_id, { + await api.sendState(spaceID, "m.space.child", roomID, { // TODO: should I deduplicate with the equivalent code from syncRoom? via: ["cadence.moe"] // TODO: use the proper server }) + + return roomID } /** @@ -158,22 +162,46 @@ function channelToGuild(channel) { return guild } +/* + Ensure flow: + 1. Get IDs + 2. Does room exist? If so great! + (it doesn't, so it needs to be created) + 3. Get kstate for channel + 4. Create room, return new ID + + New combined flow with ensure / sync: + 1. Get IDs + 2. Does room exist? + 2.5: If room does exist AND don't need to sync: return here + 3. Get kstate for channel + 4. Create room with kstate if room doesn't exist + 5. Get and update room state with kstate if room does exist +*/ + /** * @param {string} channelID + * @param {boolean} shouldActuallySync false if just need to ensure room exists (which is a quick database check), true if also want to sync room data when it does exist (slow) + * @returns {Promise} room ID */ -async function syncRoom(channelID) { +async function _syncRoom(channelID, shouldActuallySync) { /** @ts-ignore @type {import("discord-api-types/v10").APIGuildChannel} */ const channel = discord.channels.get(channelID) assert.ok(channel) const guild = channelToGuild(channel) - const {spaceID, channelKState} = await channelToKState(channel, guild) - /** @type {string?} */ const existing = db.prepare("SELECT room_id from channel_room WHERE channel_id = ?").pluck().get(channel.id) if (!existing) { + const {spaceID, channelKState} = await channelToKState(channel, guild) return createRoom(channel, guild, spaceID, channelKState) } else { + if (!shouldActuallySync) { + return existing // only need to ensure room exists, and it does. return the room ID + } + + const {spaceID, channelKState} = await channelToKState(channel, guild) + // sync channel state to room const roomKState = await roomToKState(existing) const roomDiff = diffKState(roomKState, channelKState) @@ -187,10 +215,20 @@ async function syncRoom(channelID) { } }) const spaceApply = applyKStateDiffToRoom(spaceID, spaceDiff) - return Promise.all([roomApply, spaceApply]) + await Promise.all([roomApply, spaceApply]) + + return existing } } +function ensureRoom(channelID) { + return _syncRoom(channelID, false) +} + +function syncRoom(channelID) { + return _syncRoom(channelID, true) +} + async function createAllForGuild(guildID) { const channelIDs = discord.guildChannelMap.get(guildID) assert.ok(channelIDs) @@ -200,6 +238,7 @@ async function createAllForGuild(guildID) { } module.exports.createRoom = createRoom +module.exports.ensureRoom = ensureRoom module.exports.syncRoom = syncRoom module.exports.createAllForGuild = createAllForGuild module.exports.kstateToState = kstateToState diff --git a/d2m/actions/send-message.js b/d2m/actions/send-message.js index 0a425ee..630cf48 100644 --- a/d2m/actions/send-message.js +++ b/d2m/actions/send-message.js @@ -11,13 +11,15 @@ const messageToEvent = sync.require("../converters/message-to-event") const api = sync.require("../../matrix/api") /** @type {import("./register-user")} */ const registerUser = sync.require("./register-user") +/** @type {import("../actions/create-room")} */ +const createRoom = sync.require("../actions/create-room") /** * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message */ async function sendMessage(message) { const event = messageToEvent.messageToEvent(message) - const roomID = "!VwVlIAjOjejUpDhlbA:cadence.moe" + const roomID = await createRoom.ensureRoom(message.channel_id) let senderMxid = null if (!message.webhook_id) { senderMxid = await registerUser.ensureSimJoined(message.author, roomID) diff --git a/d2m/event-dispatcher.js b/d2m/event-dispatcher.js index e4de37e..8539044 100644 --- a/d2m/event-dispatcher.js +++ b/d2m/event-dispatcher.js @@ -16,6 +16,7 @@ module.exports = { * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message */ onMessageCreate(client, message) { + if (message.guild_id !== "112760669178241024") return // TODO: activate on other servers (requires the space creation flow to be done first) sendMessage.sendMessage(message) }, diff --git a/matrix/api.js b/matrix/api.js index e3a2600..04b7cd1 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -11,7 +11,12 @@ const file = sync.require("./file") /** @type {import("./txnid")} */ const makeTxnId = sync.require("./txnid") -function path(p, mxid = null) { +/** + * @param {string} p endpoint to access + * @param {string} [mxid] optional: user to act as, for the ?user_id parameter + * @returns {string} the new endpoint + */ +function path(p, mxid) { if (!mxid) return p const u = new URL(p, "http://localhost") u.searchParams.set("user_id", mxid) @@ -65,6 +70,7 @@ function getAllState(roomID) { * @param {string} roomID * @param {string} type * @param {string} stateKey + * @param {string} [mxid] * @returns {Promise} event ID */ async function sendState(roomID, type, stateKey, content, mxid) {