space and room creation
This commit is contained in:
parent
51480e21e5
commit
5716366b3f
17 changed files with 409 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)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
BIN
db/ooye.db
Normal file
BIN
db/ooye.db
Normal file
Binary file not shown.
81
db/ooye.sql
Normal file
81
db/ooye.sql
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
CREATE TABLE IF NOT EXISTS "guild_space" (
|
||||||
|
"guild_id" TEXT NOT NULL UNIQUE,
|
||||||
|
"space_id" TEXT NOT NULL UNIQUE,
|
||||||
|
PRIMARY KEY("guild_id")
|
||||||
|
);
|
||||||
|
INSERT INTO guild_space VALUES('112760669178241024','!jjWAGMeQdNrVZSSfvz:cadence.moe');
|
||||||
|
CREATE TABLE IF NOT EXISTS "channel_room" (
|
||||||
|
"channel_id" TEXT NOT NULL UNIQUE,
|
||||||
|
"room_id" TEXT NOT NULL UNIQUE,
|
||||||
|
PRIMARY KEY("channel_id")
|
||||||
|
);
|
||||||
|
INSERT INTO channel_room VALUES('395073525641117699','!HfUDHZheYriEncfKpJ:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('808564048294838284','!uMHZzVXeXPrVehmPIm:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('694935757160185907','!qAAlGzsrXrLKqAEHas:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('739017679796436992','!cGIULAxjVJReFZosbK:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('441910023501774858','!JrwSgmaBchooVnCqcF:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('841417575120371722','!mwzCPYqPHAHOdeKPMi:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('488516474735034389','!dqvFUrlHREgNEWmkua:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('920170211330650152','!sTfMRJPdoqTNzMXvbn:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('203751294157062145','!repkBsIWwFyOOvudGt:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('134477188899536898','!uUzBXdWQblkxNmThLz:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('266767590641238027','!IzOgQiDnusFQiwymaL:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('834530844743434289','!kczmYjDXhhTVvCRHGE:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('265998010092093441','!zGfmedYghbfnFQJXjU:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('339294043274215424','!fNDEjktDGIWAPlMWYy:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('398661111869865985','!gAnxDqVCDfudmiuwnU:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('814300638237163550','!GTkemJlzNRPcbXIjHh:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('112760669178241024','!kLRqKKUQXcibIMtOpl:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('604901695255740426','!gsMllRhFEUVaVAiJQR:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('176333891320283136','!pzHnyQchkiIJzfjYlR:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('350076239257796620','!MkOZEeLWrKJLpYjCig:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('160197704226439168','!uCtjHhfGlYbVnPVlkG:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('204427407539568640','!aaBHsbHThhtFBjJnjs:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('288058913985789953','!TBwEJEXTvbvDSYzyJq:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('622903842282930198','!RCRvXmNpFSjoFNEmvh:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('421368191567265794','!cKgTdFmarjJnGDipUE:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('334553412698112002','!EacGxEcLvxmrSPZoOA:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('395750520435769347','!btmhtSzFqMYqTzNGmq:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('196455508146651136','!QGSDlxmJjIGzqmhngS:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('1089120827926134854','!QlsPSkhOsplXOgvKzG:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('655216173696286746','!prNIHWeXgudqChdvTJ:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('171083630985216001','!kEWSvtyEhPFCviOHnA:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('530220226109898752','!bdNsNYyBQyEdFmeoZd:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('1075095715396735056','!gPfVCpFUnmoEDVAPph:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('392141322863116319','!ErHIqXEnsVdvHbFAUO:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('189898393705906177','!UAXXOjEgIYtexsvzZC:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('134077753485033472','!qGpHzEREMSFEKDjzdB:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('696180458417029170','!thbRkzupoPmsxCiWyv:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('191487489943404544','!nOfpEIzWgaLnRHFoAF:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('121380024812044288','!QKqjAQJmXwnevnKsGh:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('687028734322147344','!fGgIymcYWOqjbSRUdV:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('330164254969823233','!vYZSKYOSArwqWyaJZB:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('872258827846832139','!INBHUKdIiCMxpizitC:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('112767097234305024','!bXgJfZZqdFlmmAeYSj:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('249968792346558465','!CRoJhPJAarFkoOVfUg:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('130176644093575168','!tgQCmRkBndtQcbhqPX:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('312054608535224320','!oDNMTEymekxHTizhEC:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('1099031887500034088','!bexkxPoPBmSuUkvACP:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('412754166885122048','!ASqMFolSWJsJWAIJqB:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('700941324810977333','!gLvyxfpmPetCqtOCka:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('361364140448808960','!yyzLRrLSmYGuNGkbup:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('132423337019310081','!QcGgaDKBEDvSnFpDUT:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('698892233398812742','!ASiHdjKOmjyQCmhWEJ:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('591183598166736908','!NMmIckmkngIVeTLmWM:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('288882953314893825','!hNBIHkfRMrryuWfPrb:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('265617582126661642','!YaJsBSpCOtaccZShBy:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('113414562417496064','!UHfjZYvdnkjqwvOylF:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('373335332436967424','!cFjDyGrtFmHymyLfRE:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('331390333810376704','!kdALuKGeNSkYDgRhIZ:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('768264034327724132','!FEhofHtvWOSNCuvUxW:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('359903425074561024','!IGixYyKLdvmnAzzOGB:cadence.moe');
|
||||||
|
INSERT INTO channel_room VALUES('122155380120748034','!iMLtMMlHpWNyAnadZu:cadence.moe');
|
||||||
|
CREATE TABLE IF NOT EXISTS "file" (
|
||||||
|
"discord_url" TEXT NOT NULL UNIQUE,
|
||||||
|
"mxc_url" TEXT NOT NULL UNIQUE,
|
||||||
|
PRIMARY KEY("discord_url")
|
||||||
|
);
|
||||||
|
INSERT INTO file VALUES('https://cdn.discordapp.com/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c?size=1024','mxc://cadence.moe/sZtPwbfOIsvfSoWCWPrGnzql');
|
||||||
|
COMMIT;
|
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…
Reference in a new issue