Skip to content

Commit

Permalink
feat(qqguild): support qqguild adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jul 7, 2022
1 parent d9689e4 commit c790afa
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 1 deletion.
36 changes: 36 additions & 0 deletions adapters/qqguild/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@satorijs/adapter-qqguild",
"description": "QQ Guild Adapter for Satorijs",
"version": "1.0.0",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"files": [
"lib"
],
"author": "Shigma <shigma10826@gmail.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/satorijs/node-sdk.git",
"directory": "adapters/qqguild"
},
"bugs": {
"url": "https://github.com/satorijs/node-sdk/issues"
},
"homepage": "https://koishi.js.org/api/adapter/qqguild.html",
"keywords": [
"bot",
"qq",
"qqguild",
"chatbot",
"satori"
],
"peerDependencies": {
"@satorijs/core": "^1.0.0",
"@satorijs/env-node": "^1.0.0"
},
"dependencies": {
"@qq-guild-sdk/core": "^2.0.1",
"qface": "^1.2.0"
}
}
90 changes: 90 additions & 0 deletions adapters/qqguild/src/bot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as QQGuild from '@qq-guild-sdk/core'
import { Bot, Context, Session } from '@satorijs/core'
import { Schema } from '@satorijs/env-node'
import { adaptGuild, adaptUser } from './utils'
import { WsClient } from './ws'
import segment from '@satorijs/message'

export class QQGuildBot extends Bot<QQGuildBot.Config> {
internal: QQGuild.Bot

constructor(ctx: Context, config: QQGuildBot.Config) {
super(ctx, config)
this.internal = new QQGuild.Bot(config)
}

async getSelf() {
const user = adaptUser(await this.internal.me)
user['selfId'] = user.userId
delete user.userId
return user
}

async sendMessage(channelId: string, content: string, guildId?: string) {
const session = await this.session({ channelId, content, guildId, subtype: 'group' })
if (!session?.content) return []
const resp = await this.internal.send.channel(channelId, session.content)
session.messageId = resp.id
this.ctx.emit(session, 'send', session)
this.ctx.emit(session, 'message', this.adaptMessage(resp))
return [resp.id]
}

async getGuildList() {
return this.internal.guilds.then(guilds => guilds.map(adaptGuild))
}

adaptMessage(msg: QQGuild.Message) {
const {
id: messageId, author, guildId, channelId, timestamp,
} = msg
const session: Partial<Session> = {
selfId: this.selfId,
guildId,
messageId,
channelId,
timestamp: +timestamp,
}
session.author = adaptUser(msg.author)
session.userId = author.id
session.guildId = msg.guildId
session.channelId = msg.channelId
session.subtype = 'group'
session.content = (msg.content ?? '')
.replace(/<@!(.+)>/, (_, $1) => segment.at($1))
.replace(/<#(.+)>/, (_, $1) => segment.sharp($1))
const { attachments = [] } = msg as any as { attachments?: any[] }
if (attachments.length > 0) {
session.content += attachments.map((attachment) => {
if (attachment.contentType.startsWith('image')) {
return segment.image(attachment.url)
}
}).join('')
}
session.content = attachments
.filter(({ contentType }) => contentType.startsWith('image'))
.reduce((content, attachment) => content + segment.image(attachment.url), session.content)
return new Session(this, session)
}
}

export namespace QQGuildBot {
export interface Config extends Bot.Config, QQGuild.Bot.Options, WsClient.Config {
intents: number
}

export const Config: Schema<Config> = Schema.intersect([
Schema.object({
app: Schema.object({
id: Schema.string().description('机器人 id。').required(),
key: Schema.string().description('机器人 key。').role('secret').required(),
token: Schema.string().description('机器人令牌。').role('secret').required(),
}),
sandbox: Schema.boolean().description('是否开启沙箱模式。').default(true),
endpoint: Schema.string().role('url').description('API 入口地址。').default('https://api.sgroup.qq.com/'),
authType: Schema.union(['bot', 'bearer'] as const).description('采用的验证方式。').default('bot'),
intents: Schema.bitset(QQGuild.Bot.Intents).description('需要订阅的机器人事件。').default(QQGuild.Bot.Intents.PUBLIC_GUILD_MESSAGES),
}),
WsClient.Config,
] as const)
}
16 changes: 16 additions & 0 deletions adapters/qqguild/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as QQGuild from '@qq-guild-sdk/core'
import { QQGuildBot } from './bot'

export { QQGuild }

export * from './bot'
export * from './utils'
export * from './ws'

export default QQGuildBot

declare module '@satorijs/core' {
interface Session {
qqguild?: QQGuild.Bot
}
}
15 changes: 15 additions & 0 deletions adapters/qqguild/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Guild, User } from '@satorijs/core'
import * as QQGuild from '@qq-guild-sdk/core'

export const adaptGuild = (guild: QQGuild.Guild): Guild => ({
guildId: guild.id,
guildName: guild.name,
})

export const adaptUser = (user: QQGuild.User): User => ({
isBot: user.bot,
avatar: user.avatar,
userId: user.id,
username: user.username,
nickname: user.username,
})
31 changes: 31 additions & 0 deletions adapters/qqguild/src/ws.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Adapter } from '@satorijs/core'
import { Schema } from '@satorijs/env-node'
import { QQGuildBot } from './bot'

export class WsClient extends Adapter<QQGuildBot> {
async start(bot: QQGuildBot) {
Object.assign(bot, await bot.getSelf())
await bot.internal.startClient(bot.config.intents)
bot.internal.on('ready', bot.online.bind(bot))
bot.internal.on('message', msg => {
const session = bot.adaptMessage(msg)
if (session) {
session.type = 'message'
bot.dispatch(session)
}
})
}

async stop(bot: QQGuildBot) {
bot.internal.stopClient()
bot.offline()
}
}

export namespace WsClient {
export interface Config extends Adapter.WsClient.Config {}

export const Config: Schema<Config> = Schema.intersect([
Adapter.WsClient.Config,
])
}
10 changes: 10 additions & 0 deletions adapters/qqguild/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src",
},
"include": [
"src",
],
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"yakumo": "^0.2.8",
"yakumo-mocha": "^0.2.5",
"yakumo-publish": "^0.2.4",
"yakumo-tsc": "^0.2.2",
"yakumo-tsc": "^0.2.3",
"yakumo-upgrade": "^0.2.3",
"yakumo-version": "^0.2.5"
},
Expand Down

0 comments on commit c790afa

Please sign in to comment.