space and room creation
This commit is contained in:
		
							parent
							
								
									51480e21e5
								
							
						
					
					
						commit
						c7868e9dbb
					
				
					 15 changed files with 328 additions and 36 deletions
				
			
		| 
						 | 
					@ -1,22 +1,99 @@
 | 
				
			||||||
// @ts-check
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const reg = require("../../matrix/read-registration.js")
 | 
					const assert = require("assert").strict
 | 
				
			||||||
const fetch = require("node-fetch")
 | 
					const DiscordTypes = require("discord-api-types/v10")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fetch("https://matrix.cadence.moe/_matrix/client/v3/createRoom?user_id=@_ooye_example:cadence.moe", {
 | 
					const passthrough = require("../../passthrough")
 | 
				
			||||||
	method: "POST",
 | 
					const { discord, sync, db } = passthrough
 | 
				
			||||||
	body: JSON.stringify({
 | 
					/** @type {import("../../matrix/mreq")} */
 | 
				
			||||||
		invite: ["@cadence:cadence.moe"],
 | 
					const mreq = sync.require("../../matrix/mreq")
 | 
				
			||||||
		is_direct: false,
 | 
					/** @type {import("../../matrix/file")} */
 | 
				
			||||||
		name: "New Bot User Room",
 | 
					const file = sync.require("../../matrix/file")
 | 
				
			||||||
		preset: "trusted_private_chat"
 | 
					
 | 
				
			||||||
	}),
 | 
					/**
 | 
				
			||||||
	headers: {
 | 
					 * @param {import("discord-api-types/v10").APIGuildTextChannel} channel
 | 
				
			||||||
		Authorization: `Bearer ${reg.as_token}`
 | 
					 */
 | 
				
			||||||
 | 
					async function createRoom(channel) {
 | 
				
			||||||
 | 
						const guildID = channel.guild_id
 | 
				
			||||||
 | 
						assert.ok(guildID)
 | 
				
			||||||
 | 
						const guild = discord.guilds.get(guildID)
 | 
				
			||||||
 | 
						assert.ok(guild)
 | 
				
			||||||
 | 
						const spaceID = db.prepare("SELECT space_id FROM guild_space WHERE guild_id = ?").pluck().get(guildID)
 | 
				
			||||||
 | 
						assert.ok(typeof spaceID === "string")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const avatarEventContent = {}
 | 
				
			||||||
 | 
						if (guild.icon) {
 | 
				
			||||||
 | 
							avatarEventContent.url = await file.uploadDiscordFileToMxc(file.guildIcon(guild))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}).then(res => res.text()).then(text => {
 | 
					
 | 
				
			||||||
	// {"room_id":"!aAVaqeAKwChjWbsywj:cadence.moe"}
 | 
						/** @type {import("../../types").R_RoomCreated} */
 | 
				
			||||||
	console.log(text)
 | 
						const root = await mreq.mreq("POST", "/client/v3/createRoom", {
 | 
				
			||||||
}).catch(err => {
 | 
							name: channel.name,
 | 
				
			||||||
	console.log(err)
 | 
							topic: channel.topic || undefined,
 | 
				
			||||||
 | 
							preset: "private_chat",
 | 
				
			||||||
 | 
							visibility: "private",
 | 
				
			||||||
 | 
							invite: ["@cadence:cadence.moe"], // TODO
 | 
				
			||||||
 | 
							initial_state: [
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.avatar",
 | 
				
			||||||
 | 
									state_key: "",
 | 
				
			||||||
 | 
									content: avatarEventContent
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.guest_access",
 | 
				
			||||||
 | 
									state_key: "",
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										guest_access: "can_join"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.history_visibility",
 | 
				
			||||||
 | 
									state_key: "",
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										history_visibility: "invited"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.space.parent",
 | 
				
			||||||
 | 
									state_key: spaceID,
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										via: ["cadence.moe"], // TODO: put the proper server here
 | 
				
			||||||
 | 
										canonical: true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.join_rules",
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										join_rule: "restricted",
 | 
				
			||||||
 | 
										allow: [{
 | 
				
			||||||
 | 
											type: "m.room.membership",
 | 
				
			||||||
 | 
											room_id: spaceID
 | 
				
			||||||
 | 
										}]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							]
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						db.prepare("INSERT INTO channel_room (channel_id, room_id) VALUES (?, ?)").run(channel.id, root.room_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Put the newly created child into the space
 | 
				
			||||||
 | 
						await mreq.mreq("PUT", `/client/v3/rooms/${spaceID}/state/m.space.child/${root.room_id}`, {
 | 
				
			||||||
 | 
							via: ["cadence.moe"] // TODO: use the proper server
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function createAllForGuild(guildID) {
 | 
				
			||||||
 | 
						const channelIDs = discord.guildChannelMap.get(guildID)
 | 
				
			||||||
 | 
						assert.ok(channelIDs)
 | 
				
			||||||
 | 
						for (const channelID of channelIDs) {
 | 
				
			||||||
 | 
							const channel = discord.channels.get(channelID)
 | 
				
			||||||
 | 
							assert.ok(channel)
 | 
				
			||||||
 | 
							const existing = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
 | 
				
			||||||
 | 
							if (channel.type === DiscordTypes.ChannelType.GuildText && !existing) {
 | 
				
			||||||
 | 
								await createRoom(channel)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.createRoom = createRoom
 | 
				
			||||||
 | 
					module.exports.createAllForGuild = createAllForGuild
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										46
									
								
								d2m/actions/create-space.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								d2m/actions/create-space.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const passthrough = require("../../passthrough")
 | 
				
			||||||
 | 
					const { sync, db } = passthrough
 | 
				
			||||||
 | 
					/** @type {import("../../matrix/mreq")} */
 | 
				
			||||||
 | 
					const mreq = sync.require("../../matrix/mreq")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {import("discord-api-types/v10").RESTGetAPIGuildResult} guild
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function createSpace(guild) {
 | 
				
			||||||
 | 
						return mreq.mreq("POST", "/client/v3/createRoom", {
 | 
				
			||||||
 | 
							name: guild.name,
 | 
				
			||||||
 | 
							preset: "private_chat",
 | 
				
			||||||
 | 
							visibility: "private",
 | 
				
			||||||
 | 
							power_level_content_override: {
 | 
				
			||||||
 | 
								events_default: 100,
 | 
				
			||||||
 | 
								invite: 50
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							invite: ["@cadence:cadence.moe"], // TODO
 | 
				
			||||||
 | 
							topic: guild.description || undefined,
 | 
				
			||||||
 | 
							creation_content: {
 | 
				
			||||||
 | 
								type: "m.space"
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							initial_state: [
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.guest_access",
 | 
				
			||||||
 | 
									state_key: "",
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										guest_access: "can_join"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									type: "m.room.history_visibility",
 | 
				
			||||||
 | 
									content: {
 | 
				
			||||||
 | 
										history_visibility: "invited"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							]
 | 
				
			||||||
 | 
						}).then(/** @param {import("../../types").R_RoomCreated} root */ root => {
 | 
				
			||||||
 | 
							db.prepare("INSERT INTO guild_space (guild_id, space_id) VALUES (?, ?)").run(guild.id, root.room_id)
 | 
				
			||||||
 | 
							return root
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.createSpace = createSpace
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ const messageToEvent = require("../converters/message-to-event.js")
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function sendMessage(message) {
 | 
					function sendMessage(message) {
 | 
				
			||||||
	const event = messageToEvent(message)
 | 
						const event = messageToEvent(message)
 | 
				
			||||||
	fetch(`https://matrix.cadence.moe/_matrix/client/v3/rooms/!VwVlIAjOjejUpDhlbA:cadence.moe/send/m.room.message/${makeTxnId()}?user_id=@_ooye_example:cadence.moe`, {
 | 
						return fetch(`https://matrix.cadence.moe/_matrix/client/v3/rooms/!VwVlIAjOjejUpDhlbA:cadence.moe/send/m.room.message/${makeTxnId()}?user_id=@_ooye_example:cadence.moe`, {
 | 
				
			||||||
		method: "PUT",
 | 
							method: "PUT",
 | 
				
			||||||
		body: JSON.stringify(event),
 | 
							body: JSON.stringify(event),
 | 
				
			||||||
		headers: {
 | 
							headers: {
 | 
				
			||||||
| 
						 | 
					@ -24,4 +24,4 @@ function sendMessage(message) {
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = sendMessage
 | 
					module.exports.sendMessage = sendMessage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Discord library internals type beat
 | 
					// Discord library internals type beat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const DiscordTypes = require("discord-api-types/v10")
 | 
				
			||||||
const passthrough = require("../passthrough")
 | 
					const passthrough = require("../passthrough")
 | 
				
			||||||
const { sync } = passthrough
 | 
					const { sync } = passthrough
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +28,8 @@ const utils = {
 | 
				
			||||||
			const arr = []
 | 
								const arr = []
 | 
				
			||||||
			client.guildChannelMap.set(message.d.id, arr)
 | 
								client.guildChannelMap.set(message.d.id, arr)
 | 
				
			||||||
			for (const channel of message.d.channels || []) {
 | 
								for (const channel of message.d.channels || []) {
 | 
				
			||||||
 | 
									// @ts-ignore
 | 
				
			||||||
 | 
									channel.guild_id = message.d.id
 | 
				
			||||||
				arr.push(channel.id)
 | 
									arr.push(channel.id)
 | 
				
			||||||
				client.channels.set(channel.id, channel)
 | 
									client.channels.set(channel.id, channel)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,14 @@
 | 
				
			||||||
// @ts-check
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Grab Discord events we care about for the bridge, check them, and pass them on
 | 
					const {sync} = require("../passthrough")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sendMessage = require("./actions/send-message")
 | 
					/** @type {import("./actions/create-space")}) */
 | 
				
			||||||
 | 
					const createSpace = sync.require("./actions/create-space")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @type {import("./actions/send-message")}) */
 | 
				
			||||||
 | 
					const sendMessage = sync.require("./actions/send-message")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Grab Discord events we care about for the bridge, check them, and pass them on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -10,10 +16,7 @@ module.exports = {
 | 
				
			||||||
	 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
						 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	onMessageCreate(client, message) {
 | 
						onMessageCreate(client, message) {
 | 
				
			||||||
		console.log(message)
 | 
							sendMessage.sendMessage(message)
 | 
				
			||||||
		console.log(message.guild_id)
 | 
					 | 
				
			||||||
		console.log(message.member)
 | 
					 | 
				
			||||||
		sendMessage(message)
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								index.js
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								index.js
									
										
									
									
									
								
							| 
						 | 
					@ -1,13 +1,15 @@
 | 
				
			||||||
// @ts-check
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const sqlite = require("better-sqlite3")
 | 
				
			||||||
const HeatSync = require("heatsync")
 | 
					const HeatSync = require("heatsync")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const config = require("./config")
 | 
					const config = require("./config")
 | 
				
			||||||
const passthrough = require("./passthrough")
 | 
					const passthrough = require("./passthrough")
 | 
				
			||||||
 | 
					const db = new sqlite("db/ooye.db")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sync = new HeatSync()
 | 
					const sync = new HeatSync()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Object.assign(passthrough, { config, sync })
 | 
					Object.assign(passthrough, { config, sync, db })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DiscordClient = require("./d2m/discord-client")
 | 
					const DiscordClient = require("./d2m/discord-client")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										63
									
								
								matrix/file.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								matrix/file.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const fetch = require("node-fetch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const passthrough = require("../passthrough")
 | 
				
			||||||
 | 
					const { sync, db } = passthrough
 | 
				
			||||||
 | 
					/** @type {import("./mreq")} */
 | 
				
			||||||
 | 
					const mreq = sync.require("./mreq")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const DISCORD_IMAGES_BASE = "https://cdn.discordapp.com"
 | 
				
			||||||
 | 
					const IMAGE_SIZE = 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @type {Map<string, Promise<string>>} */
 | 
				
			||||||
 | 
					const inflight = new Map()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} path
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function uploadDiscordFileToMxc(path) {
 | 
				
			||||||
 | 
						const url = DISCORD_IMAGES_BASE + path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Are we uploading this file RIGHT NOW? Return the same inflight promise with the same resolution
 | 
				
			||||||
 | 
						let existing = inflight.get(url)
 | 
				
			||||||
 | 
						if (typeof existing === "string") {
 | 
				
			||||||
 | 
							return existing
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Has this file already been uploaded in the past? Grab the existing copy from the database.
 | 
				
			||||||
 | 
						existing = db.prepare("SELECT mxc_url FROM file WHERE discord_url = ?").pluck().get(url)
 | 
				
			||||||
 | 
						if (typeof existing === "string") {
 | 
				
			||||||
 | 
							return existing
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Download from Discord
 | 
				
			||||||
 | 
						const promise = fetch(url, {}).then(/** @param {import("node-fetch").Response} res */ async res => {
 | 
				
			||||||
 | 
							/** @ts-ignore @type {import("stream").Readable} body */
 | 
				
			||||||
 | 
							const body = res.body
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Upload to Matrix
 | 
				
			||||||
 | 
							/** @type {import("../types").R_FileUploaded} */
 | 
				
			||||||
 | 
							const root = await mreq.mreq("POST", "/media/v3/upload", body, {
 | 
				
			||||||
 | 
								headers: {
 | 
				
			||||||
 | 
									"Content-Type": res.headers.get("content-type")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Store relationship in database
 | 
				
			||||||
 | 
							db.prepare("INSERT INTO file (discord_url, mxc_url) VALUES (?, ?)").run(url, root.content_uri)
 | 
				
			||||||
 | 
							inflight.delete(url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return root.content_uri
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						inflight.set(url, promise)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return promise
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function guildIcon(guild) {
 | 
				
			||||||
 | 
						return `/icons/${guild.id}/${guild.icon}?size=${IMAGE_SIZE}`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.guildIcon = guildIcon
 | 
				
			||||||
 | 
					module.exports.uploadDiscordFileToMxc = uploadDiscordFileToMxc
 | 
				
			||||||
							
								
								
									
										47
									
								
								matrix/mreq.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								matrix/mreq.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const fetch = require("node-fetch")
 | 
				
			||||||
 | 
					const mixin = require("mixin-deep")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const passthrough = require("../passthrough")
 | 
				
			||||||
 | 
					const { sync } = passthrough
 | 
				
			||||||
 | 
					/** @type {import("./read-registration")} */
 | 
				
			||||||
 | 
					const reg = sync.require("./read-registration.js")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const baseUrl = "https://matrix.cadence.moe/_matrix"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MatrixServerError {
 | 
				
			||||||
 | 
						constructor(data) {
 | 
				
			||||||
 | 
							this.data = data
 | 
				
			||||||
 | 
							/** @type {string} */
 | 
				
			||||||
 | 
							this.errcode = data.errcode
 | 
				
			||||||
 | 
							/** @type {string} */
 | 
				
			||||||
 | 
							this.error = data.error
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} method
 | 
				
			||||||
 | 
					 * @param {string} url
 | 
				
			||||||
 | 
					 * @param {any} [body]
 | 
				
			||||||
 | 
					 * @param {any} [extra]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function mreq(method, url, body, extra = {}) {
 | 
				
			||||||
 | 
						const opts = mixin({
 | 
				
			||||||
 | 
							method,
 | 
				
			||||||
 | 
							body: (body == undefined || Object.is(body.constructor, Object)) ? JSON.stringify(body) : body,
 | 
				
			||||||
 | 
							headers: {
 | 
				
			||||||
 | 
								Authorization: `Bearer ${reg.as_token}`
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}, extra)
 | 
				
			||||||
 | 
						console.log(baseUrl + url, opts)
 | 
				
			||||||
 | 
						return fetch(baseUrl + url, opts).then(res => {
 | 
				
			||||||
 | 
							return res.json().then(root => {
 | 
				
			||||||
 | 
								if (!res.ok || root.errcode) throw new MatrixServerError(root)
 | 
				
			||||||
 | 
								return root
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.MatrixServerError = MatrixServerError
 | 
				
			||||||
 | 
					module.exports.mreq = mreq
 | 
				
			||||||
| 
						 | 
					@ -3,11 +3,5 @@
 | 
				
			||||||
const fs = require("fs")
 | 
					const fs = require("fs")
 | 
				
			||||||
const yaml = require("js-yaml")
 | 
					const yaml = require("js-yaml")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** 
 | 
					/** @type {import("../types").AppServiceRegistrationConfig} */
 | 
				
			||||||
 * @typedef AppServiceRegistrationConfig
 | 
					 | 
				
			||||||
 * @property {string} id
 | 
					 | 
				
			||||||
 * @property {string} as_token
 | 
					 | 
				
			||||||
 * @property {string} hs_token
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = yaml.load(fs.readFileSync("registration.yaml", "utf8"))
 | 
					module.exports = yaml.load(fs.readFileSync("registration.yaml", "utf8"))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								notes.md
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								notes.md
									
										
									
									
									
								
							| 
						 | 
					@ -36,6 +36,13 @@ Public channels in that server should then use the following settings, so that t
 | 
				
			||||||
- Find & join access: Space members (so users must have been invited to the space already, even if they find out the room ID to join)
 | 
					- Find & join access: Space members (so users must have been invited to the space already, even if they find out the room ID to join)
 | 
				
			||||||
- Who can read history: Anyone (so that people can see messages during the preview before joining)
 | 
					- Who can read history: Anyone (so that people can see messages during the preview before joining)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Step by step process:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Create a space room for the guild. Store the guild-space ID relationship in the database. Configure the space room to act like a space.
 | 
				
			||||||
 | 
						- `{"name":"NAME","preset":"private_chat","visibility":"private","power_level_content_override":{"events_default":100,"invite":50},"topic":"TOPIC","creation_content":{"type":"m.space"},"initial_state":[{"type":"m.room.guest_access","state_key":"","content":{"guest_access":"can_join"}},{"type":"m.room.history_visibility","content":{"history_visibility":"invited"}}]}`
 | 
				
			||||||
 | 
					2. Create channel rooms for the channels. Store the channel-room ID relationship in the database. (Probably no need to store parent-child relationships in the database?)
 | 
				
			||||||
 | 
					3. Send state events to put the channel rooms in the space.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Private channels
 | 
					### Private channels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Discord **channels** that disallow view permission to @everyone should instead have the following **room** settings in Matrix:
 | 
					Discord **channels** that disallow view permission to @everyone should instead have the following **room** settings in Matrix:
 | 
				
			||||||
| 
						 | 
					@ -58,6 +65,13 @@ The context-sensitive /invite command will invite Matrix users to the correspond
 | 
				
			||||||
1. Transform content.
 | 
					1. Transform content.
 | 
				
			||||||
2. Send to matrix.
 | 
					2. Send to matrix.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Webhook message sent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Consider using the _ooye_bot account to send all webhook messages to prevent extraneous joins?
 | 
				
			||||||
 | 
						- Downside: the profile information from the most recently sent message would stick around in the member list. This is toleable.
 | 
				
			||||||
 | 
					- Otherwise, could use an account per webhook ID, but if webhook IDs are often deleted and re-created, this could still end up leaving too many accounts in the room.
 | 
				
			||||||
 | 
					- The original bridge uses an account per webhook display name, which does the most sense in terms of canonical accounts, but leaves too many accounts in the room.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Message deleted
 | 
					## Message deleted
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Look up equivalents on matrix.
 | 
					1. Look up equivalents on matrix.
 | 
				
			||||||
| 
						 | 
					@ -91,4 +105,13 @@ The context-sensitive /invite command will invite Matrix users to the correspond
 | 
				
			||||||
	1. Create the corresponding room.
 | 
						1. Create the corresponding room.
 | 
				
			||||||
	2. Add to database.
 | 
						2. Add to database.
 | 
				
			||||||
3. Update room details to match.
 | 
					3. Update room details to match.
 | 
				
			||||||
4. Add to space.
 | 
					4. Make sure the permissions are correct according to the rules above!
 | 
				
			||||||
 | 
					5. Add to space.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Emojis updated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Upload any newly added images to msc.
 | 
				
			||||||
 | 
					2. Create or replace state event for the bridged pack. (Can just use key "ooye" and display name "Discord", or something, for this pack.)
 | 
				
			||||||
 | 
					3. The emojis may now be sent by Matrix users!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TOSPEC: m2d emoji uploads??
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -16,6 +16,7 @@
 | 
				
			||||||
        "js-yaml": "^4.1.0",
 | 
					        "js-yaml": "^4.1.0",
 | 
				
			||||||
        "matrix-appservice": "^2.0.0",
 | 
					        "matrix-appservice": "^2.0.0",
 | 
				
			||||||
        "matrix-js-sdk": "^24.1.0",
 | 
					        "matrix-js-sdk": "^24.1.0",
 | 
				
			||||||
 | 
					        "mixin-deep": "^2.0.1",
 | 
				
			||||||
        "node-fetch": "^2.6.7",
 | 
					        "node-fetch": "^2.6.7",
 | 
				
			||||||
        "snowtransfer": "^0.7.0",
 | 
					        "snowtransfer": "^0.7.0",
 | 
				
			||||||
        "supertape": "^8.3.0"
 | 
					        "supertape": "^8.3.0"
 | 
				
			||||||
| 
						 | 
					@ -1696,6 +1697,14 @@
 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/mixin-deep": {
 | 
				
			||||||
 | 
					      "version": "2.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-2.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-imbHQNRglyaplMmjBLL3V5R6Bfq5oM+ivds3SKgc6oRtzErEnBUUc5No11Z2pilkUvl42gJvi285xTNswcKCMA==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/mkdirp-classic": {
 | 
					    "node_modules/mkdirp-classic": {
 | 
				
			||||||
      "version": "0.5.3",
 | 
					      "version": "0.5.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
    "js-yaml": "^4.1.0",
 | 
					    "js-yaml": "^4.1.0",
 | 
				
			||||||
    "matrix-appservice": "^2.0.0",
 | 
					    "matrix-appservice": "^2.0.0",
 | 
				
			||||||
    "matrix-js-sdk": "^24.1.0",
 | 
					    "matrix-js-sdk": "^24.1.0",
 | 
				
			||||||
 | 
					    "mixin-deep": "^2.0.1",
 | 
				
			||||||
    "node-fetch": "^2.6.7",
 | 
					    "node-fetch": "^2.6.7",
 | 
				
			||||||
    "snowtransfer": "^0.7.0",
 | 
					    "snowtransfer": "^0.7.0",
 | 
				
			||||||
    "supertape": "^8.3.0"
 | 
					    "supertape": "^8.3.0"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
 * @property {typeof import("./config")} config
 | 
					 * @property {typeof import("./config")} config
 | 
				
			||||||
 * @property {import("./d2m/discord-client")} discord
 | 
					 * @property {import("./d2m/discord-client")} discord
 | 
				
			||||||
 * @property {import("heatsync")} sync
 | 
					 * @property {import("heatsync")} sync
 | 
				
			||||||
 | 
					 * @property {import("better-sqlite3/lib/database")} db
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
/** @type {Passthrough} */
 | 
					/** @type {Passthrough} */
 | 
				
			||||||
// @ts-ignore
 | 
					// @ts-ignore
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								stdin.js
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								stdin.js
									
										
									
									
									
								
							| 
						 | 
					@ -4,7 +4,12 @@ const repl = require("repl")
 | 
				
			||||||
const util = require("util")
 | 
					const util = require("util")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const passthrough = require("./passthrough")
 | 
					const passthrough = require("./passthrough")
 | 
				
			||||||
const { discord, config, sync } = passthrough
 | 
					const { discord, config, sync, db } = passthrough
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createSpace = sync.require("./d2m/actions/create-space.js")
 | 
				
			||||||
 | 
					const createRoom = sync.require("./d2m/actions/create-room.js")
 | 
				
			||||||
 | 
					const mreq = sync.require("./matrix/mreq.js")
 | 
				
			||||||
 | 
					const guildID = "112760669178241024"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const extraContext = {}
 | 
					const extraContext = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								types.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								types.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,6 +1,24 @@
 | 
				
			||||||
 | 
					export type AppServiceRegistrationConfig = {
 | 
				
			||||||
 | 
						id: string
 | 
				
			||||||
 | 
						as_token: string
 | 
				
			||||||
 | 
						hs_token: string
 | 
				
			||||||
 | 
						url: string
 | 
				
			||||||
 | 
						sender_localpart: string
 | 
				
			||||||
 | 
						protocols: [string]
 | 
				
			||||||
 | 
						rate_limited: boolean
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type M_Room_Message_content = {
 | 
					export type M_Room_Message_content = {
 | 
				
			||||||
	msgtype: "m.text"
 | 
						msgtype: "m.text"
 | 
				
			||||||
	body: string
 | 
						body: string
 | 
				
			||||||
	formatted_body?: "org.matrix.custom.html"
 | 
						formatted_body?: "org.matrix.custom.html"
 | 
				
			||||||
	format?: string
 | 
						format?: string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type R_RoomCreated = {
 | 
				
			||||||
 | 
						room_id: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type R_FileUploaded = {
 | 
				
			||||||
 | 
						content_uri: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue