From 5b06d5984ac91d830f161fbbcf72b6ba5ff9d11e Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 20 Jan 2025 02:33:24 +1300 Subject: [PATCH] Do cache space members in member_cache --- scripts/setup.js | 4 ++-- src/d2m/actions/register-pk-user.js | 2 +- src/d2m/actions/register-user.js | 2 +- src/d2m/converters/user-to-mxid.js | 2 +- src/db/migrations/0016-foreign-keys.sql | 23 +++------------------ src/m2d/converters/event-to-message.js | 19 ++++++++++------- src/m2d/converters/event-to-message.test.js | 14 ++++++------- src/m2d/event-dispatcher.js | 4 ++-- test/ooye-test-data.sql | 22 ++++++++++---------- 9 files changed, 40 insertions(+), 52 deletions(-) diff --git a/scripts/setup.js b/scripts/setup.js index 3491106..6ee8c19 100644 --- a/scripts/setup.js +++ b/scripts/setup.js @@ -319,8 +319,8 @@ function defineEchoHandler() { await migrate.migrate(db) // add initial rows to database, like adding the bot to sim... - const botID = Buffer.from(reg.ooye.discord_token.split(".")[0], "base64").toString() - db.prepare("INSERT OR IGNORE INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(botID, reg.sender_localpart.slice(reg.ooye.namespace_prefix.length), reg.sender_localpart, mxid) + const client = await discord.snow.user.getSelf() + db.prepare("INSERT INTO sim (user_id, username, sim_name, mxid) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING").run(client.id, client.username, reg.sender_localpart.slice(reg.ooye.namespace_prefix.length), mxid) console.log("✅ Database is ready...") diff --git a/src/d2m/actions/register-pk-user.js b/src/d2m/actions/register-pk-user.js index 411fcf8..7083006 100644 --- a/src/d2m/actions/register-pk-user.js +++ b/src/d2m/actions/register-pk-user.js @@ -33,7 +33,7 @@ async function createSim(pkMessage) { const mxid = `@${localpart}:${reg.ooye.server_name}` // Save chosen name in the database forever - db.prepare("INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(pkMessage.member.uuid, simName, localpart, mxid) + db.prepare("INSERT INTO sim (user_id, username, sim_name, mxid) VALUES (?, ?, ?, ?)").run(pkMessage.member.uuid, simName, simName, mxid) // Register matrix user with that name try { diff --git a/src/d2m/actions/register-user.js b/src/d2m/actions/register-user.js index b914d41..c3bd16c 100644 --- a/src/d2m/actions/register-user.js +++ b/src/d2m/actions/register-user.js @@ -33,7 +33,7 @@ async function createSim(user) { // Save chosen name in the database forever // Making this database change right away so that in a concurrent registration, the 2nd registration will already have generated a different localpart because it can see this row when it generates - db.prepare("INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(user.id, simName, localpart, mxid) + db.prepare("INSERT INTO sim (user_id, username, sim_name, mxid) VALUES (?, ?, ?, ?)").run(user.id, user.username, simName, mxid) // Register matrix user with that name try { diff --git a/src/d2m/converters/user-to-mxid.js b/src/d2m/converters/user-to-mxid.js index a619b36..e0ab137 100644 --- a/src/d2m/converters/user-to-mxid.js +++ b/src/d2m/converters/user-to-mxid.js @@ -64,7 +64,7 @@ function userToSimName(user) { } // 1. Is sim user already registered? - const existing = select("sim", "sim_name", {user_id: user.id}).pluck().get() + const existing = select("sim", "user_id", {user_id: user.id}).pluck().get() assert.equal(existing, null, "Shouldn't try to create a new name for an existing sim") // 2. Register based on username (could be new or old format) diff --git a/src/db/migrations/0016-foreign-keys.sql b/src/db/migrations/0016-foreign-keys.sql index c41f329..7a2b26c 100644 --- a/src/db/migrations/0016-foreign-keys.sql +++ b/src/db/migrations/0016-foreign-keys.sql @@ -86,24 +86,6 @@ DROP TABLE guild_space; -- 7 ALTER TABLE new_guild_space RENAME TO guild_space; --- *** member_cache *** - --- 4 -CREATE TABLE "new_member_cache" ( - "room_id" TEXT NOT NULL, - "mxid" TEXT NOT NULL, - "displayname" TEXT, - "avatar_url" TEXT, power_level INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY("room_id","mxid"), - FOREIGN KEY("room_id") REFERENCES "channel_room"("room_id") ON DELETE CASCADE -) WITHOUT ROWID; --- 5 -INSERT INTO new_member_cache (room_id, mxid, displayname, avatar_url) SELECT room_id, mxid, displayname, avatar_url FROM member_cache WHERE room_id IN (SELECT room_id FROM channel_room); --- 6 -DROP TABLE member_cache; --- 7 -ALTER TABLE new_member_cache RENAME TO member_cache; - -- *** reaction *** -- 4 @@ -142,15 +124,16 @@ ALTER TABLE new_webhook RENAME TO webhook; -- *** sim *** -- 4 --- while we're at it, rebuild this table to give it WITHOUT ROWID, remove UNIQUE, and drop the localpart column. no foreign keys needed +-- while we're at it, rebuild this table to give it WITHOUT ROWID, remove UNIQUE, and replace the localpart column with username. no foreign keys needed CREATE TABLE "new_sim" ( "user_id" TEXT NOT NULL, + "username" TEXT NOT NULL, "sim_name" TEXT NOT NULL, "mxid" TEXT NOT NULL, PRIMARY KEY("user_id") ) WITHOUT ROWID; -- 5 -INSERT INTO new_sim (user_id, sim_name, mxid) SELECT user_id, sim_name, mxid FROM sim; +INSERT INTO new_sim (user_id, username, sim_name, mxid) SELECT user_id, sim_name, sim_name, mxid FROM sim; -- 6 DROP TABLE sim; -- 7 diff --git a/src/m2d/converters/event-to-message.js b/src/m2d/converters/event-to-message.js index c498f1e..9a17817 100644 --- a/src/m2d/converters/event-to-message.js +++ b/src/m2d/converters/event-to-message.js @@ -258,13 +258,18 @@ async function getMemberFromCacheOrHomeserver(roomID, mxid, api) { const row = select("member_cache", ["displayname", "avatar_url"], {room_id: roomID, mxid}).get() if (row) return row return api.getStateEvent(roomID, "m.room.member", mxid).then(event => { - const displayname = event?.displayname || null - const avatar_url = event?.avatar_url || null - db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?").run( - roomID, mxid, - displayname, avatar_url, - displayname, avatar_url - ) + const room = select("channel_room", "room_id", {room_id: roomID}).get() + if (room) { + // save the member to the cache so we don't have to check with the homeserver next time + // the cache will be kept in sync by the `m.room.member` event listener + const displayname = event?.displayname || null + const avatar_url = event?.avatar_url || null + db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?").run( + roomID, mxid, + displayname, avatar_url, + displayname, avatar_url + ) + } return event }).catch(() => { return {displayname: null, avatar_url: null} diff --git a/src/m2d/converters/event-to-message.test.js b/src/m2d/converters/event-to-message.test.js index 0dc9110..cc3d19a 100644 --- a/src/m2d/converters/event-to-message.test.js +++ b/src/m2d/converters/event-to-message.test.js @@ -3535,8 +3535,8 @@ test("event2message: does not cache the member if the room is not known", async }, event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", origin_server_ts: 1688301929913, - room_id: "!should_be_newly_cached:cadence.moe", - sender: "@should_be_newly_cached:cadence.moe", + room_id: "!not_real:cadence.moe", + sender: "@should_not_be_cached:cadence.moe", type: "m.room.message", unsigned: { age: 405299 @@ -3545,9 +3545,9 @@ test("event2message: does not cache the member if the room is not known", async api: { getStateEvent: async (roomID, type, stateKey) => { called++ - t.equal(roomID, "!should_be_newly_cached:cadence.moe") + t.equal(roomID, "!not_real:cadence.moe") t.equal(type, "m.room.member") - t.equal(stateKey, "@should_be_newly_cached:cadence.moe") + t.equal(stateKey, "@should_not_be_cached:cadence.moe") return { avatar_url: "mxc://cadence.moe/this_is_the_avatar" } @@ -3559,9 +3559,9 @@ test("event2message: does not cache the member if the room is not known", async messagesToDelete: [], messagesToEdit: [], messagesToSend: [{ - username: "should_be_newly_cached", + username: "should_not_be_cached", content: "testing the member state cache", - avatar_url: undefined, + avatar_url: "https://bridge.example.org/download/matrix/cadence.moe/this_is_the_avatar", allowed_mentions: { parse: ["users", "roles"] } @@ -3569,7 +3569,7 @@ test("event2message: does not cache the member if the room is not known", async } ) - t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached:cadence.moe"}).all(), []) + t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!not_real:cadence.moe"}).all(), []) t.equal(called, 1, "getStateEvent should be called once") }) diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js index 6cbd6c6..fc2a558 100644 --- a/src/m2d/event-dispatcher.js +++ b/src/m2d/event-dispatcher.js @@ -205,8 +205,8 @@ async event => { return db.prepare("DELETE FROM member_cache WHERE room_id = ? and mxid = ?").run(event.room_id, event.state_key) } - const room = select("channel_room", "room_id", {room_id: event.room_id}) - if (!room) return // don't cache members in unbridged rooms + const exists = select("channel_room", "room_id", {room_id: event.room_id}) ?? select("guild_space", "space_id", {space_id: event.room_id}) + if (!exists) return // don't cache members in unbridged rooms // Member is here let powerLevel = 0 diff --git a/test/ooye-test-data.sql b/test/ooye-test-data.sql index 757ef9b..4a7d2f4 100644 --- a/test/ooye-test-data.sql +++ b/test/ooye-test-data.sql @@ -19,17 +19,17 @@ INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom ('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL), ('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL); -INSERT INTO sim (user_id, sim_name, mxid) VALUES -('0', 'bot', '@_ooye_bot:cadence.moe'), -('820865262526005258', 'crunch_god', '@_ooye_crunch_god:cadence.moe'), -('771520384671416320', 'bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'), -('112890272819507200', '.wing.', '@_ooye_.wing.:cadence.moe'), -('114147806469554185', 'extremity', '@_ooye_extremity:cadence.moe'), -('111604486476181504', 'kyuugryphon', '@_ooye_kyuugryphon:cadence.moe'), -('1109360903096369153', 'amanda', '@_ooye_amanda:cadence.moe'), -('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '@_ooye__pk_zoego:cadence.moe'), -('320067006521147393', 'papiophidian', '@_ooye_papiophidian:cadence.moe'), -('772659086046658620', 'cadence', '@_ooye_cadence:cadence.moe'); +INSERT INTO sim (user_id, username, sim_name, mxid) VALUES +('0', 'Matrix Bridge', 'bot', '@_ooye_bot:cadence.moe'), +('820865262526005258', 'Crunch God', 'crunch_god', '@_ooye_crunch_god:cadence.moe'), +('771520384671416320', 'Bojack Horseman', 'bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'), +('112890272819507200', 'wing', '.wing.', '@_ooye_.wing.:cadence.moe'), +('114147806469554185', 'extremity', 'extremity', '@_ooye_extremity:cadence.moe'), +('111604486476181504', 'kyuugryphon', 'kyuugryphon', '@_ooye_kyuugryphon:cadence.moe'), +('1109360903096369153', 'Amanda', 'amanda', '@_ooye_amanda:cadence.moe'), +('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '_pk_zoego', '@_ooye__pk_zoego:cadence.moe'), +('320067006521147393', 'papiophidian', 'papiophidian', '@_ooye_papiophidian:cadence.moe'), +('772659086046658620', 'cadence.worm', 'cadence', '@_ooye_cadence:cadence.moe'); INSERT INTO sim_member (mxid, room_id, hashed_profile_content) VALUES ('@_ooye_bojack_horseman:cadence.moe', '!hYnGGlPHlbujVVfktC:cadence.moe', NULL),