- 基于 Gin 框架搭建 HTTP 服务,接收并处理 Bot 命令请求 - 实现插件化命令系统,支持通过 Plugin 接口扩展新命令 - 内置菜单、启用/禁用、时间查询等基础命令 - 新增图片生成插件,对接 OpenAI Images API - 支持管理员权限控制、命令动态启禁用 - 提供完整配置管理(.env)与 Docker 部署方案
168 lines
3.2 KiB
Go
168 lines
3.2 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
plugins []Plugin
|
|
commands map[string]*commandInfo
|
|
mu sync.RWMutex
|
|
)
|
|
|
|
type commandInfo struct {
|
|
name string
|
|
description string
|
|
usage string
|
|
handler Handler
|
|
initFunc func()
|
|
enabled bool
|
|
adminOnly bool
|
|
}
|
|
|
|
func init() {
|
|
plugins = make([]Plugin, 0)
|
|
commands = make(map[string]*commandInfo)
|
|
}
|
|
|
|
// RegisterPlugin 注册一个插件(推荐方式)
|
|
func RegisterPlugin(p Plugin) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
plugins = append(plugins, p)
|
|
|
|
info := &commandInfo{
|
|
name: p.Name(),
|
|
description: p.Description(),
|
|
usage: p.Usage(),
|
|
handler: p.Run,
|
|
enabled: true,
|
|
}
|
|
|
|
// 检查是否实现了 PluginWithInit
|
|
if initable, ok := p.(PluginWithInit); ok {
|
|
info.initFunc = initable.Init
|
|
}
|
|
|
|
// 检查是否实现了 PluginAdmin
|
|
if admin, ok := p.(PluginAdmin); ok {
|
|
info.adminOnly = admin.IsAdminOnly()
|
|
}
|
|
|
|
commands[info.name] = info
|
|
}
|
|
|
|
// Register 兼容旧方式:直接注册 Command
|
|
func Register(cmd Command) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
commands[cmd.Name] = &commandInfo{
|
|
name: cmd.Name,
|
|
description: cmd.Description,
|
|
usage: cmd.Usage,
|
|
handler: cmd.Handler,
|
|
initFunc: cmd.Init,
|
|
enabled: true,
|
|
adminOnly: cmd.AdminOnly,
|
|
}
|
|
}
|
|
|
|
// InitAll 初始化所有需要初始化的插件
|
|
func InitAll() {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
for _, info := range commands {
|
|
if info.initFunc != nil {
|
|
info.initFunc()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle 查找并执行命令
|
|
func Handle(req *Req) Resp {
|
|
mu.RLock()
|
|
info, ok := commands[req.Command]
|
|
mu.RUnlock()
|
|
|
|
if !ok {
|
|
return Resp{Reply: "无法识别的命令。发送\"菜单\"查看可用命令。"}
|
|
}
|
|
|
|
if !info.enabled {
|
|
return Resp{Reply: fmt.Sprintf("命令\"%s\"已被禁用。", info.name)}
|
|
}
|
|
|
|
if info.adminOnly && !IsAdmin(req.UserID) {
|
|
return Resp{Reply: "权限不足,该命令仅管理员可用。"}
|
|
}
|
|
|
|
return info.handler(req)
|
|
}
|
|
|
|
// AllPlugins 返回所有插件
|
|
func AllPlugins() []Plugin {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
return append([]Plugin(nil), plugins...)
|
|
}
|
|
|
|
// AllCommands 返回所有命令信息(用于菜单)
|
|
func AllCommands() []CommandInfo {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
|
|
result := make([]CommandInfo, 0, len(commands))
|
|
for _, info := range commands {
|
|
result = append(result, CommandInfo{
|
|
Name: info.name,
|
|
Description: info.description,
|
|
Usage: info.usage,
|
|
Enabled: info.enabled,
|
|
AdminOnly: info.adminOnly,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
// CommandInfo 命令信息(用于菜单显示)
|
|
type CommandInfo struct {
|
|
Name string
|
|
Description string
|
|
Usage string
|
|
Enabled bool
|
|
AdminOnly bool
|
|
}
|
|
|
|
// Toggle 启用或禁用命令
|
|
func Toggle(name string, enable bool) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
info, ok := commands[name]
|
|
if !ok {
|
|
return fmt.Errorf("命令\"%s\"不存在", name)
|
|
}
|
|
|
|
if info.adminOnly {
|
|
return fmt.Errorf("管理命令\"%s\"不可被禁用", name)
|
|
}
|
|
|
|
info.enabled = enable
|
|
return nil
|
|
}
|
|
|
|
// Handler 命令处理函数(兼容旧方式)
|
|
type Handler func(req *Req) Resp
|
|
|
|
// Command 命令定义(兼容旧方式)
|
|
type Command struct {
|
|
Name string
|
|
Description string
|
|
Usage string
|
|
Handler Handler
|
|
Init func()
|
|
AdminOnly bool
|
|
}
|