diff --git a/adapters/dingtalk/src/bot.ts b/adapters/dingtalk/src/bot.ts index 8d73a5d0..fd87f5a0 100644 --- a/adapters/dingtalk/src/bot.ts +++ b/adapters/dingtalk/src/bot.ts @@ -12,11 +12,12 @@ export class DingtalkBot extends Bot { public oldHttp: Quester public http: Quester public internal: Internal - refreshTokenTimer: NodeJS.Timeout + private refreshTokenTimer: NodeJS.Timeout constructor(ctx: Context, config: DingtalkBot.Config) { super(ctx, config) this.platform = 'dingtalk' + this.selfId = config.appkey this.http = ctx.http.extend(config.api) this.oldHttp = ctx.http.extend(config.oldApi) this.internal = new Internal(this) @@ -28,15 +29,15 @@ export class DingtalkBot extends Bot { } } - async initialize() { + async getLogin() { const { appList } = await this.internal.OapiMicroappList() const self = appList.find(v => v.agentId === this.config.agentId) - this.username = self.name - this.avatar = self.appIcon + this.user.name = self.name + this.user.avatar = self.appIcon + return { status: this.status, user: this.user } } - // @ts-ignore - stop(): Promise { + async stop() { clearTimeout(this.refreshTokenTimer) } @@ -61,7 +62,8 @@ export class DingtalkBot extends Bot { // https://open.dingtalk.com/document/orgapp/download-the-file-content-of-the-robot-receiving-message async downloadFile(downloadCode: string): Promise { const { downloadUrl } = await this.internal.robotMessageFileDownload({ - downloadCode, robotCode: this.selfId, + downloadCode, + robotCode: this.selfId, }) return downloadUrl } diff --git a/adapters/dingtalk/src/http.ts b/adapters/dingtalk/src/http.ts index a9af42fe..a09c8b11 100644 --- a/adapters/dingtalk/src/http.ts +++ b/adapters/dingtalk/src/http.ts @@ -12,8 +12,7 @@ export class HttpServer extends Adapter.Server { async start(bot: DingtalkBot) { await bot.refreshToken() - bot.selfId = bot.config.appkey - await bot.initialize() + await bot.getLogin() // https://open.dingtalk.com/document/orgapp/receive-message bot.ctx.router.post('/dingtalk', async (ctx) => { const timestamp = ctx.get('timestamp') diff --git a/adapters/dingtalk/src/message.ts b/adapters/dingtalk/src/message.ts index b6ac9421..f4ce7a8e 100644 --- a/adapters/dingtalk/src/message.ts +++ b/adapters/dingtalk/src/message.ts @@ -52,7 +52,6 @@ export class DingtalkMessageEncoder extends MessageEncoder { session.messageId = processQueryKey session.channelId = this.session.channelId session.guildId = this.session.guildId - console.log(session, processQueryKey) session.app.emit(session, 'send', session) this.results.push(session) } diff --git a/adapters/dingtalk/src/utils.ts b/adapters/dingtalk/src/utils.ts index ffc2d09d..83264b79 100644 --- a/adapters/dingtalk/src/utils.ts +++ b/adapters/dingtalk/src/utils.ts @@ -6,17 +6,27 @@ export async function decodeMessage(bot: DingtalkBot, body: Message): Promise v.dingtalkId !== body.chatbotUserId).map(v => h.at(v.staffId)) + session.elements = [h.at(body.robotCode), ...atUsers, ...session.elements] + session.channelId = body.conversationId + } + if (body.conversationTitle) { + session.data.channel.name = body.conversationTitle + } + + session.data.user = { + id: body.senderStaffId, + name: body.senderNick, + } + session.data.member = { roles: body.isAdmin ? ['admin'] : [], } - session.timestamp = Number(body.createAt) + session.timestamp = +body.createAt if (body.msgtype === 'text') { session.elements = [h.text(body.text.content)] } else if (body.msgtype === 'richText') { @@ -36,14 +46,6 @@ export async function decodeMessage(bot: DingtalkBot, body: Message): Promise v.dingtalkId !== body.chatbotUserId).map(v => h.at(v.staffId)) - session.elements = [h.at(body.robotCode), ...atUsers, ...session.elements] - session.channelId = body.conversationId - } else { - session.channelId = session.userId - } session.content = session.elements.join('') return session } diff --git a/adapters/dingtalk/src/ws.ts b/adapters/dingtalk/src/ws.ts index ba3d853d..291e2228 100644 --- a/adapters/dingtalk/src/ws.ts +++ b/adapters/dingtalk/src/ws.ts @@ -5,8 +5,7 @@ import { decodeMessage } from './utils' export class WsClient extends Adapter.WsClient { async prepare() { await this.bot.refreshToken() - this.bot.selfId = this.bot.config.appkey - await this.bot.initialize() + await this.bot.getLogin() const { endpoint, ticket } = await this.bot.http.post<{ endpoint: string ticket: string diff --git a/adapters/discord/src/bot.ts b/adapters/discord/src/bot.ts index 26a0165e..e9cefea6 100644 --- a/adapters/discord/src/bot.ts +++ b/adapters/discord/src/bot.ts @@ -1,4 +1,4 @@ -import { Bot, Context, defineProperty, Fragment, h, isNullable, Logger, Quester, Schema, SendOptions, Universal } from '@satorijs/satori' +import { Bot, Context, defineProperty, Fragment, h, isNullable, Logger, Quester, Schema, Universal } from '@satorijs/satori' import * as Discord from './utils' import { DiscordMessageEncoder } from './message' import { Internal, Webhook } from './types' @@ -93,7 +93,7 @@ export class DiscordBot extends Bot { async getMessageList(channelId: string, before?: string) { const messages = await this.internal.getChannelMessages(channelId, { before, limit: 100 }) const data = await Promise.all(messages.reverse().map(data => Discord.decodeMessage(this, data, {}, false))) - return { data, next: data[0]?.messageId } + return { data, next: data[0]?.id } } async getUser(userId: string) { @@ -188,7 +188,7 @@ export class DiscordBot extends Bot { return this.internal.deleteGuildRole(guildId, roleId) } - async sendPrivateMessage(userId: string, content: Fragment, options?: SendOptions) { + async sendPrivateMessage(userId: string, content: Fragment, options?: Universal.SendOptions) { const channel = await this.internal.createDM({ recipient_id: userId, }) diff --git a/adapters/discord/src/utils.ts b/adapters/discord/src/utils.ts index 2f2d04c7..d4603b56 100644 --- a/adapters/discord/src/utils.ts +++ b/adapters/discord/src/utils.ts @@ -23,7 +23,7 @@ export const decodeUser = (user: Discord.User): Universal.User => ({ export const decodeGuildMember = (member: Discord.GuildMember): Universal.GuildMember => ({ ...decodeUser(member.user), user: decodeUser(member.user), - nickname: member.nick, + name: member.nick, roles: member.roles, avatar: member.user.avatar, }) @@ -36,6 +36,7 @@ export const decodeGuild = (data: Discord.Guild): Universal.Guild => ({ export const decodeChannel = (data: Discord.Channel): Universal.Channel => ({ id: data.id, name: data.name, + type: data.type === Discord.Channel.Type.DM ? Universal.Channel.Type.DIRECT : Universal.Channel.Type.TEXT, }) export const decodeAuthor = (author: Discord.User): Universal.Author => ({ diff --git a/adapters/kook/src/bot.ts b/adapters/kook/src/bot.ts index 39a2d95d..64f907a0 100644 --- a/adapters/kook/src/bot.ts +++ b/adapters/kook/src/bot.ts @@ -1,4 +1,4 @@ -import { Bot, Context, Fragment, h, Quester, Schema, SendOptions, Universal } from '@satorijs/satori' +import { Bot, Context, Fragment, h, Quester, Schema, Universal } from '@satorijs/satori' import { adaptGroup, adaptMessage, adaptUser, decodeGuildMember, decodeRole, encodeRole } from './utils' import * as Kook from './types' import FormData from 'form-data' @@ -80,11 +80,9 @@ export class KookBot extends Bot { } } - async getSelf() { - const data = adaptUser(await this.request('GET', '/user/me')) - data['selfId'] = data.userId - delete data.userId - return data + async getLogin() { + this.user = adaptUser(await this.request('GET', '/user/me')) + return { status: this.status, user: this.user } } async getGuildList() { @@ -109,7 +107,7 @@ export class KookBot extends Bot { await this.request('POST', '/guild/kickout', { guild_id, user_id }) } - async sendPrivateMessage(userId: string, content: Fragment, options?: SendOptions) { + async sendPrivateMessage(userId: string, content: Fragment, options?: Universal.SendOptions) { const { code } = await this.request('POST', '/user-chat/create', { target_id: userId }) return this.sendMessage(code, content, null, options) } diff --git a/adapters/kook/src/http.ts b/adapters/kook/src/http.ts index 1c29039a..c90e2fd6 100644 --- a/adapters/kook/src/http.ts +++ b/adapters/kook/src/http.ts @@ -30,7 +30,7 @@ export class HttpServer extends Adapter.Server ({ export const decodeGuildMember = (member: Kook.Author): Universal.GuildMember => ({ ...adaptUser(member), user: adaptUser(member), - nickname: member.nickname, + name: member.nickname, }) export const adaptAuthor = (author: Kook.Author): Universal.Author => ({ ...adaptUser(author), - nickname: author.nickname, + name: author.nickname, }) export const decodeRole = (role: Kook.GuildRole): Universal.GuildRole => ({ diff --git a/adapters/kook/src/ws.ts b/adapters/kook/src/ws.ts index 749b8e77..f5992327 100644 --- a/adapters/kook/src/ws.ts +++ b/adapters/kook/src/ws.ts @@ -53,7 +53,7 @@ export class WsClient extends Adapter.WsClient { if (session) bot.dispatch(session) } else if (parsed.s === Signal.hello) { this._heartbeat = setInterval(() => this.heartbeat(bot), Time.minute * 0.5) - Object.assign(bot, await bot.getSelf()) + await bot.getLogin() bot.online() } else if (parsed.s === Signal.pong) { clearTimeout(this._ping) diff --git a/adapters/qqguild/src/bot.ts b/adapters/qqguild/src/bot.ts index e78120c8..ffa6ca7a 100644 --- a/adapters/qqguild/src/bot.ts +++ b/adapters/qqguild/src/bot.ts @@ -16,11 +16,9 @@ export class QQGuildBot extends Bot { ctx.plugin(WsClient, this) } - async getSelf() { - const user = adaptUser(await this.internal.me) - user['selfId'] = user.userId - delete user.userId - return user + async getLogin() { + this.user = adaptUser(await this.internal.me) + return { status: this.status, user: this.user } } async getGuildList() { diff --git a/adapters/qqguild/src/ws.ts b/adapters/qqguild/src/ws.ts index 2a461ddd..b4661c99 100644 --- a/adapters/qqguild/src/ws.ts +++ b/adapters/qqguild/src/ws.ts @@ -3,7 +3,7 @@ import { QQGuildBot } from './bot' export class WsClient extends Adapter.Client { async start(bot: QQGuildBot) { - Object.assign(bot, await bot.getSelf()) + await bot.getLogin() await bot.internal.startClient(bot.config.intents) bot.internal.on('ready', bot.online.bind(bot)) bot.internal.on('message', msg => { diff --git a/packages/core/src/bot.ts b/packages/core/src/bot.ts index 85dd9117..423b46cb 100644 --- a/packages/core/src/bot.ts +++ b/packages/core/src/bot.ts @@ -16,6 +16,7 @@ export abstract class Bot { static filter = false static MessageEncoder?: new (bot: Bot, channelId: string, guildId?: string, options?: SendOptions) => MessageEncoder + public user = {} as User public isBot = true public hidden = false public platform: string diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index 09460de5..c4a38681 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -1,7 +1,7 @@ import { defineProperty, isNullable } from 'cosmokit' import { Context } from '.' import { Bot } from './bot' -import { Channel, EventData, h } from '@satorijs/protocol' +import { Channel, EventData, h, Message } from '@satorijs/protocol' declare module '@satorijs/protocol' { interface SendOptions { @@ -9,6 +9,19 @@ declare module '@satorijs/protocol' { } } +export interface Session { + type: string + subtype: string + subsubtype: string + timestamp: number + userId: string + channelId: string + guildId: string + messageId: string + roleId: string + quote: Message +} + export class Session { static counter = 0 @@ -42,36 +55,12 @@ export class Session { return this.data.channel.type === Channel.Type.DIRECT } - get author() { - return { user: this.data.user, ...this.data.user, ...this.data.member } - } - - get type() { - return this.data.type + set isDirect(value) { + (this.data.channel ??= {} as Channel).type = value ? Channel.Type.DIRECT : Channel.Type.TEXT } - set type(value) { - this.data.type = value - } - - get userId() { - return this.data.user?.id - } - - get channelId() { - return this.data.channel?.id - } - - get guildId() { - return this.data.guild?.id - } - - get messageId() { - return this.data.message?.id - } - - get quote() { - return this.data.message?.quote + get author() { + return { user: this.data.user, ...this.data.user, ...this.data.member } } get uid() { @@ -121,4 +110,28 @@ export class Session { toJSON(): EventData { return { ...this.data, id: this.id } } + + static accessor(name: string, keys: string[]) { + Object.defineProperty(Session.prototype, name, { + get() { + return keys.reduce((data, key) => data?.[key], this.data) + }, + set(value) { + const last = keys.pop() + const data = keys.reduce((data, key) => data[key] ??= {}, this.data) + data[last] = value + }, + }) + } } + +Session.accessor('type', ['type']) +Session.accessor('subtype', ['subtype']) +Session.accessor('subsubtype', ['subsubtype']) +Session.accessor('timestamp', ['timestamp']) +Session.accessor('userId', ['user', 'id']) +Session.accessor('channelId', ['channel', 'id']) +Session.accessor('guildId', ['guild', 'id']) +Session.accessor('messageId', ['message', 'id']) +Session.accessor('roleId', ['role', 'id']) +Session.accessor('quote', ['message', 'quote']) diff --git a/packages/protocol/src/index.ts b/packages/protocol/src/index.ts index f87969ad..3b426f3b 100644 --- a/packages/protocol/src/index.ts +++ b/packages/protocol/src/index.ts @@ -75,7 +75,7 @@ export interface Methods { getReactionIter(channelId: string, messageId: string, emoji: string): AsyncIterable // user - getSelf(): Promise + getLogin(): Promise getUser(userId: string, guildId?: string): Promise getFriendList(next?: string): Promise> getFriendIter(): AsyncIterable