ctx.emit() // 同时触发,返回 void
ctx.parallel() // 同时触发,返回一个全部完成的 Promise
ctx.bail() // 依次触发,返回第一个 non-nullable 的结果
ctx.serial() // 依次触发,返回第一个 resolve non-nullable 的结果
从旧版本迁移
这个页面将介绍 Koishi v3 的新特性和对应的迁移方法。
包名变更
koishi-database-mysql 变更为 koishi-plugin-mysql。
此外,你可能还需要额外安装 koishi-adapter-onebot 作为 QQ 平台的支持。
钩子函数
Koishi v1 的 ctx.receiver
使用了 EventEmitteropen in new window 来分发事件,而 Koishi v3 则自己实现了一个事件系统。这样做将带来几点好处:
- 使用统一的事件分发机制,无需对每个上下文构造 EventEmitter 实例,具有更高的性能
emit
,parallel
,bail
,serial
等方法能够妥善处理不同场景下的事件回调
相关 API 的迁移方法如下:
ctx.receiver.on(event, callback) => ctx.on(event, callback)
ctx.receiver.emit(event, ...args) => ctx.emit(event, ...args)
ctx.app.emitEvent(...args) => ctx.emit(...args)
选择器
Koishi v3 提供了选择器,它完全覆盖了 v1 的上下文创建功能并有所增强。
ctx.user(123, 456) => ctx.select('userId', '123', '456')
ctx.groups.exclude(123, 456) => ctx.unselect('groupId', '123', '456')
ctx.groups.intersect(ctx.user(789)) => ctx.select('groupId').select('userId', '789')
相关文档:使用选择器
会话接口
Koishi v3 新增了会话的概念,它向下兼容大部分 Koishi v1 元信息对象的特性,并增加了大量方法:
ses.app // App 实例
ses.bot // Bot 实例
ses.send() // 发送消息
ses.sendQueued() // 延时发送消息
ses.cancelQueued() // 取消延时队列
ses.middleware() // 注册仅对当前会话生效的中间件
ses.prompt() // 等待一条消息
ses.suggest() // 书写错误提示
ses.resolve() // 解析 argv 对象
ses.collect() // 获取指令所需字段
ses.execute() // 执行指令
ses.getUser() // 获取用户数据
ses.getChannel() // 获取频道数据
ses.observeUser() // 绑定可观测用户实例
ses.observeChannel() // 绑定可观测频道实例
相关文档:使用会话
数据库变更
Koishi v3 的数据库相比 v1 发生了许多改动,最为显著的一点就是大部分 group 被替换为了 channel:
extendUser(callback) => User.extend(callback)
createUser(callback) => User.create(callback)
extendChannel(callback) => Channel.extend(callback)
createChannel(callback) => Channel.create(callback)
ctx.db.getUser(...args) => ctx.db.getUser(...args)
=> session.getUser(...args)
ctx.db.getGroup(...args) => ctx.db.getChannel(...args)
=> session.getChannel(...args)
同时由于 v3 的跨平台特性,你可能还需要留意 database.getUser()
这个接口本身的变化。
相关文档:使用数据库
单一应用实例
Koishi v3 使用单一的 App 实例管理多个机器人账号,这将大幅提高程序的启动速度。
现在可以通过 ctx.bots
访问当前 App 下的所有机器人,也可以用 session.app
和 session.bot
访问当前会话所在的 App 和 Bot 实例了。
// ctx.bot 支持以两种方式索引:
// 首先其本身是一个数组,可以直接用下标或者 forEach, map 等方法
// 其次我们也支持通过 platform:selfId 的方式进行索引
ctx.sender.sendGroupMsg() => ctx.bots[0].sendMessage()
ctx.sender.sendGroupMsg() => ctx.bots[`${platform}:${selfId}`].sendMessage()
appMap[selfId] => session.app
appMap[selfId].sender => session.bot
ctx.sender.sendGroupMsg() => session.bot.sendMessage()
app.selfId => bot.selfId
getSelfIds() => app.bots.map(bot => bot.selfId)
同时我们也不再需要全局的生命周期方法了。直接使用 v1 就有的生命周期方法即可控制所有 Bot 实例。
startAll() => app.start()
stopAll() => app.stop()
onStart(cb) => ctx.on('connect', cb)
onStop(cb) => ctx.on('disconnect', cb)
其他的构造选项变更:
- commandPrefix -> prefix
- maxMiddlewares -> maxListeners
- defaultAuthority -> autoAuthorize
- similarityCoefficient -> minSimilarity
- quickOperationTimeout -> onebot.quickOperation
指令选项
Koishi v1 的指令系统对 TypeScript 的类型标注并不友好。为了更好地适应强类型和按需获取数据的程序风格,Koishi v3 修改了指令选项的行为:
// v1
cmd.option('-f, --foo <arg>', 'description', { default: 123 })
cmd.option('-B, --no-bar', 'description')
cmd.option('--baz <arg>', 'description', { isString: true })
// v3
cmd.option('foo', '-f <arg> description', { fallback: 123 })
cmd.option('bar', '-B description', { value: false })
cmd.option('baz', '<arg:string> description')
相关文档:定义选项
事件名称
为跨平台考虑,Koishi v3 调整了部分事件名称:
'group-recall' => 'message-deleted/group'
'friend-recall' => 'message-deleted/private'
'friend-add' => 'friend-added'
'group-increase' => 'group-added'
=> 'group-member-added'
'group-decrease' => 'group-deleted'
=> 'group-member-deleted'
'group-upload' => 'group-file-added'
'group-admin' => 'group-member/role'
'group-ban' => 'group-member/ban'
'notify/*' => 'notice/*'
'request/friend' => 'friend-request'
'request/group/invite' => 'group-request'
'request/group/add' => 'group-member-request'
'heartbeat' => 'lifecycle/heartbeat'
'lifecycle/*' => 'lifecycle/*'
消息段变更
CQCode 在 v3 中升级为了 消息段。你需要调整这些消息段:
'[CQ:at,qq=123]' => '[CQ:at,id=123]' // 接收和发送
'[CQ:reply,id=123]' => '[CQ:quote,id=123]' // 接收和发送
'[CQ:image,file=///]' => '[CQ:image,url=///]' // 仅限发送(接收逻辑不变)