diff --git a/packages/adapter-discord/src/bot.ts b/packages/adapter-discord/src/bot.ts index 3b069d3260..d0cd752476 100644 --- a/packages/adapter-discord/src/bot.ts +++ b/packages/adapter-discord/src/bot.ts @@ -9,6 +9,18 @@ import { segment } from 'koishi-utils' import FormData from 'form-data' import FileType from 'file-type' +export class SenderError extends Error { + constructor(url: string, data: any, selfId: string) { + super(`Error when trying to request ${url}, data: ${JSON.stringify(data)}`) + Object.defineProperties(this, { + name: { value: 'SenderError' }, + selfId: { value: selfId }, + data: { value: data }, + url: { value: url }, + }) + } +} + export class DiscordBot extends Bot<'discord'> { _d = 0 version = 'discord' @@ -21,15 +33,19 @@ export class DiscordBot extends Bot<'discord'> { const headers: Record = { Authorization: `Bot ${this.token}`, } - const response = await axios({ - ...axiosConfig, - ...discord.axiosConfig, - method, - url, - headers: { ...headers, ...exHeaders }, - data, - }) - return response.data + try { + const response = await axios({ + ...axiosConfig, + ...discord.axiosConfig, + method, + url, + headers: { ...headers, ...exHeaders }, + data, + }) + return response.data + } catch (e) { + throw new SenderError(url, data, this.selfId) + } } async getSelf() { @@ -63,7 +79,7 @@ export class DiscordBot extends Bot<'discord'> { delete addition.content async function sendMessage() { const r = await that.request('POST', requestUrl, { - content: needSend, + content: needSend.trim(), ...addition, }) sentMessageId = r.id @@ -72,7 +88,7 @@ export class DiscordBot extends Bot<'discord'> { for (const code of chain) { const { type, data } = code if (type === 'text') { - needSend += data.content + needSend += data.content.trim() } else if (type === 'at' && data.id) { needSend += `<@${data.id}>` } else if (type === 'at' && data.type === 'all') { @@ -84,7 +100,7 @@ export class DiscordBot extends Bot<'discord'> { } else if (type === 'face' && data.name && data.id) { needSend += `<:${data.name}:${data.id}>` } else { - if (needSend) await sendMessage() + if (needSend.trim()) await sendMessage() if (type === 'share') { const sendData = isWebhook ? { embeds: [{ ...addition, ...data }], @@ -109,18 +125,22 @@ export class DiscordBot extends Bot<'discord'> { }) sentMessageId = r.id } else { - const a = await axios.get(data.url, { - responseType: 'arraybuffer', - }) - const r = await this.sendEmbedMessage(requestUrl, a.data, { - ...addition, - }) - sentMessageId = r.id + try { + const a = await axios.get(data.url, { + responseType: 'arraybuffer', + }) + const r = await this.sendEmbedMessage(requestUrl, a.data, { + ...addition, + }) + sentMessageId = r.id + } catch (e) { + throw new SenderError(data.url, data, this.selfId) + } } } } } - if (needSend) await sendMessage() + if (needSend.trim()) await sendMessage() return sentMessageId } @@ -155,12 +175,12 @@ export class DiscordBot extends Bot<'discord'> { }) } - async getMessageFromServer(channelId: string, messageId: string) { + async $getMessage(channelId: string, messageId: string) { return this.request('GET', `/channels/${channelId}/messages/${messageId}`) } async getMessage(channelId: string, messageId: string): Promise { - const msg = await this.getMessageFromServer(channelId, messageId) + const msg = await this.$getMessage(channelId, messageId) const result: MessageInfo = { messageId: msg.id, channelId: msg.channel_id, @@ -172,7 +192,7 @@ export class DiscordBot extends Bot<'discord'> { } result.author.nickname = msg.member?.nick if (msg.message_reference) { - const quoteMsg = await this.getMessageFromServer(msg.message_reference.channel_id, msg.message_reference.message_id) + const quoteMsg = await this.$getMessage(msg.message_reference.channel_id, msg.message_reference.message_id) result.quote = await adaptMessage(this, quoteMsg) } return result diff --git a/packages/adapter-discord/src/index.ts b/packages/adapter-discord/src/index.ts index 106da66e85..f7b5283a50 100644 --- a/packages/adapter-discord/src/index.ts +++ b/packages/adapter-discord/src/index.ts @@ -2,8 +2,7 @@ import { Adapter } from 'koishi-core' import { AxiosRequestConfig } from 'axios' import { DiscordBot } from './bot' import WsClient from './ws' -import { Embed } from './types' - +import * as dc from './types' export * from './bot' export * as dc from './types' @@ -16,9 +15,12 @@ declare module 'koishi-core' { discord?: DiscordOptions } - interface Session { + interface Session { discord?: { - embeds: Embed[] + mentions: dc.User[]; + // eslint-disable-next-line camelcase + webhook_id?: dc.snowflake + flags: number } } diff --git a/packages/adapter-discord/src/types.ts b/packages/adapter-discord/src/types.ts index ca0bf6ba04..3dd6b50703 100644 --- a/packages/adapter-discord/src/types.ts +++ b/packages/adapter-discord/src/types.ts @@ -45,7 +45,7 @@ export type Payload = { s?: number } -type snowflake = string +export type snowflake = string /** https://discord.com/developers/docs/resources/emoji#emoji-object */ export interface Emoji { @@ -357,14 +357,25 @@ export interface ModifyGuildMember extends Pick>) { - session.groupId = meta.guild_id - session.subtype = meta.guild_id ? 'group' : 'private' - session.channelId = meta.channel_id - await adaptMessageSession(bot, meta, session) -} - export async function adaptSession(bot: DiscordBot, input: DC.Payload) { const session: Partial> = { selfId: bot.selfId, @@ -125,17 +117,25 @@ export async function adaptSession(bot: DiscordBot, input: DC.Payload) { } if (input.t === 'MESSAGE_CREATE') { session.type = 'message' - await adaptMessageCreate(bot, input.d as DC.Message, session) - if (!session.content) return + 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) + // 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 - const msg = await bot.getMessageFromServer(d.channel_id, d.id) + 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) // 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 adaptMessageCreate(bot, msg, session) - if (!session.content) return + await adaptMessageSession(bot, msg, session) + // if (!session.content) return if (session.userId === bot.selfId) return } else if (input.t === 'MESSAGE_DELETE') { session.type = 'message-deleted'