开发文档
# 开发文档
# 基本介绍
派蒙Bot使用插件式统一管理,用以提供帮助、限流、鉴权等能力。开发语言Golang,因此理论性能要比使用python开发的机器人高出不少。
推荐Golang教程:iswbm (opens new window)
# 插件开发
插件管理器所在包:manager
开发一个新插件时,请在plugins目录下新建一个目录,其目录名(包名)会被manager自动沿用为插件Key,用于进行插件配置、限流管理等等。
例子
例如,开发一个复读插件,在plugins目录下新建目录echo,在echo下创建echo.go文件,它的插件Key将会自动设为echo,在config-plugin.yaml文件中,该插件的配置项将会以echo
为根。
# 初始化
首先,为你的新插件声明一个manager.PluginInfo
类型变量,用以描述插件信息。
manager.PluginInfo
结构定义:
// PluginInfo 插件信息
type PluginInfo struct {
Name string // [必填] 插件名称
Usage string // [必填] 插件用法描述:会在插件帮助详情中展示
SuperUsage string // [选填] 插件超级用户用法描述
Classify string // [选填] 插件分类,为空时代表默认分类
IsPassive bool // [选填] 是否为被动插件:在帮助中被标识为被动功能;
IsSuperOnly bool // [选填] 是否为超级用户专属插件:若true,消息性事件会自动加上SuperOnly检查;在帮助中只有超级用户私聊可见;
AdminLevel int // [选填] 群管理员使用最低级别: 0 表示非群管理员专用插件 >0 表示数字越低,权限要求越高;会在帮助中进行标识;配置文件中 插件Key.adminlevel 配置项优先级高于此项
}
2
3
4
5
6
7
8
9
10
11
随后,声明一个*manager.PluginProxy
类型变量,用来作为插件代理 使用插件管理器提供的各项能力。
接下来,在init
函数中,调用manager.RegisterPlugin(info manager.PluginInfo)
函数来初始化你的*manager.PluginProxy
。
至此,你的新插件(以echo为例)应该是这个样子:
package echo
import (
"github.com/RicheyJang/PaimengBot/manager"
zero "github.com/wdvxdr1123/ZeroBot"
)
var info = manager.PluginInfo{ // [1] 声明插件信息结构变量
Name: "复读",
Usage: `
用法:
echo [复读内容]:将echo后的内容进行复读
`,
}
var proxy *manager.PluginProxy // [2] 声明插件代理变量
func init() {
proxy = manager.RegisterPlugin(info) // [3] 使用插件信息初始化插件代理
if proxy == nil { // 若初始化失败,请return,失败原因会在日志中打印
return
}
// [4] 此处进行其它初始化操作
}
// [5] 其它代码实现
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 定义事件处理
Onebot基础知识
派蒙Bot全面基于Onebot v11协议 (opens new window),Onebot采用事件与API系统:收到新消息、收到好友请求、收到群邀请等等皆为由前端(如go-cqhttp)推送给后端(如派蒙Bot)的事件,后端会对事件进行处理,并可以通过一定的方式来调用前端API:如发送各类消息、撤回消息、同意好友请求等等。
proxy初始化后,便可以使用proxy提供的能力了。
最常用的便是定义某个事件的处理函数(Handler)。例如,想要在收到以复读
或echo
开头的消息时进行一定的处理,便可以:
proxy.OnCommands([]string{"复读","echo"}).SetBlock(true).FirstPriority().Handle(EchoHandler)
OnCommands
这类以On开头的函数为事件注册函数,会针对某一类事件进行注册以提供事件处理函数。同类型的函数有:
func (p *PluginProxy) OnCommands(cmd []string, rules ...zero.Rule) *zero.Matcher // 处理消息内容以cmd中任意一项开头的消息事件,消息内容中剩下的部分则为参数
func (p *PluginProxy) OnRegex(reg string, rules ...zero.Rule) *zero.Matcher // 处理消息内容满足reg正则的消息事件
func (p *PluginProxy) OnFullMatch(cmd []string, rules ...zero.Rule) *zero.Matcher // 处理消息内容与cmd中任意一项完全相同的消息事件
func (p *PluginProxy) On(tp string, rules ...zero.Rule) *zero.Matcher // 处理[tp]类型事件
func (p *PluginProxy) OnMessage(rules ...zero.Rule) *zero.Matcher // 处理消息类型事件
func (p *PluginProxy) OnRequest(rules ...zero.Rule) *zero.Matcher // 处理Request类型事件
func (p *PluginProxy) OnNotice(rules ...zero.Rule) *zero.Matcher // 处理Notice类型事件
// 上述三种类型参见Onebot协议
2
3
4
5
6
7
8
9
可以注意到,每个事件注册函数参数中都包含了rules ...zero.Rule
,它是一系列过滤函数,函数定义如下,只有所有过滤函数皆返回true,该事件才会被你所指定的Handler处理。
func(ctx *zero.Ctx) bool
回归此前的事件注册,在OnCommand
后的各个函数:
SetBlock(true) // 代表经过此Handler处理后,其它事件处理函数不再处理此次事件,一般需要设为true,防止同一事件被多个插件处理
FirstPriority() // 此Handler的优先级,同类型函数还有SetPriority(int)
Handle(EchoHandler) // 指定Handler为EchoHandler函数
2
3
而一个Handler(例如EchoHandler)的类型应该为:
func (ctx *zero.Ctx)
在Handler及Rule的定义中都出现了zero.Ctx,它是ZeroBot框架(一个实现了Onebot协议的Go后端框架,派蒙Bot是对它的上层封装)所提供的事件上下文,常用属性或方法有:
ctx.Event // 此次事件的内容
ctx.MessageString() string // 获取消息事件的消息纯文本内容
ctx.Send(message interface{}) int64 // 快捷向消息发送者发送一条消息,返回消息ID
ctx.SendChain(message ...message.MessageSegment) int64 // 以消息链的方式向消息发送者发送一条消息
// 其它请参见zerobot.Ctx定义
2
3
4
5
例如,上述例子的EchoHandler,其内容如下:
func EchoHandler(ctx *zero.Ctx) {
str := utils.GetArgs(ctx) // 派蒙Bot提供的工具函数,用于获取此次事件的消息参数内容
tm := proxy.GetConfigInt64("times") // proxy提供的统一配置项管理功能,此函数用于获取int64类型的times配置项值
for i := int64(0); i < tm; i++ {
ctx.Send(str)
}
}
2
3
4
5
6
7
重要
派蒙Bot作为一个较为完毕的Onebot后端框架,无论是插件代理proxy还是工具包utils,都提供了大量固有能力:如统一插件配置管理、定时任务、插件用户级锁、关系型数据库、K-V数据库、快捷获取指定消息内容、2D绘图、可重试的Http Client、字符串处理等等,无需自己造轮子,详细请参见proxy文档和工具包文档。
# 完整复读插件示例:
最后,写完一个插件后,别忘在cmd/main.go文件的import中引用该插件所在的包,以启用该插件,例如:
// cmd/main.go中
import (
// ...其它包
_ "github.com/RicheyJang/PaimengBot/plugins/echo"
)
2
3
4
5
package echo
import (
"github.com/RicheyJang/PaimengBot/manager"
"github.com/RicheyJang/PaimengBot/utils"
zero "github.com/wdvxdr1123/ZeroBot"
)
var info = manager.PluginInfo{ // [1] 声明插件信息结构变量
Name: "复读",
Usage: `
用法:
echo [复读内容]:将echo后的内容进行复读
`,
}
var proxy *manager.PluginProxy // [2] 声明插件代理变量
func init() {
proxy = manager.RegisterPlugin(info) // [3] 使用插件信息初始化插件代理
if proxy == nil { // 若初始化失败,请return,失败原因会在日志中打印
return
}
proxy.OnCommands([]string{"复读","echo"}).SetBlock(true).FirstPriority().Handle(EchoHandler) // [4] 注册事件处理函数
proxy.AddConfig("times", 2) // proxy提供的统一配置项管理功能,此函数新增一个配置项times,默认值为2
}
// [5] Handler实现
func EchoHandler(ctx *zero.Ctx) {
str := utils.GetArgs(ctx) // 派蒙Bot提供的工具函数,用于获取此次事件的消息参数内容
tm := proxy.GetConfigInt64("times") // proxy提供的统一配置项管理功能,此函数用于获取int64类型的times配置项值
for i := int64(0); i < tm; i++ {
ctx.Send(str)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 事件处理Hook
此外,还可以为事件处理添加钩子函数,已有插件中的限流、鉴权、统计等便是基于钩子函数实现的。
挂载点有两处:
- 进入具体的事件处理函数前
- 事件处理函数处理完成后
- plugin-config配置文件有所变更时
第一处使用:
manager.AddPreHook(hook ...PluginHook)
第二处使用:
manager.AddPostHook(hook ...PluginHook)
第三处使用:
manager.WhenConfigFileChange(hook ...FileHook)
其中,PluginHook
定义为:
func(condition *manager.PluginCondition, ctx *zero.Ctx) error
condition包含了即将被调用的插件信息:
type PluginCondition struct {
PluginInfo // 插件信息(由插件提供,只读)
Key string // 插件Key
NormalCmd [][]string // 该插件的普通用户命令集
SuperCmd [][]string // 该插件的超级用户专用命令集
}
2
3
4
5
6
ctx为此次事件的zerobot上下文。
注意!对于返回值,若返回的error不为nil,控制器将立马终止此次事件,后续一切事件处理函数或其它钩子都将不会被调用。
此外,manager还提供了一些PluginCondition相关的工具函数:
manager.GetAllPluginConditions() []*PluginCondition // 返回所有插件的PluginCondition
GetPluginConditionByKey(key string) *PluginCondition // 通过插件Key查询该插件的PluginCondition
2
FileHook
定义为:
func(event fsnotify.Event) error // 该error仅会在日志中有所体现