From 4c68dc235aabd5af9b938ce4276b87a35aa0826a Mon Sep 17 00:00:00 2001 From: bili22 Date: Tue, 16 Jul 2024 16:00:58 +0800 Subject: [PATCH] feat: update qq adapter, support new auth (#290) --- adapters/qq/src/bot/guild.ts | 4 +-- adapters/qq/src/bot/index.ts | 23 +++++++++------ adapters/qq/src/internal/group.ts | 9 +++++- adapters/qq/src/message.ts | 47 ++++++++++++++++--------------- adapters/qq/src/types.ts | 1 + adapters/qq/src/utils.ts | 2 +- adapters/qq/src/ws.ts | 12 ++++---- 7 files changed, 58 insertions(+), 40 deletions(-) diff --git a/adapters/qq/src/bot/guild.ts b/adapters/qq/src/bot/guild.ts index 46bc29f3..0d5e1131 100644 --- a/adapters/qq/src/bot/guild.ts +++ b/adapters/qq/src/bot/guild.ts @@ -22,8 +22,8 @@ export class QQGuildBot extends Bot { this.parent = config.parent this.parent.guildBot = this this.platform = 'qqguild' - this.internal = new GuildInternal(this, () => config.parent.guildHttp) - this.http = config.parent.guildHttp + this.internal = new GuildInternal(this, () => config.parent.http) + this.http = config.parent.http } get status() { diff --git a/adapters/qq/src/bot/index.ts b/adapters/qq/src/bot/index.ts index a92d9b76..6b3f796f 100644 --- a/adapters/qq/src/bot/index.ts +++ b/adapters/qq/src/bot/index.ts @@ -18,7 +18,6 @@ export class QQBot extends Bot { internal: GroupInternal http: HTTP - guildHttp: HTTP private _token: string private _timer: NodeJS.Timeout @@ -29,12 +28,16 @@ export class QQBot extends Bot { if (config.sandbox) { endpoint = endpoint.replace(/^(https?:\/\/)/, '$1sandbox.') } - this.guildHttp = ctx.http.extend({ - endpoint, - headers: { - 'Authorization': `Bot ${this.config.id}.${this.config.token}`, - }, - }) + // 如果是 bot 类型, 使用固定 token + if (this.config.authType === 'bot') { + this.http = this.ctx.http.extend({ + endpoint, + headers: { + 'Authorization': `Bot ${this.config.id}.${this.config.token}`, + 'X-Union-Appid': this.config.id, + }, + }) + } this.ctx.plugin(QQGuildBot, { parent: this, @@ -126,6 +129,7 @@ export namespace QQBot { export interface Config extends QQ.Options, WsClient.Options { intents?: number retryWhen: number[] + manualAcknowledge: boolean } export const Config: Schema = Schema.intersect([ @@ -136,10 +140,13 @@ export namespace QQBot { type: Schema.union(['public', 'private'] as const).description('机器人类型。').required(), sandbox: Schema.boolean().description('是否开启沙箱模式。').default(false), endpoint: Schema.string().role('link').description('要连接的服务器地址。').default('https://api.sgroup.qq.com/'), - authType: Schema.union(['bot', 'bearer'] as const).description('采用的验证方式。').default('bot'), + authType: Schema.union(['bot', 'bearer'] as const).description('采用的验证方式。').default('bearer'), intents: Schema.bitset(QQ.Intents).description('需要订阅的机器人事件。'), retryWhen: Schema.array(Number).description('发送消息遇到平台错误码时重试。').default([]), }), WsClient.Options, + Schema.object({ + manualAcknowledge: Schema.boolean().description('手动响应回调消息。').default(false), + }).description('高级设置'), ] as const) } diff --git a/adapters/qq/src/internal/group.ts b/adapters/qq/src/internal/group.ts index 1c911dd4..56cd5f62 100644 --- a/adapters/qq/src/internal/group.ts +++ b/adapters/qq/src/internal/group.ts @@ -11,7 +11,14 @@ declare module './internal' { message: string data: any }> - sendPrivateMessage(openid: string, data: QQ.Message.Request): Promise + sendPrivateMessage(openid: string, data: QQ.Message.Request): Promise<{ + id: string + timestamp: string + } & { + code: number + message: string + data: any + }> sendFilePrivate(openid: string, data: QQ.Message.File.Request): Promise sendFileGuild(group_openid: string, data: QQ.Message.File.Request): Promise acknowledgeInteraction(interaction_id: string, data: { diff --git a/adapters/qq/src/message.ts b/adapters/qq/src/message.ts index 9235f782..e3b360b7 100644 --- a/adapters/qq/src/message.ts +++ b/adapters/qq/src/message.ts @@ -193,6 +193,7 @@ export class QQMessageEncoder extends MessageEncode private content: string = '' private passiveId: string private passiveSeq: number + private passiveEventId: string private useMarkdown = false private rows: QQ.Button[][] = [] private attachedFile: QQ.Message.File.Response @@ -202,19 +203,23 @@ export class QQMessageEncoder extends MessageEncode async flush() { if (!this.content.trim() && !this.rows.flat().length && !this.attachedFile) return this.trimButtons() - let msg_id: string, msg_seq: number + let msg_id: string, msg_seq: number, event_id: string if (this.options?.session?.messageId && Date.now() - this.options.session.timestamp < MSG_TIMEOUT) { this.options.session['seq'] ||= 0 msg_id = this.options.session.messageId msg_seq = ++this.options.session['seq'] + } else if (this.options?.session?.qq['id'] && Date.now() - this.options.session.timestamp < MSG_TIMEOUT) { + event_id = this.options.session.qq['id'] } if (this.passiveId) msg_id = this.passiveId if (this.passiveSeq) msg_seq = this.passiveSeq + if (this.passiveEventId) event_id = this.passiveEventId const data: QQ.Message.Request = { content: this.content, msg_type: QQ.Message.Type.TEXT, msg_id, msg_seq, + event_id, } if (this.attachedFile) { if (!data.content.length) data.content = ' ' @@ -240,27 +245,24 @@ export class QQMessageEncoder extends MessageEncode session.type = 'send' const send = async () => { try { - if (this.session.isDirect) { - const { sendResult: { msg_id } } = await this.bot.internal.sendPrivateMessage(this.session.channelId, data) - session.messageId = msg_id - } else { - const resp = await this.bot.internal.sendMessage(this.session.channelId, data) - if (resp.id) { - session.messageId = resp.id - session.timestamp = new Date(resp.timestamp).valueOf() - session.channelId = this.session.channelId - session.guildId = this.session.guildId + const resp = this.session.isDirect + ? await this.bot.internal.sendPrivateMessage(this.session.channelId, data) + : await this.bot.internal.sendMessage(this.session.channelId, data) + if (resp.id) { + session.messageId = resp.id + session.timestamp = new Date(resp.timestamp).valueOf() + session.channelId = this.session.channelId + session.guildId = this.session.guildId + session.app.emit(session, 'send', session) + this.results.push(session.event.message) + } else if (resp.code === 304023 && this.bot.config.intents & QQ.Intents.MESSAGE_AUDIT) { + try { + const auditData: QQ.MessageAudited = await this.audit(resp.data.message_audit.audit_id) + session.messageId = auditData.message_id session.app.emit(session, 'send', session) this.results.push(session.event.message) - } else if (resp.code === 304023 && this.bot.config.intents & QQ.Intents.MESSAGE_AUDIT) { - try { - const auditData: QQ.MessageAudited = await this.audit(resp.data.message_audit.audit_id) - session.messageId = auditData.message_id - session.app.emit(session, 'send', session) - this.results.push(session.event.message) - } catch (e) { - this.bot.logger.error(e) - } + } catch (e) { + this.bot.logger.error(e) } } } catch (e) { @@ -386,8 +388,9 @@ export class QQMessageEncoder extends MessageEncode if (type === 'text') { this.content += attrs.content } else if (type === 'passive') { - this.passiveId = attrs.messageId - this.passiveSeq = Number(attrs.seq) + if (attrs.messageId) this.passiveId = attrs.messageId + if (attrs.seq) this.passiveSeq = Number(attrs.seq) + if (attrs.eventId) this.passiveEventId = attrs.eventId } else if ((type === 'img' || type === 'image') && (attrs.src || attrs.url)) { await this.flush() const data = await this.sendFile(type, attrs) diff --git a/adapters/qq/src/types.ts b/adapters/qq/src/types.ts index b63946df..32357c71 100644 --- a/adapters/qq/src/types.ts +++ b/adapters/qq/src/types.ts @@ -193,6 +193,7 @@ export interface GetGatewayBotResponse { } export interface PayloadStructure { + id: string /** opcode for the payload */ op: O /** event data */ diff --git a/adapters/qq/src/utils.ts b/adapters/qq/src/utils.ts index 405d42de..6f900630 100644 --- a/adapters/qq/src/utils.ts +++ b/adapters/qq/src/utils.ts @@ -216,7 +216,7 @@ export async function adaptSession(bot: QQBot, i // {message: 'get header appid failed', code: 630006} // {"message":"check app privilege not pass","code":11253 - bot.internal.acknowledgeInteraction(input.d.id, { code: 0 }).catch(() => { }) + if (!bot.config.manualAcknowledge) bot.internal.acknowledgeInteraction(input.d.id, { code: 0 }).catch(() => { }) } else if (input.t === 'GUILD_MEMBER_ADD' || input.t === 'GUILD_MEMBER_DELETE' || input.t === 'GUILD_MEMBER_UPDATE') { session.type = { GUILD_MEMBER_ADD: 'guild-member-added', diff --git a/adapters/qq/src/ws.ts b/adapters/qq/src/ws.ts index 7f8f91c9..8ef56cb7 100644 --- a/adapters/qq/src/ws.ts +++ b/adapters/qq/src/ws.ts @@ -9,7 +9,7 @@ export class WsClient extends Adapter.WsClient extends Adapter.WsClient extends Adapter.WsClient