Skip to content

Commit

Permalink
feat(core): login structure
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Sep 25, 2023
1 parent dcc50d3 commit 2e42d38
Show file tree
Hide file tree
Showing 16 changed files with 90 additions and 78 deletions.
16 changes: 9 additions & 7 deletions adapters/dingtalk/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ export class DingtalkBot extends Bot<DingtalkBot.Config> {
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)
Expand All @@ -28,15 +29,15 @@ export class DingtalkBot extends Bot<DingtalkBot.Config> {
}
}

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<void> {
async stop() {
clearTimeout(this.refreshTokenTimer)
}

Expand All @@ -61,7 +62,8 @@ export class DingtalkBot extends Bot<DingtalkBot.Config> {
// https://open.dingtalk.com/document/orgapp/download-the-file-content-of-the-robot-receiving-message
async downloadFile(downloadCode: string): Promise<string> {
const { downloadUrl } = await this.internal.robotMessageFileDownload({
downloadCode, robotCode: this.selfId,
downloadCode,
robotCode: this.selfId,
})
return downloadUrl
}
Expand Down
3 changes: 1 addition & 2 deletions adapters/dingtalk/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ export class HttpServer extends Adapter.Server<DingtalkBot> {

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')
Expand Down
1 change: 0 additions & 1 deletion adapters/dingtalk/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export class DingtalkMessageEncoder extends MessageEncoder<DingtalkBot> {
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)
}
Expand Down
32 changes: 17 additions & 15 deletions adapters/dingtalk/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@ export async function decodeMessage(bot: DingtalkBot, body: Message): Promise<Se
const session = bot.session()
session.type = 'message'
session.messageId = body.msgId
session.isDirect = body.conversationType === '1'
session.guildId = body.chatbotCorpId

if (body.conversationTitle) session.channelName = body.conversationTitle
session.userId = body.senderStaffId
session.author = {
userId: body.senderStaffId,
username: body.senderNick,
if (body.conversationType === '1') {
session.channelId = session.userId
} else {
const atUsers = body.atUsers.filter(v => 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') {
Expand All @@ -36,14 +46,6 @@ export async function decodeMessage(bot: DingtalkBot, body: Message): Promise<Se
} else {
return
}
if (!session.isDirect) {
// group message
const atUsers = body.atUsers.filter(v => 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
}
3 changes: 1 addition & 2 deletions adapters/dingtalk/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { decodeMessage } from './utils'
export class WsClient extends Adapter.WsClient<DingtalkBot> {
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
Expand Down
6 changes: 3 additions & 3 deletions adapters/discord/src/bot.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -93,7 +93,7 @@ export class DiscordBot extends Bot<DiscordBot.Config> {
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) {
Expand Down Expand Up @@ -188,7 +188,7 @@ export class DiscordBot extends Bot<DiscordBot.Config> {
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,
})
Expand Down
3 changes: 2 additions & 1 deletion adapters/discord/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
Expand All @@ -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 => ({
Expand Down
12 changes: 5 additions & 7 deletions adapters/kook/src/bot.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -80,11 +80,9 @@ export class KookBot<T extends KookBot.Config = KookBot.Config> extends Bot<T> {
}
}

async getSelf() {
const data = adaptUser(await this.request<Kook.Self>('GET', '/user/me'))
data['selfId'] = data.userId
delete data.userId
return data
async getLogin() {
this.user = adaptUser(await this.request<Kook.Self>('GET', '/user/me'))
return { status: this.status, user: this.user }
}

async getGuildList() {
Expand All @@ -109,7 +107,7 @@ export class KookBot<T extends KookBot.Config = KookBot.Config> extends Bot<T> {
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)
}
Expand Down
2 changes: 1 addition & 1 deletion adapters/kook/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class HttpServer extends Adapter.Server<KookBot<KookBot.BaseConfig & Http
}

async start(bot: KookBot) {
Object.assign(bot, await bot.getSelf())
await bot.getLogin()
bot.online()
}
}
Expand Down
4 changes: 2 additions & 2 deletions adapters/kook/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ export const adaptUser = (user: Kook.User): Universal.User => ({
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 => ({
Expand Down
2 changes: 1 addition & 1 deletion adapters/kook/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class WsClient extends Adapter.WsClient<KookBot> {
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)
Expand Down
8 changes: 3 additions & 5 deletions adapters/qqguild/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ export class QQGuildBot extends Bot<QQGuildBot.Config> {
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() {
Expand Down
2 changes: 1 addition & 1 deletion adapters/qqguild/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { QQGuildBot } from './bot'

export class WsClient extends Adapter.Client<QQGuildBot> {
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 => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export abstract class Bot<T extends Bot.Config = Bot.Config> {
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
Expand Down
71 changes: 42 additions & 29 deletions packages/core/src/session.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
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 {
session?: Session
}
}

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

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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'])
2 changes: 1 addition & 1 deletion packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export interface Methods {
getReactionIter(channelId: string, messageId: string, emoji: string): AsyncIterable<User>

// user
getSelf(): Promise<User>
getLogin(): Promise<Login>
getUser(userId: string, guildId?: string): Promise<User>
getFriendList(next?: string): Promise<List<User>>
getFriendIter(): AsyncIterable<User>
Expand Down

0 comments on commit 2e42d38

Please sign in to comment.