summary refs log tree commit diff
path: root/scripts
diff options
context:
space:
mode:
authorCadence Ember <cadence@disroot.org>2023-09-04 01:38:30 +1200
committerCadence Ember <cadence@disroot.org>2023-09-04 01:38:30 +1200
commit39458bd2bf09a79ea8e8fa8783d853ec071c2f11 (patch)
tree809b67fabc63a7edf4689b505307cad37254a44c /scripts
parentm->d fix a few markdown escaping problems (diff)
downloadout-of-your-element-39458bd2bf09a79ea8e8fa8783d853ec071c2f11.tar.xz
allow migrating from old to new bridge
Diffstat (limited to 'scripts')
-rw-r--r--scripts/capture-message-update-events.js4
-rw-r--r--scripts/migrate-from-old-bridge.js124
-rw-r--r--scripts/save-channel-names-to-db.js2
3 files changed, 127 insertions, 3 deletions
diff --git a/scripts/capture-message-update-events.js b/scripts/capture-message-update-events.js

index 2ff9b49..f345d3f 100644 --- a/scripts/capture-message-update-events.js +++ b/scripts/capture-message-update-events.js
@@ -23,9 +23,9 @@ const sync = new HeatSync({watchFS: false}) Object.assign(passthrough, {config, sync}) -const DiscordClient = require("../d2m/discord-client", false) +const DiscordClient = require("../d2m/discord-client") -const discord = new DiscordClient(config.discordToken, false) +const discord = new DiscordClient(config.discordToken, "no") passthrough.discord = discord ;(async () => { diff --git a/scripts/migrate-from-old-bridge.js b/scripts/migrate-from-old-bridge.js new file mode 100644
index 0000000..4504aea --- /dev/null +++ b/scripts/migrate-from-old-bridge.js
@@ -0,0 +1,124 @@ +// @ts-check + +const assert = require("assert").strict +/** @type {any} */ // @ts-ignore bad types from semaphore +const Semaphore = require("@chriscdn/promise-semaphore") +const sqlite = require("better-sqlite3") +const HeatSync = require("heatsync") + +const config = require("../config") +const passthrough = require("../passthrough") + +const sync = new HeatSync({watchFS: false}) + +/** @type {import("../matrix/read-registration")} */ +const reg = sync.require("../matrix/read-registration") +assert(reg.old_bridge) +const oldAT = reg.old_bridge.as_token +const newAT = reg.as_token + +const oldDB = new sqlite(reg.old_bridge.database) +const db = new sqlite("db/ooye.db") + +db.exec(`CREATE TABLE IF NOT EXISTS migration ( + discord_channel TEXT NOT NULL, + migrated INTEGER NOT NULL, + PRIMARY KEY("discord_channel") +) WITHOUT ROWID;`) + +Object.assign(passthrough, {config, sync, db}) + +const DiscordClient = require("../d2m/discord-client") +const discord = new DiscordClient(config.discordToken, "half") +passthrough.discord = discord + +/** @type {import("../d2m/actions/create-space")} */ +const createSpace = sync.require("../d2m/actions/create-space") +/** @type {import("../d2m/actions/create-room")} */ +const createRoom = sync.require("../d2m/actions/create-room") +/** @type {import("../matrix/mreq")} */ +const mreq = sync.require("../matrix/mreq") +/** @type {import("../matrix/api")} */ +const api = sync.require("../matrix/api") + +const sema = new Semaphore() + +;(async () => { + await discord.cloud.connect() + console.log("Discord gateway started") + + discord.cloud.on("event", event => onPacket(discord, event)) +})() + +/** @param {DiscordClient} discord */ +function onPacket(discord, event) { + if (event.t === "GUILD_CREATE") { + const guild = event.d + if (["1100319549670301727", "112760669178241024", "497159726455455754"].includes(guild.id)) return + sema.request(() => migrateGuild(guild)) + } +} + +const newBridgeMxid = `@${reg.sender_localpart}:${reg.ooye.server_name}` + +/** @param {import("discord-api-types/v10").GatewayGuildCreateDispatchData} guild */ +async function migrateGuild(guild) { + console.log(`START MIGRATION of ${guild.name} (${guild.id})`) + + // Step 1: Create a new space for the guild (createSpace) + const spaceID = await createSpace.syncSpace(guild.id) + + let oldRooms = oldDB.prepare("SELECT matrix_id, discord_guild, discord_channel FROM room_entries INNER JOIN remote_room_data ON remote_id = room_id WHERE discord_guild = ?").all(guild.id) + const migrated = db.prepare("SELECT discord_channel FROM migration WHERE migrated = 1").pluck().all() + oldRooms = oldRooms.filter(row => discord.channels.has(row.discord_channel) && !migrated.includes(row.discord_channel)) + console.log("Found these rooms which can be migrated:") + console.log(oldRooms) + + for (const row of oldRooms) { + const roomID = row.matrix_id + const channel = discord.channels.get(row.discord_channel) + assert(channel) + + // Step 2: (Using old bridge access token) Join the new bridge to the old rooms and give it PL 100 + console.log(`-- Joining channel ${channel.name}...`) + await mreq.withAccessToken(oldAT, async () => { + try { + await api.inviteToRoom(roomID, newBridgeMxid) + } catch (e) { + if (e.message.includes("is already in the room")) { + // Great! + } else { + throw e + } + } + await api.setUserPower(roomID, newBridgeMxid, 100) + }) + await api.joinRoom(roomID) + + // Step 3: Remove the old bridge's aliases + console.log(`-- -- Deleting aliases...`) + await mreq.withAccessToken(oldAT, async () => { // have to run as old application service since the AS owns its aliases + const aliases = (await mreq.mreq("GET", `/client/v3/rooms/${roomID}/aliases`)).aliases + for (const alias of aliases) { + if (alias.match(/^#?_?discord/)) { + await mreq.mreq("DELETE", `/client/v3/directory/room/${alias.replace(/#/g, "%23")}`) + } + } + await api.sendState(roomID, "m.room.canonical_alias", "", {}) + }) + + // Step 4: Add old rooms to new database; they are now also the new rooms + db.prepare("REPLACE INTO channel_room (channel_id, room_id, name) VALUES (?, ?, ?)").run(channel.id, row.matrix_id, channel.name) + console.log(`-- -- Added to database`) + + // Step 5: Call syncRoom for each room + await createRoom.syncRoom(row.discord_channel) + console.log(`-- -- Finished syncing`) + + db.prepare("INSERT INTO migration (discord_channel, migrated) VALUES (?, 1)").run(channel.id) + } + + // Step 5: Call syncSpace to make sure everything is up to date + await createSpace.syncSpace(guild.id) + console.log(`Finished migrating ${guild.name} to Out Of Your Element`) +} diff --git a/scripts/save-channel-names-to-db.js b/scripts/save-channel-names-to-db.js
index 6f5867a..1e5c541 100644 --- a/scripts/save-channel-names-to-db.js +++ b/scripts/save-channel-names-to-db.js
@@ -13,7 +13,7 @@ Object.assign(passthrough, {config, sync, db}) const DiscordClient = require("../d2m/discord-client") -const discord = new DiscordClient(config.discordToken, false) +const discord = new DiscordClient(config.discordToken, "no") passthrough.discord = discord ;(async () => {