From 21d06f25c677209ced79857cbea1912c220d798b Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Mon, 5 Jul 2021 00:56:23 +0800 Subject: [PATCH] feat(discord): support reaction events --- packages/adapter-discord/src/utils.ts | 60 +++++++++++++++++++-------- packages/adapter-discord/src/ws.ts | 9 ++-- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/packages/adapter-discord/src/utils.ts b/packages/adapter-discord/src/utils.ts index 0002e835f0..cd75de0c92 100644 --- a/packages/adapter-discord/src/utils.ts +++ b/packages/adapter-discord/src/utils.ts @@ -30,7 +30,7 @@ export const adaptAuthor = (author: DC.User): AuthorInfo => ({ nickname: author.username, }) -export async function adaptMessage(bot: DiscordBot, meta: DC.Message, session: Partial = {}) { +export function adaptMessage(bot: DiscordBot, meta: DC.Message, session: Partial = {}) { if (meta.author) { session.author = adaptAuthor(meta.author) session.userId = meta.author.id @@ -106,8 +106,8 @@ export async function adaptMessage(bot: DiscordBot, meta: DC.Message, session: P return session } -async function adaptMessageSession(bot: DiscordBot, meta: DC.Message, session: Partial = {}) { - await adaptMessage(bot, meta, session) +function adaptMessageSession(bot: DiscordBot, meta: DC.Message, session: Partial = {}) { + adaptMessage(bot, meta, session) session.messageId = meta.id session.timestamp = new Date(meta.timestamp).valueOf() || Date.now() // 遇到过 cross post 的消息在这里不会传消息 id @@ -118,6 +118,23 @@ async function adaptMessageSession(bot: DiscordBot, meta: DC.Message, session: P return session } +function prepareMessageSession(session: Partial, data: DC.Message) { + session.groupId = data.guild_id + session.subtype = data.guild_id ? 'group' : 'private' + session.channelId = data.channel_id +} + +function prepareReactionSession(session: Partial, data: any) { + session.userId = data.user_id + session.messageId = data.message_id + session.groupId = data.guild_id + session.channelId = data.channel_id + session.subtype = data.guild_id ? 'group' : 'private' + if (!data.emoji) return + const { id, name } = data.emoji + session.content = id ? `${name}:${id}` : name +} + export async function adaptSession(bot: DiscordBot, input: DC.Payload) { const session: Partial = { selfId: bot.selfId, @@ -125,31 +142,40 @@ export async function adaptSession(bot: DiscordBot, input: DC.Payload) { } if (input.t === 'MESSAGE_CREATE') { session.type = 'message' - const msg = input.d as DC.Message - session.groupId = msg.guild_id - session.subtype = msg.guild_id ? 'group' : 'private' - session.channelId = msg.channel_id - await adaptMessageSession(bot, input.d, session) + prepareMessageSession(session, input.d) + adaptMessageSession(bot, input.d, session) // dc 情况特殊 可能有 embeds 但是没有消息主体 // if (!session.content) return if (session.userId === bot.selfId) return } else if (input.t === 'MESSAGE_UPDATE') { session.type = 'message-updated' - const d = input.d as DC.Message - session.groupId = d.guild_id - session.subtype = d.guild_id ? 'group' : 'private' - session.channelId = d.channel_id - const msg = await bot.$getMessage(d.channel_id, d.id) + prepareMessageSession(session, input.d) + const msg = await bot.$getMessage(input.d.channel_id, input.d.id) // Unlike creates, message updates may contain only a subset of the full message object payload // https://discord.com/developers/docs/topics/gateway#message-update - await adaptMessageSession(bot, msg, session) + adaptMessageSession(bot, msg, session) // if (!session.content) return if (session.userId === bot.selfId) return } else if (input.t === 'MESSAGE_DELETE') { session.type = 'message-deleted' - session.messageId = input.d.id - session.groupId = input.d.guild_id - session.channelId = input.d.channel_id + prepareMessageSession(session, input.d) + } else if (input.t === 'MESSAGE_REACTION_ADD') { + session.type = 'reaction-added' + prepareReactionSession(session, input.d) + } else if (input.t === 'MESSAGE_REACTION_REMOVE') { + session.type = 'reaction-deleted' + session.subtype = 'one' + prepareReactionSession(session, input.d) + } else if (input.t === 'MESSAGE_REACTION_REMOVE_ALL') { + session.type = 'reaction-deleted' + session.subtype = 'all' + prepareReactionSession(session, input.d) + } else if (input.t === 'MESSAGE_REACTION_REMOVE_EMOJI') { + session.type = 'reaction-deleted' + session.subtype = 'emoji' + prepareReactionSession(session, input.d) + } else { + return } return new Session(bot.app, session) } diff --git a/packages/adapter-discord/src/ws.ts b/packages/adapter-discord/src/ws.ts index 8124e5151a..bab70e955f 100644 --- a/packages/adapter-discord/src/ws.ts +++ b/packages/adapter-discord/src/ws.ts @@ -6,7 +6,7 @@ import WebSocket from 'ws' const logger = new Logger('discord') -// https://discord.com/developers/docs/topics/gateway +/** https://discord.com/developers/docs/topics/gateway */ export default class WsClient extends Adapter.WsClient<'discord'> { constructor(app: App) { super(app, DiscordBot, app.options.discord) @@ -59,10 +59,13 @@ export default class WsClient extends Adapter.WsClient<'discord'> { token: bot.token, properties: {}, compress: false, - intents: (1 << 9) + (1 << 12), + // https://discord.com/developers/docs/topics/gateway#gateway-intents + intents: (1 << 9) + (1 << 10) + (1 << 12) + (1 << 13), }, })) - } else if (parsed.op === Opcode.Dispatch) { + } + + if (parsed.op === Opcode.Dispatch) { if (parsed.t === 'READY') { bot._sessionId = parsed.d.session_id const self: any = adaptUser(parsed.d.user)