Compare commits

...

2 commits

Author SHA1 Message Date
0237d45c60 support uk.half-shot.bridge 2023-09-07 12:08:10 +12:00
0caaa0940b allow slashes in state keys 2023-09-07 12:08:10 +12:00
5 changed files with 46 additions and 7 deletions

View file

@ -110,6 +110,23 @@ async function channelToKState(channel, guild) {
}, },
"chat.schildi.hide_ui/read_receipts": { "chat.schildi.hide_ui/read_receipts": {
hidden: true hidden: true
},
[`uk.half-shot.bridge/moe.cadence.ooye://discord/${guild.id}/${channel.id}`]: {
bridgebot: `@${reg.sender_localpart}:${reg.ooye.server_name}`,
protocol: {
id: "discord",
displayname: "Discord"
},
network: {
id: guild.id,
displayname: guild.name,
avatar_url: file.DISCORD_IMAGES_BASE + file.guildIcon(guild)
},
channel: {
id: channel.id,
displayname: channel.name,
external_url: `https://discord.com/channels/${guild.id}/${channel.id}`
}
} }
} }
@ -295,6 +312,9 @@ async function _unbridgeRoom(channelID) {
await api.sendState(roomID, "m.space.parent", spaceID, {}) await api.sendState(roomID, "m.space.parent", spaceID, {})
await api.sendState(spaceID, "m.space.child", roomID, {}) await api.sendState(spaceID, "m.space.child", roomID, {})
// remove declaration that the room is bridged
await api.sendState(roomID, "uk.half-shot.bridge", `moe.cadence.ooye://discord/${channel.guild_id}/${channel.id}`, {})
// send a notification in the room // send a notification in the room
await api.sendEvent(roomID, "m.room.message", { await api.sendEvent(roomID, "m.room.message", {
msgtype: "m.notice", msgtype: "m.notice",

View file

@ -121,7 +121,8 @@ async function sendState(roomID, type, stateKey, content, mxid) {
assert.ok(type) assert.ok(type)
assert.ok(typeof stateKey === "string") assert.ok(typeof stateKey === "string")
/** @type {Ty.R.EventSent} */ /** @type {Ty.R.EventSent} */
const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/state/${type}/${stateKey}`, mxid), content) // encodeURIComponent is necessary because state key can contain some special characters like / but you must encode them so they fit in a single component of the URI
const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/state/${type}/${encodeURIComponent(stateKey)}`, mxid), content)
return root.event_id return root.event_id
} }

View file

@ -99,6 +99,7 @@ function sticker(sticker) {
return `/stickers/${sticker.id}.${ext}` return `/stickers/${sticker.id}.${ext}`
} }
module.exports.DISCORD_IMAGES_BASE = DISCORD_IMAGES_BASE
module.exports.guildIcon = guildIcon module.exports.guildIcon = guildIcon
module.exports.userAvatar = userAvatar module.exports.userAvatar = userAvatar
module.exports.memberAvatar = memberAvatar module.exports.memberAvatar = memberAvatar

View file

@ -19,9 +19,10 @@ function kstateToState(kstate) {
const events = [] const events = []
kstateStripConditionals(kstate) kstateStripConditionals(kstate)
for (const [k, content] of Object.entries(kstate)) { for (const [k, content] of Object.entries(kstate)) {
const [type, state_key] = k.split("/") const slashIndex = k.indexOf("/")
assert.ok(typeof type === "string") assert(slashIndex > 0)
assert.ok(typeof state_key === "string") const type = k.slice(0, slashIndex)
const state_key = k.slice(slashIndex + 1)
events.push({type, state_key, content}) events.push({type, state_key, content})
} }
return events return events
@ -43,7 +44,7 @@ function diffKState(actual, target) {
const diff = {} const diff = {}
// go through each key that it should have // go through each key that it should have
for (const key of Object.keys(target)) { for (const key of Object.keys(target)) {
if (!key.includes("/")) throw new Error(`target kstate's key "${key}" does not contain a slash separator; if a blank state_key was intended, add a trailing slash to the kstate key.`) if (!key.includes("/")) throw new Error(`target kstate's key "${key}" does not contain a slash separator; if a blank state_key was intended, add a trailing slash to the kstate key.\ncontext: ${JSON.stringify(target)}`)
if (key === "m.room.power_levels/") { if (key === "m.room.power_levels/") {
// Special handling for power levels, we want to deep merge the actual and target into the final state. // Special handling for power levels, we want to deep merge the actual and target into the final state.

View file

@ -23,7 +23,8 @@ test("kstate strip: keeps true conditions while removing $if", t => {
test("kstate2state: general", t => { test("kstate2state: general", t => {
t.deepEqual(kstateToState({ t.deepEqual(kstateToState({
"m.room.name/": {name: "test name"}, "m.room.name/": {name: "test name"},
"m.room.member/@cadence:cadence.moe": {membership: "join"} "m.room.member/@cadence:cadence.moe": {membership: "join"},
"uk.half-shot.bridge/org.matrix.appservice-irc://irc/epicord.net/#general": {creator: "@cadence:cadence.moe"}
}), [ }), [
{ {
type: "m.room.name", type: "m.room.name",
@ -38,6 +39,13 @@ test("kstate2state: general", t => {
content: { content: {
membership: "join" membership: "join"
} }
},
{
type: "uk.half-shot.bridge",
state_key: "org.matrix.appservice-irc://irc/epicord.net/#general",
content: {
creator: "@cadence:cadence.moe"
}
} }
]) ])
}) })
@ -57,10 +65,18 @@ test("state2kstate: general", t => {
content: { content: {
membership: "join" membership: "join"
} }
},
{
type: "uk.half-shot.bridge",
state_key: "org.matrix.appservice-irc://irc/epicord.net/#general",
content: {
creator: "@cadence:cadence.moe"
}
} }
]), { ]), {
"m.room.name/": {name: "test name"}, "m.room.name/": {name: "test name"},
"m.room.member/@cadence:cadence.moe": {membership: "join"} "m.room.member/@cadence:cadence.moe": {membership: "join"},
"uk.half-shot.bridge/org.matrix.appservice-irc://irc/epicord.net/#general": {creator: "@cadence:cadence.moe"}
}) })
}) })