diff --git a/d2m/discord-command-handler.js b/d2m/discord-command-handler.js new file mode 100644 index 0000000..9f96c18 --- /dev/null +++ b/d2m/discord-command-handler.js @@ -0,0 +1,81 @@ +// @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") + +const prefix = "/" + +/** + * @callback CommandExecute + * @param {DiscordTypes.GatewayMessageCreateDispatchData} message + * @param {DiscordTypes.APIGuildTextChannel} channel + * @param {DiscordTypes.APIGuild} guild + * @param {any} [ctx] + */ + +/** + * @typedef Command + * @property {string[]} aliases + * @property {(message: DiscordTypes.GatewayMessageCreateDispatchData, channel: DiscordTypes.APIGuildTextChannel, guild: DiscordTypes.APIGuild) => Promise} 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) => { + 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." + }) + const avatarEvent = await api.getStateEvent(roomID, "m.room.avatar", "") + const avatarURL = avatarEvent?.url + return discord.snow.channel.createMessage(channel.id, { + ...ctx, + content: `Current room avatar: ${avatarURL}` + }) + } + ) +}, { + aliases: ["invite"], + execute: replyctx( + async (message, channel, guild, ctx) => { + 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.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 diff --git a/d2m/event-dispatcher.js b/d2m/event-dispatcher.js index 9bb07c0..91a7cba 100644 --- a/d2m/event-dispatcher.js +++ b/d2m/event-dispatcher.js @@ -18,6 +18,8 @@ const createRoom = sync.require("./actions/create-room") const createSpace = sync.require("./actions/create-space") /** @type {import("../matrix/api")}) */ const api = sync.require("../matrix/api") +/** @type {import("./discord-command-handler")}) */ +const discordCommandHandler = sync.require("./discord-command-handler") let lastReportedEvent = 0 @@ -156,7 +158,11 @@ module.exports = { if (!channel.guild_id) return // Nothing we can do in direct messages. const guild = client.guilds.get(channel.guild_id) if (!isGuildAllowed(guild.id)) return - await sendMessage.sendMessage(message, guild) + + await Promise.all([ + sendMessage.sendMessage(message, guild), + discordCommandHandler.execute(message, channel, guild) + ]) }, /** diff --git a/matrix/api.js b/matrix/api.js index 2e0763e..7253a1a 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -190,6 +190,7 @@ module.exports.inviteToRoom = inviteToRoom module.exports.leaveRoom = leaveRoom module.exports.getEvent = getEvent module.exports.getAllState = getAllState +module.exports.getStateEvent = getStateEvent module.exports.getJoinedMembers = getJoinedMembers module.exports.sendState = sendState module.exports.sendEvent = sendEvent