sync child room avatars when guild is updated
This commit is contained in:
		
							parent
							
								
									9f717dc24f
								
							
						
					
					
						commit
						20cd7ab38e
					
				
					 2 changed files with 38 additions and 13 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue