sync child room avatars when guild is updated

This commit is contained in:
Cadence Ember 2023-08-25 17:23:51 +12:00
parent 9f717dc24f
commit 20cd7ab38e
2 changed files with 38 additions and 13 deletions

View file

@ -17,6 +17,7 @@ const ks = sync.require("../../matrix/kstate")
const inflightRoomCreate = new Map() const inflightRoomCreate = new Map()
/** /**
* Async because it gets all room state from the homeserver.
* @param {string} roomID * @param {string} roomID
*/ */
async function roomToKState(roomID) { async function roomToKState(roomID) {
@ -60,6 +61,7 @@ function convertNameAndTopic(channel, guild, customName) {
} }
/** /**
* Async because it may upload the guild icon to mxc.
* @param {DiscordTypes.APIGuildTextChannel | DiscordTypes.APIThreadChannel} channel * @param {DiscordTypes.APIGuildTextChannel | DiscordTypes.APIThreadChannel} channel
* @param {DiscordTypes.APIGuild} guild * @param {DiscordTypes.APIGuild} guild
*/ */
@ -200,10 +202,10 @@ function channelToGuild(channel) {
3. Get kstate for channel 3. Get kstate for channel
4. Create room, return new ID 4. Create room, return new ID
New combined flow with ensure / sync: Ensure + sync flow:
1. Get IDs 1. Get IDs
2. Does room exist? 2. Does room exist?
2.5: If room does exist AND don't need to sync: return here 2.5: If room does exist AND wasn't asked to sync: return here
3. Get kstate for channel 3. Get kstate for channel
4. Create room with kstate if room doesn't exist 4. Create room with kstate if room doesn't exist
5. Get and update room state with kstate if room does exist 5. Get and update room state with kstate if room does exist
@ -246,7 +248,7 @@ async function _syncRoom(channelID, shouldActuallySync) {
console.log(`[room sync] to matrix: ${channel.name}`) console.log(`[room sync] to matrix: ${channel.name}`)
const {spaceID, channelKState} = await channelToKState(channel, guild) const {spaceID, channelKState} = await channelToKState(channel, guild) // calling this in both branches because we don't want to calculate this if not syncing
// sync channel state to room // sync channel state to room
const roomKState = await roomToKState(roomID) const roomKState = await roomToKState(roomID)
@ -261,6 +263,16 @@ async function _syncRoom(channelID, shouldActuallySync) {
return roomID return roomID
} }
/** Ensures the room exists. If it doesn't, creates the room with an accurate initial state. */
function ensureRoom(channelID) {
return _syncRoom(channelID, false)
}
/** Actually syncs. Gets all room state from the homeserver in order to diff, and uploads the icon to mxc if it has changed. */
function syncRoom(channelID) {
return _syncRoom(channelID, true)
}
async function _unbridgeRoom(channelID) { async function _unbridgeRoom(channelID) {
/** @ts-ignore @type {DiscordTypes.APIGuildChannel} */ /** @ts-ignore @type {DiscordTypes.APIGuildChannel} */
const channel = discord.channels.get(channelID) const channel = discord.channels.get(channelID)
@ -289,6 +301,7 @@ async function _unbridgeRoom(channelID) {
/** /**
* Async because it gets all space state from the homeserver, then if necessary sends one state event back.
* @param {DiscordTypes.APIGuildTextChannel} channel * @param {DiscordTypes.APIGuildTextChannel} channel
* @param {string} spaceID * @param {string} spaceID
* @param {string} roomID * @param {string} roomID
@ -311,14 +324,6 @@ async function _syncSpaceMember(channel, spaceID, roomID) {
return applyKStateDiffToRoom(spaceID, spaceDiff) return applyKStateDiffToRoom(spaceID, spaceDiff)
} }
function ensureRoom(channelID) {
return _syncRoom(channelID, false)
}
function syncRoom(channelID) {
return _syncRoom(channelID, true)
}
async function createAllForGuild(guildID) { async function createAllForGuild(guildID) {
const channelIDs = discord.guildChannelMap.get(guildID) const channelIDs = discord.guildChannelMap.get(guildID)
assert.ok(channelIDs) assert.ok(channelIDs)

View file

@ -1,6 +1,6 @@
// @ts-check // @ts-check
const assert = require("assert") const assert = require("assert").strict
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
@ -84,11 +84,31 @@ async function syncSpace(guildID) {
console.log(`[space sync] to matrix: ${guild.name}`) console.log(`[space sync] to matrix: ${guild.name}`)
// sync channel state to room // sync guild state to space
const spaceKState = await createRoom.roomToKState(spaceID) const spaceKState = await createRoom.roomToKState(spaceID)
const spaceDiff = ks.diffKState(spaceKState, guildKState) const spaceDiff = ks.diffKState(spaceKState, guildKState)
await createRoom.applyKStateDiffToRoom(spaceID, spaceDiff) await createRoom.applyKStateDiffToRoom(spaceID, spaceDiff)
// guild icon was changed, so room avatars need to be updated as well as the space ones
// doing it this way rather than calling syncRoom for great efficiency gains
const newAvatarState = spaceDiff["m.room.avatar/"]
if (guild.icon && newAvatarState?.url) {
// don't try to update rooms with custom avatars though
const roomsWithCustomAvatars = db.prepare("SELECT room_id FROM channel_room WHERE custom_avatar IS NOT NULL").pluck().all()
const childRooms = ks.kstateToState(spaceKState).filter(({type, state_key, content}) => {
return type === "m.space.child" && "via" in content && roomsWithCustomAvatars.includes(state_key)
}).map(({state_key}) => state_key)
for (const roomID of childRooms) {
const avatarEventContent = await api.getStateEvent(roomID, "m.room.avatar", "")
if (avatarEventContent.url !== newAvatarState.url) {
await api.sendState(roomID, "m.room.avatar", "", newAvatarState)
}
}
}
return spaceID return spaceID
} }