🛠️ WxBot Enhanced 插件开发指南¶
 **从零开始学习WxBot插件开发,打造属于你的Enhanced插件**
📋 目录导航¶
🎯 快速开始¶
开发环境准备¶
# 1. 环境要求
go version # 需要 Go 1.21+
git --version # 需要 Git
# 2. 克隆项目
git clone https://github.com/ruk1ng001/wxbot.git
cd wxbot
# 3. 安装依赖
go mod download
# 4. 创建你的插件目录
mkdir plugins/myfirstplugin
cd plugins/myfirstplugin
创建你的第一个插件¶
创建 plugins/myfirstplugin/init.go:
package myfirstplugin
import (
"github.com/ruk1ng001/wxbot/engine/control"
"github.com/ruk1ng001/wxbot/engine/robot"
)
func init() {
// 注册插件
engine := control.Register("myfirstplugin", &control.Options{
Alias: "我的第一个插件", // 插件显示名称
Help: "这是一个示例插件", // 帮助信息
DataFolder: "myfirstplugin", // 数据目录名
DisableOnDefault: false, // 是否默认禁用
HideMenu: false, // 是否在菜单中隐藏
})
// 注册消息处理器
engine.OnPrefix("hello").SetBlock(true).Handle(helloHandler)
engine.OnFullMatch("测试").Handle(testHandler)
// 管理员命令
engine.OnCommand("myplugin", robot.AdminPermission).Handle(adminHandler)
}
// Hello处理器
func helloHandler(ctx *robot.Ctx) {
name := ctx.State["args"].(string) // 获取参数
if name == "" {
ctx.ReplyText("请告诉我你的名字,例如:hello 张三")
return
}
ctx.ReplyText("你好," + name + "!欢迎使用WxBot Enhanced!")
}
// 测试处理器
func testHandler(ctx *robot.Ctx) {
ctx.ReplyText("插件测试成功!🎉")
}
// 管理员处理器
func adminHandler(ctx *robot.Ctx) {
ctx.ReplyText("管理员命令执行成功!")
}
注册插件¶
在 plugins.yaml 中添加你的插件:
测试插件¶
# 生成插件导入
make plugins
# 运行测试
go run main.go
# 在微信中测试
# 发送: hello 世界
# 期望回复: 你好,世界!欢迎使用WxBot Enhanced!
🏗️ 插件架构¶
插件生命周期¶
graph TD
A[插件加载] --> B[init函数执行]
B --> C[Register注册]
C --> D[配置Options]
D --> E[注册处理器]
E --> F[插件就绪]
F --> G[接收消息]
G --> H[规则匹配]
H --> I[执行处理器]
I --> J[发送响应]
J --> G
核心组件¶
| 组件 | 作用 | 示例 |
|---|---|---|
| Register | 插件注册入口 | control.Register("pluginname", options) |
| Options | 插件配置选项 | 别名、帮助、数据目录等 |
| Engine | 插件引擎 | 提供API调用和数据存储 |
| Handler | 消息处理器 | 业务逻辑实现 |
| Matcher | 消息匹配器 | 定义触发条件 |
| Context | 上下文对象 | 包含事件信息和响应方法 |
📝 基础插件开发¶
插件配置详解¶
type Options struct {
Alias string // 插件别名,用于显示
Help string // 插件帮助信息
DataFolder string // 数据目录名称(必须唯一)
DisableOnDefault bool // 是否默认禁用
HideMenu bool // 是否在插件菜单中隐藏
Priority uint64 // 优先级(可选,自动分配)
}
// 使用示例
engine := control.Register("weather", &control.Options{
Alias: "天气查询",
Help: "查询城市天气信息\n使用方法:天气 城市名",
DataFolder: "weather",
DisableOnDefault: false,
HideMenu: false,
})
消息匹配器类型¶
// 1. 前缀匹配 - 最常用
engine.OnPrefix("天气", "weather").Handle(weatherHandler)
// 匹配: "天气 北京", "weather beijing"
// 参数存储在: ctx.State["args"]
// 2. 完全匹配
engine.OnFullMatch("查看帮助", "help").Handle(helpHandler)
// 匹配: "查看帮助", "help"
// 3. 后缀匹配
engine.OnSuffix("查询", "query").Handle(queryHandler)
// 匹配: "北京天气查询"
// 4. 正则匹配 - 高级用法
engine.OnRegex(`查询(\d+)`).Handle(regexHandler)
// 匹配: "查询12345"
// 结果存储在: ctx.State["regex_matched"]
// 5. 关键词匹配
engine.OnKeyword("你好", "hello").Handle(greetHandler)
// 匹配包含关键词的消息
// 6. 命令匹配 - 管理功能
engine.OnCommand("reload", robot.AdminPermission).Handle(reloadHandler)
// 匹配: "/reload" (需要命令前缀)
// 7. 通用消息匹配 - 高级用法
engine.OnMessage(robot.OnlyGroup, robot.AdminPermission).Handle(generalHandler)
// 可组合多个条件
匹配器配置选项¶
// 设置优先级(数值越小优先级越高)
engine.OnPrefix("urgent").SetPriority(1).Handle(urgentHandler)
// 设置为最高优先级
engine.OnPrefix("emergency").FirstPriority().Handle(emergencyHandler)
// 设置阻断(阻止后续匹配器处理同一消息)
engine.OnPrefix("stop").SetBlock(true).Handle(stopHandler)
// 设置无超时处理(对于长时间运行的任务)
engine.OnPrefix("longtask").SetNoTimeout(true).Handle(longTaskHandler)
// 链式调用
engine.OnPrefix("weather").
SetBlock(true).
SetPriority(10).
Handle(weatherHandler)
上下文(Context)使用¶
func weatherHandler(ctx *robot.Ctx) {
// 1. 获取消息信息
message := ctx.MessageString() // 消息内容
userId := ctx.Event.FinalFromWxId // 发送者ID
groupId := ctx.Event.FromWxId // 群组ID(如果是群聊)
// 2. 获取参数
city := ctx.State["args"].(string) // 前缀后的参数
// 3. 基础回复
ctx.ReplyText("今天北京晴,温度25°C")
ctx.ReplyImage("local://weather.png") // 本地图片
ctx.ReplyImage("https://example.com/weather.jpg") // 网络图片
// 4. 智能@回复(群聊时自动@,私聊时直接回复)
ctx.ReplyTextAndAt("@你 今天天气不错!")
// 5. 发送到指定对象
ctx.SendText("wxid_target", "发送给特定用户")
ctx.SendTextAndAt("group_id", "user_id", "昵称", "群内@特定人")
// 6. 高级消息类型
ctx.ReplyShareLink("标题", "描述", "图片URL", "跳转链接")
ctx.ReplyMiniProgram("小程序ID", "标题", "内容", "图片", "跳转路径")
ctx.ReplyMusic("歌名", "歌手", "app", "跳转链接", "播放链接", "封面")
// 7. 判断消息类型和来源
if ctx.IsEventGroupChat() {
// 群聊消息处理
} else if ctx.IsEventPrivateChat() {
// 私聊消息处理
}
if ctx.IsAt() {
// 被@的消息
}
// 8. 获取用户和群组信息
userInfo, _ := ctx.GetObjectInfo(userId)
friends, _ := ctx.GetFriends()
groups, _ := ctx.GetGroups()
if ctx.IsEventGroupChat() {
members, _ := ctx.GetGroupMembers(groupId)
}
}
权限控制系统¶
// 内置权限规则
engine.OnCommand("admin", robot.AdminPermission).Handle(adminHandler)
engine.OnCommand("manage", robot.GroupAdminPermission).Handle(manageHandler)
engine.OnCommand("user", robot.UserOrGroupAdmin).Handle(userHandler)
// 环境限制
engine.OnPrefix("群功能", robot.OnlyGroup).Handle(groupHandler)
engine.OnPrefix("私聊功能", robot.OnlyPrivate).Handle(privateHandler)
engine.OnPrefix("@功能", robot.OnlyAtMe).Handle(atHandler)
// 自定义权限规则
func vipUserOnly(ctx *robot.Ctx) bool {
vipUsers := []string{"wxid1", "wxid2", "wxid3"}
for _, vip := range vipUsers {
if vip == ctx.Event.FinalFromWxId {
return true
}
}
ctx.ReplyText("此功能仅限VIP用户使用")
return false
}
engine.OnPrefix("vip", vipUserOnly).Handle(vipHandler)
数据存储¶
func dataHandler(ctx *robot.Ctx) {
engine := ctx.GetMatcher().Engine // 获取插件引擎
// 获取插件数据目录
dataDir := engine.GetDataFolder() // data/plugins/myplugin/
cacheDir := engine.GetCacheFolder() // data/plugins/myplugin/cache/
// 文件操作
configFile := filepath.Join(dataDir, "config.json")
cacheFile := filepath.Join(cacheDir, "temp.dat")
// 读写文件...
}
异步事件处理¶
func interactiveHandler(ctx *robot.Ctx) {
ctx.ReplyText("请输入你的选择(输入数字1-3):")
// 等待用户下一条消息
next := ctx.EventChannel(ctx.CheckUserSession()).Next()
select {
case <-time.After(30 * time.Second):
ctx.ReplyText("超时,操作取消")
return
case nextCtx := <-next:
choice := nextCtx.MessageString()
switch choice {
case "1", "2", "3":
ctx.ReplyText("你选择了: " + choice)
default:
ctx.ReplyText("无效选择")
}
}
}
📚 更多文档¶
- ⭐ Enhanced模式开发 - 开发Enhanced插件
- 🎮 游戏插件开发 - 游戏插件开发指南
- 📊 监控集成 - 监控系统集成
- 🔒 安全最佳实践 - 安全开发指南
- 🧪 测试和调试 - 测试和调试技巧
示例插件¶
查看完整的插件示例:
- 猜成语Enhanced - Enhanced游戏插件
- 天气查询 - 工具类插件
- ChatGPT - AI集成插件
- 自动加好友 - 社交管理插件
🎮 游戏插件开发¶
游戏类插件特点¶
游戏插件需要处理复杂的状态管理和用户交互:
// 游戏状态管理
type GameState struct {
PlayerID string
GameID string
Status GameStatus
Score int
StartTime time.Time
}
// 游戏插件示例
func gameHandler(ctx *robot.Ctx) {
// 创建游戏实例
game := NewGame(ctx.Event.FinalFromWxId)
// 游戏逻辑处理
result := game.Process(ctx.MessageString())
// 发送游戏结果
ctx.ReplyText(result.Message)
}
详细的游戏插件开发请参考: - 猜成语Enhanced - 完整的游戏插件实现 - 成语接龙 - 多人游戏状态管理
📊 监控集成¶
插件监控统计¶
WxBot Enhanced提供完整的监控系统集成:
import "github.com/ruk1ng001/wxbot/engine/pkg/monitor"
func monitoredHandler(ctx *robot.Ctx) {
start := time.Now()
defer func() {
// 自动记录执行时间
duration := time.Since(start)
monitor.GlobalMetrics.RecordPluginExecution("pluginname", duration, false)
}()
// 插件逻辑
processMessage(ctx)
}
自定义指标¶
// 业务指标统计
monitor.GlobalMetrics.RecordMessage()
monitor.GlobalMetrics.UpdateConnectionStatus("connected")
monitor.GlobalMetrics.IncrementErrorCount("pluginname")
监控数据会自动显示在Web仪表板:http://localhost:7601/monitor.html
🔒 安全最佳实践¶
输入验证¶
import "github.com/ruk1ng001/wxbot/engine/pkg/validator"
func secureHandler(ctx *robot.Ctx) {
input := ctx.MessageString()
// 输入验证
if err := validator.ValidateMessage(input); err != nil {
ctx.ReplyText("输入格式有误: " + err.Error())
return
}
// 文件路径安全检查
if err := validator.ValidateFilePath(filePath); err != nil {
log.Warnf("文件路径不安全: %v", err)
return
}
}
权限控制¶
// 管理员权限检查
engine.OnCommand("admin", robot.AdminPermission)
// 自定义权限验证
func customPermission(ctx *robot.Ctx) bool {
userID := ctx.Event.FinalFromWxId
return isUserAuthorized(userID)
}
engine.OnPrefix("vip", customPermission)
频率限制¶
var userRateLimit = make(map[string]time.Time)
var rateMutex sync.RWMutex
func rateLimitedHandler(ctx *robot.Ctx) {
userID := ctx.Event.FinalFromWxId
rateMutex.Lock()
lastTime, exists := userRateLimit[userID]
if exists && time.Since(lastTime) < time.Minute {
rateMutex.Unlock()
ctx.ReplyText("请求过于频繁,请稍后再试")
return
}
userRateLimit[userID] = time.Now()
rateMutex.Unlock()
// 处理请求
}
🧪 测试和调试¶
单元测试¶
package myplugin
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPluginHandler(t *testing.T) {
// 模拟消息上下文
ctx := &robot.Ctx{
Event: &robot.Event{
Message: &robot.Message{
Content: "test message",
},
},
}
// 测试处理器
result := processMessage(ctx.MessageString())
assert.NotEmpty(t, result)
}
调试日志¶
import "github.com/ruk1ng001/wxbot/engine/pkg/log"
func debugHandler(ctx *robot.Ctx) {
log.Debugf("[%s] 收到消息: %s", "pluginname", ctx.MessageString())
// 业务逻辑
result := processMessage(ctx)
log.Infof("[%s] 处理结果: %s", "pluginname", result)
}
性能测试¶
func BenchmarkPluginHandler(b *testing.B) {
ctx := createTestContext()
b.ResetTimer()
for i := 0; i < b.N; i++ {
pluginHandler(ctx)
}
}
**🛠️ 开始你的插件开发之旅!** **让WxBot Enhanced变得更加强大和有趣!**