Compare commits

..

No commits in common. "1643a46812ed5b96f568e9712ea3bd64750fbf3e" and "7712bc34a6081a62cd06e2b046f3ba8869c44aa7" have entirely different histories.

15 changed files with 36 additions and 319 deletions

View file

@ -17,7 +17,6 @@ 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) {
@ -37,17 +36,12 @@ function applyKStateDiffToRoom(roomID, kstate) {
} }
/** /**
* @param {{id: string, name: string, topic?: string?, type: number}} channel * @param {{id: string, name: string, topic?: string?}} channel
* @param {{id: string}} guild * @param {{id: string}} guild
* @param {string?} customName * @param {string?} customName
*/ */
function convertNameAndTopic(channel, guild, customName) { function convertNameAndTopic(channel, guild, customName) {
let channelPrefix = const convertedName = customName || channel.name;
( channel.type === DiscordTypes.ChannelType.PublicThread ? "[⛓️] "
: channel.type === DiscordTypes.ChannelType.PrivateThread ? "[🔒⛓️] "
: channel.type === DiscordTypes.ChannelType.GuildVoice ? "[🔊] "
: "")
const chosenName = customName || (channelPrefix + channel.name);
const maybeTopicWithPipe = channel.topic ? ` | ${channel.topic}` : ''; const maybeTopicWithPipe = channel.topic ? ` | ${channel.topic}` : '';
const maybeTopicWithNewlines = channel.topic ? `${channel.topic}\n\n` : ''; const maybeTopicWithNewlines = channel.topic ? `${channel.topic}\n\n` : '';
const channelIDPart = `Channel ID: ${channel.id}`; const channelIDPart = `Channel ID: ${channel.id}`;
@ -57,11 +51,10 @@ function convertNameAndTopic(channel, guild, customName) {
? `#${channel.name}${maybeTopicWithPipe}\n\n${channelIDPart}\n${guildIDPart}` ? `#${channel.name}${maybeTopicWithPipe}\n\n${channelIDPart}\n${guildIDPart}`
: `${maybeTopicWithNewlines}${channelIDPart}\n${guildIDPart}`; : `${maybeTopicWithNewlines}${channelIDPart}\n${guildIDPart}`;
return [chosenName, convertedTopic]; return [convertedName, convertedTopic];
} }
/** /**
* 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
*/ */
@ -125,21 +118,13 @@ async function createRoom(channel, guild, spaceID, kstate) {
if (channel.type === DiscordTypes.ChannelType.PublicThread) threadParent = channel.parent_id if (channel.type === DiscordTypes.ChannelType.PublicThread) threadParent = channel.parent_id
const invite = threadParent ? [] : ["@cadence:cadence.moe"] // TODO const invite = threadParent ? [] : ["@cadence:cadence.moe"] // TODO
// Name and topic can be done earlier in room creation rather than in initial_state
// https://spec.matrix.org/latest/client-server-api/#creation
const name = kstate["m.room.name/"].name
delete kstate["m.room.name/"]
assert(name)
const topic = kstate["m.room.topic/"].topic
delete kstate["m.room.topic/"]
assert(topic)
const roomID = await postApplyPowerLevels(kstate, async kstate => { const roomID = await postApplyPowerLevels(kstate, async kstate => {
const [convertedName, convertedTopic] = convertNameAndTopic(channel, guild, null)
const roomID = await api.createRoom({ const roomID = await api.createRoom({
name, name: convertedName,
topic, topic: convertedTopic,
preset: "private_chat", // This is closest to what we want, but properties from kstate override it anyway preset: "private_chat",
visibility: "private", // Not shown in the room directory visibility: "private",
invite, invite,
initial_state: ks.kstateToState(kstate) initial_state: ks.kstateToState(kstate)
}) })
@ -202,10 +187,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
Ensure + sync flow: New combined flow with ensure / sync:
1. Get IDs 1. Get IDs
2. Does room exist? 2. Does room exist?
2.5: If room does exist AND wasn't asked to sync: return here 2.5: If room does exist AND don't need 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
@ -248,7 +233,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) // calling this in both branches because we don't want to calculate this if not syncing const {spaceID, channelKState} = await channelToKState(channel, guild)
// sync channel state to room // sync channel state to room
const roomKState = await roomToKState(roomID) const roomKState = await roomToKState(roomID)
@ -263,16 +248,6 @@ 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)
@ -301,7 +276,6 @@ 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
@ -324,6 +298,14 @@ 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

@ -14,49 +14,28 @@ test("channel2room: general", async t => {
test("convertNameAndTopic: custom name and topic", t => { test("convertNameAndTopic: custom name and topic", t => {
t.deepEqual( t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, "hauntings"), _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:"}, {id: "456"}, "hauntings"),
["hauntings", "#the-twilight-zone | Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] ["hauntings", "#the-twilight-zone | Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"]
) )
}) })
test("convertNameAndTopic: custom name, no topic", t => { test("convertNameAndTopic: custom name, no topic", t => {
t.deepEqual( t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", type: 0}, {id: "456"}, "hauntings"), _convertNameAndTopic({id: "123", name: "the-twilight-zone"}, {id: "456"}, "hauntings"),
["hauntings", "#the-twilight-zone\n\nChannel ID: 123\nGuild ID: 456"] ["hauntings", "#the-twilight-zone\n\nChannel ID: 123\nGuild ID: 456"]
) )
}) })
test("convertNameAndTopic: original name and topic", t => { test("convertNameAndTopic: original name and topic", t => {
t.deepEqual( t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, null), _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:"}, {id: "456"}, null),
["the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"] ["the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"]
) )
}) })
test("convertNameAndTopic: original name, no topic", t => { test("convertNameAndTopic: original name, no topic", t => {
t.deepEqual( t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", type: 0}, {id: "456"}, null), _convertNameAndTopic({id: "123", name: "the-twilight-zone"}, {id: "456"}, null),
["the-twilight-zone", "Channel ID: 123\nGuild ID: 456"] ["the-twilight-zone", "Channel ID: 123\nGuild ID: 456"]
) )
}) })
test("convertNameAndTopic: public thread icon", t => {
t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 11}, {id: "456"}, null),
["[⛓️] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"]
)
})
test("convertNameAndTopic: private thread icon", t => {
t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 12}, {id: "456"}, null),
["[🔒⛓️] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"]
)
})
test("convertNameAndTopic: voice channel icon", t => {
t.deepEqual(
_convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 2}, {id: "456"}, null),
["[🔊] the-twilight-zone", "Spooky stuff here. :ghost:\n\nChannel ID: 123\nGuild ID: 456"]
)
})

View file

@ -1,6 +1,6 @@
// @ts-check // @ts-check
const assert = require("assert").strict const assert = require("assert")
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
@ -84,31 +84,11 @@ async function syncSpace(guildID) {
console.log(`[space sync] to matrix: ${guild.name}`) console.log(`[space sync] to matrix: ${guild.name}`)
// sync guild state to space // sync channel state to room
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
} }

View file

@ -3,27 +3,7 @@ const {_memberToStateContent} = require("./register-user")
const {test} = require("supertape") const {test} = require("supertape")
const testData = require("../../test/data") const testData = require("../../test/data")
test("member2state: without member nick or avatar", async t => { test("member2state: general", async t => {
t.deepEqual(
await _memberToStateContent(testData.member.kumaccino.user, testData.member.kumaccino, testData.guild.general.id),
{
avatar_url: "mxc://cadence.moe/UpAeIqeclhKfeiZNdIWNcXXL",
displayname: "kumaccino",
membership: "join",
"moe.cadence.ooye.member": {
avatar: "/avatars/113340068197859328/b48302623a12bc7c59a71328f72ccb39.png?size=1024"
},
"uk.half-shot.discord.member": {
bot: false,
displayColor: 10206929,
id: "113340068197859328",
username: "@kumaccino"
}
}
)
})
test("member2state: with member nick and avatar", async t => {
t.deepEqual( t.deepEqual(
await _memberToStateContent(testData.member.sheep.user, testData.member.sheep, testData.guild.general.id), await _memberToStateContent(testData.member.sheep.user, testData.member.sheep, testData.guild.general.id),
{ {

View file

@ -39,7 +39,6 @@ function* generateLocalpartAlternatives(preferences) {
let i = 2 let i = 2
while (true) { while (true) {
yield best + (i++) yield best + (i++)
/* c8 ignore next */
} }
} }
@ -70,7 +69,7 @@ function userToSimName(user) {
for (const suggestion of generateLocalpartAlternatives(preferences)) { for (const suggestion of generateLocalpartAlternatives(preferences)) {
if (!matches.includes(suggestion)) return suggestion if (!matches.includes(suggestion)) return suggestion
} }
/* c8 ignore next */
throw new Error(`Ran out of suggestions when generating sim name. downcased: "${downcased}"`) throw new Error(`Ran out of suggestions when generating sim name. downcased: "${downcased}"`)
} }

View file

@ -1,142 +0,0 @@
// @ts-check
const assert = require("assert").strict
const util = require("util")
const DiscordTypes = require("discord-api-types/v10")
const {discord, sync, db} = require("../passthrough")
/** @type {import("../matrix/api")}) */
const api = sync.require("../matrix/api")
/** @type {import("../matrix/file")} */
const file = sync.require("../matrix/file")
const PREFIX = "//"
let buttons = []
/**
* @param {string} channelID where to add the button
* @param {string} messageID where to add the button
* @param {string} emoji emoji to add as a button
* @param {string} userID only listen for responses from this user
* @returns {Promise<import("discord-api-types/v10").GatewayMessageReactionAddDispatchData>}
*/
async function addButton(channelID, messageID, emoji, userID) {
await discord.snow.channel.createReaction(channelID, messageID, emoji)
return new Promise(resolve => {
buttons.push({channelID, messageID, userID, resolve, created: Date.now()})
})
}
// Clear out old buttons every so often to free memory
setInterval(() => {
const now = Date.now()
buttons = buttons.filter(b => now - b.created < 2*60*60*1000)
}, 10*60*1000)
/** @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data */
function onReactionAdd(data) {
const button = buttons.find(b => b.channelID === data.channel_id && b.messageID === data.message_id && b.userID === data.user_id)
if (button) {
buttons = buttons.filter(b => b !== button) // remove button data so it can't be clicked again
button.resolve(data)
}
}
/**
* @callback CommandExecute
* @param {DiscordTypes.GatewayMessageCreateDispatchData} message
* @param {DiscordTypes.APIGuildTextChannel} channel
* @param {DiscordTypes.APIGuild} guild
* @param {Partial<DiscordTypes.RESTPostAPIChannelMessageJSONBody>} [ctx]
*/
/**
* @typedef Command
* @property {string[]} aliases
* @property {(message: DiscordTypes.GatewayMessageCreateDispatchData, channel: DiscordTypes.APIGuildTextChannel, guild: DiscordTypes.APIGuild) => Promise<any>} execute
*/
/** @param {CommandExecute} execute */
function replyctx(execute) {
/** @type {CommandExecute} */
return function(message, channel, guild, ctx = {}) {
ctx.message_reference = {
message_id: message.id,
channel_id: channel.id,
guild_id: guild.id,
fail_if_not_exists: false
}
return execute(message, channel, guild, ctx)
}
}
/** @type {Command[]} */
const commands = [{
aliases: ["icon", "avatar", "roomicon", "roomavatar", "channelicon", "channelavatar"],
execute: replyctx(
async (message, channel, guild, ctx) => {
// Guard
const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
if (!roomID) return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "This channel isn't bridged to the other side."
})
// Current avatar
const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "")
const avatarURLParts = avatarEvent?.url.match(/^mxc:\/\/([^/]+)\/(\w+)$/)
let currentAvatarMessage =
( avatarURLParts ? `Current room-specific avatar: https://matrix.cadence.moe/_matrix/media/r0/download/${avatarURLParts[1]}/${avatarURLParts[2]}`
: "No avatar. Now's your time to strike. Use `//icon` again with a link or upload to set the room-specific avatar.")
// Next potential avatar
const nextAvatarURL = message.attachments.find(a => a.content_type?.startsWith("image/"))?.url || message.content.match(/https?:\/\/[^ ]+\.[^ ]+\.(?:png|jpg|jpeg|webp)\b/)?.[0]
let nextAvatarMessage =
( nextAvatarURL ? `\nYou want to set it to: ${nextAvatarURL}\nHit ✅ to make it happen.`
: "")
const sent = await discord.snow.channel.createMessage(channel.id, {
...ctx,
content: currentAvatarMessage + nextAvatarMessage
})
if (nextAvatarURL) {
addButton(channel.id, sent.id, "✅", message.author.id).then(async data => {
const mxcUrl = await file.uploadDiscordFileToMxc(nextAvatarURL)
await api.sendState(roomID, "m.room.avatar", "", {
url: mxcUrl
})
db.prepare("UPDATE channel_room SET custom_avatar = ? WHERE channel_id = ?").run(mxcUrl, channel.id)
await discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "Your creation is unleashed. Any complaints will be redirected to Grelbo."
})
})
}
}
)
}, {
aliases: ["invite"],
execute: replyctx(
async (message, channel, guild, ctx) => {
return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "This command isn't implemented yet."
})
}
)
}]
/** @type {CommandExecute} */
async function execute(message, channel, guild) {
if (!message.content.startsWith(PREFIX)) return
const words = message.content.slice(PREFIX.length).split(" ")
const commandName = words[0]
const command = commands.find(c => c.aliases.includes(commandName))
if (!command) return
await command.execute(message, channel, guild)
}
module.exports.execute = execute
module.exports.onReactionAdd = onReactionAdd

View file

@ -18,8 +18,6 @@ const createRoom = sync.require("./actions/create-room")
const createSpace = sync.require("./actions/create-space") const createSpace = sync.require("./actions/create-space")
/** @type {import("../matrix/api")}) */ /** @type {import("../matrix/api")}) */
const api = sync.require("../matrix/api") const api = sync.require("../matrix/api")
/** @type {import("./discord-command-handler")}) */
const discordCommandHandler = sync.require("./discord-command-handler")
let lastReportedEvent = 0 let lastReportedEvent = 0
@ -158,9 +156,7 @@ module.exports = {
if (!channel.guild_id) return // Nothing we can do in direct messages. if (!channel.guild_id) return // Nothing we can do in direct messages.
const guild = client.guilds.get(channel.guild_id) const guild = client.guilds.get(channel.guild_id)
if (!isGuildAllowed(guild.id)) return if (!isGuildAllowed(guild.id)) return
await sendMessage.sendMessage(message, guild)
await sendMessage.sendMessage(message, guild),
await discordCommandHandler.execute(message, channel, guild)
}, },
/** /**
@ -195,7 +191,6 @@ module.exports = {
*/ */
async onReactionAdd(client, data) { async onReactionAdd(client, data) {
if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix. if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix.
discordCommandHandler.onReactionAdd(data)
if (data.emoji.id !== null) return // TODO: image emoji reactions if (data.emoji.id !== null) return // TODO: image emoji reactions
await addReaction.addReaction(data) await addReaction.addReaction(data)
}, },

View file

@ -93,7 +93,6 @@ INSERT INTO file (discord_url, mxc_url) VALUES
('https://cdn.discordapp.com/attachments/112760669178241024/1141501302497615912/piper_2.png', 'mxc://cadence.moe/KQYdXKRcHWjDYDLPkTOOWOjA'), ('https://cdn.discordapp.com/attachments/112760669178241024/1141501302497615912/piper_2.png', 'mxc://cadence.moe/KQYdXKRcHWjDYDLPkTOOWOjA'),
('https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg', 'mxc://cadence.moe/WlAbFSiNRIHPDEwKdyPeGywa'), ('https://cdn.discordapp.com/attachments/112760669178241024/1128084851023675515/RDT_20230704_0936184915846675925224905.jpg', 'mxc://cadence.moe/WlAbFSiNRIHPDEwKdyPeGywa'),
('https://cdn.discordapp.com/guilds/112760669178241024/users/134826546694193153/avatars/38dd359aa12bcd52dd3164126c587f8c.png?size=1024', 'mxc://cadence.moe/rfemHmAtcprjLEiPiEuzPhpl'), ('https://cdn.discordapp.com/guilds/112760669178241024/users/134826546694193153/avatars/38dd359aa12bcd52dd3164126c587f8c.png?size=1024', 'mxc://cadence.moe/rfemHmAtcprjLEiPiEuzPhpl'),
('https://cdn.discordapp.com/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024', 'mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF'), ('https://cdn.discordapp.com/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024', 'mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF');
('https://cdn.discordapp.com/avatars/113340068197859328/b48302623a12bc7c59a71328f72ccb39.png?size=1024', 'mxc://cadence.moe/UpAeIqeclhKfeiZNdIWNcXXL');
COMMIT; COMMIT;

View file

@ -32,7 +32,7 @@ function eventToMessage(event) {
}) })
} else if (event.content.msgtype === "m.emote") { } else if (event.content.msgtype === "m.emote") {
messages.push({ messages.push({
content: `\* _${displayName} ${event.content.body}_`, content: `*${displayName} ${event.content.body}*`,
username: displayName, username: displayName,
avatar_url: avatarURL avatar_url: avatarURL
}) })

View file

@ -190,7 +190,6 @@ module.exports.inviteToRoom = inviteToRoom
module.exports.leaveRoom = leaveRoom module.exports.leaveRoom = leaveRoom
module.exports.getEvent = getEvent module.exports.getEvent = getEvent
module.exports.getAllState = getAllState module.exports.getAllState = getAllState
module.exports.getStateEvent = getStateEvent
module.exports.getJoinedMembers = getJoinedMembers module.exports.getJoinedMembers = getJoinedMembers
module.exports.sendState = sendState module.exports.sendState = sendState
module.exports.sendEvent = sendEvent module.exports.sendEvent = sendEvent

View file

@ -27,15 +27,15 @@ async function uploadDiscordFileToMxc(path) {
} }
// Are we uploading this file RIGHT NOW? Return the same inflight promise with the same resolution // Are we uploading this file RIGHT NOW? Return the same inflight promise with the same resolution
const existingInflight = inflight.get(url) let existing = inflight.get(url)
if (existingInflight) { if (typeof existing === "string") {
return existingInflight return existing
} }
// Has this file already been uploaded in the past? Grab the existing copy from the database. // Has this file already been uploaded in the past? Grab the existing copy from the database.
const existingFromDb = db.prepare("SELECT mxc_url FROM file WHERE discord_url = ?").pluck().get(url) existing = db.prepare("SELECT mxc_url FROM file WHERE discord_url = ?").pluck().get(url)
if (typeof existingFromDb === "string") { if (typeof existing === "string") {
return existingFromDb return existing
} }
// Download from Discord // Download from Discord

View file

@ -1,12 +0,0 @@
// @ts-check
const {test} = require("supertape")
const txnid = require("./txnid")
test("txnid: generates different values each run", t => {
const one = txnid.makeTxnId()
t.ok(one)
const two = txnid.makeTxnId()
t.ok(two)
t.notEqual(two, one)
})

View file

@ -12,7 +12,6 @@ const createRoom = sync.require("./d2m/actions/create-room")
const registerUser = sync.require("./d2m/actions/register-user") const registerUser = sync.require("./d2m/actions/register-user")
const mreq = sync.require("./matrix/mreq") const mreq = sync.require("./matrix/mreq")
const api = sync.require("./matrix/api") const api = sync.require("./matrix/api")
const file = sync.require("./matrix/file")
const sendEvent = sync.require("./m2d/actions/send-event") const sendEvent = sync.require("./m2d/actions/send-event")
const eventDispatcher = sync.require("./d2m/event-dispatcher") const eventDispatcher = sync.require("./d2m/event-dispatcher")
const ks = sync.require("./matrix/kstate") const ks = sync.require("./matrix/kstate")

View file

@ -98,46 +98,6 @@ module.exports = {
} }
}, },
member: { member: {
kumaccino: {
avatar: null,
communication_disabled_until: null,
flags: 0,
joined_at: "2015-11-11T09:55:40.321000+00:00",
nick: null,
pending: false,
premium_since: null,
roles: [
"112767366235959296", "118924814567211009",
"199995902742626304", "204427286542417920",
"222168467627835392", "238028326281805825",
"259806643414499328", "265239342648131584",
"271173313575780353", "287733611912757249",
"225744901915148298", "305775031223320577",
"318243902521868288", "348651574924541953",
"349185088157777920", "378402925128712193",
"392141548932038658", "393912152173576203",
"482860581670486028", "495384759074160642",
"638988388740890635", "373336013109461013",
"530220455085473813", "454567553738473472",
"790724320824655873", "1040735082610167858",
"695946570482450442", "849737964090556488"
],
user: {
id: "113340068197859328",
username: "kumaccino",
avatar: "b48302623a12bc7c59a71328f72ccb39",
discriminator: "0",
public_flags: 128,
flags: 128,
banner: null,
accent_color: 10206929,
global_name: "kumaccino",
avatar_decoration_data: null,
banner_color: "#9bbed1"
},
mute: false,
deaf: false
},
sheep: { sheep: {
avatar: "38dd359aa12bcd52dd3164126c587f8c", avatar: "38dd359aa12bcd52dd3164126c587f8c",
communication_disabled_until: null, communication_disabled_until: null,

View file

@ -20,7 +20,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
require("../matrix/kstate.test") require("../matrix/kstate.test")
require("../matrix/api.test") require("../matrix/api.test")
require("../matrix/read-registration.test") require("../matrix/read-registration.test")
require("../matrix/txnid.test")
require("../d2m/converters/message-to-event.test") require("../d2m/converters/message-to-event.test")
require("../d2m/converters/message-to-event.embeds.test") require("../d2m/converters/message-to-event.embeds.test")
require("../d2m/converters/edit-to-changes.test") require("../d2m/converters/edit-to-changes.test")