mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 19:37:33 +08:00
9.6 KiB
9.6 KiB
插件系统开发指南
概述
urlDB插件系统提供了一个灵活的扩展机制,允许开发者创建自定义功能来增强系统能力。插件采用进程内加载模式,避免使用Go标准plugin包的限制。
插件生命周期
- 注册 (Register) - 插件被发现并注册到管理器
- 初始化 (Initialize) - 插件接收上下文并准备运行
- 启动 (Start) - 插件开始执行主要功能
- 运行 (Running) - 插件正常工作状态
- 停止 (Stop) - 插件停止运行
- 清理 (Cleanup) - 插件释放资源
创建插件
基本插件结构
可配置插件
插件可以实现 ConfigurablePlugin 接口来支持配置模式和模板:
// ConfigurablePlugin is an optional interface for plugins that support configuration schemas
type ConfigurablePlugin interface {
// CreateConfigSchema creates the configuration schema for the plugin
CreateConfigSchema() *config.ConfigSchema
// CreateConfigTemplate creates a default configuration template
CreateConfigTemplate() *config.ConfigTemplate
}
package myplugin
import (
"github.com/ctwj/urldb/plugin/config"
"github.com/ctwj/urldb/plugin/types"
)
// MyPlugin 实现插件接口
type MyPlugin struct {
name string
version string
description string
author string
context types.PluginContext
}
// NewMyPlugin 创建新插件实例
func NewMyPlugin() *MyPlugin {
return &MyPlugin{
name: "my-plugin",
version: "1.0.0",
description: "我的自定义插件",
author: "开发者名称",
}
}
// 实现必需的接口方法
func (p *MyPlugin) Name() string { return p.name }
func (p *MyPlugin) Version() string { return p.version }
func (p *MyPlugin) Description() string { return p.description }
func (p *MyPlugin) Author() string { return p.author }
func (p *MyPlugin) Initialize(ctx types.PluginContext) error {
p.context = ctx
p.context.LogInfo("插件初始化完成")
return nil
}
func (p *MyPlugin) Start() error {
p.context.LogInfo("插件启动")
return nil
}
func (p *MyPlugin) Stop() error {
p.context.LogInfo("插件停止")
return nil
}
func (p *MyPlugin) Cleanup() error {
p.context.LogInfo("插件清理")
return nil
}
func (p *MyPlugin) Dependencies() []string {
return []string{}
}
func (p *MyPlugin) CheckDependencies() map[string]bool {
return make(map[string]bool)
}
// 实现可选的配置接口
func (p *MyPlugin) CreateConfigSchema() *config.ConfigSchema {
schema := config.NewConfigSchema(p.name, p.version)
// 添加配置字段
intervalMin := 1.0
intervalMax := 3600.0
schema.AddField(config.ConfigField{
Key: "interval",
Name: "检查间隔",
Description: "插件执行任务的时间间隔(秒)",
Type: "int",
Required: true,
Default: 60,
Min: &intervalMin,
Max: &intervalMax,
})
schema.AddField(config.ConfigField{
Key: "enabled",
Name: "启用状态",
Description: "插件是否启用",
Type: "bool",
Required: true,
Default: true,
})
return schema
}
func (p *MyPlugin) CreateConfigTemplate() *config.ConfigTemplate {
config := map[string]interface{}{
"interval": 30,
"enabled": true,
}
return &config.ConfigTemplate{
Name: "default-config",
Description: "默认配置模板",
Config: config,
Version: p.version,
}
}
插件上下文 API
日志功能
// 记录不同级别的日志
p.context.LogDebug("调试信息: %s", "详细信息")
p.context.LogInfo("普通信息: %d", 42)
p.context.LogWarn("警告信息")
p.context.LogError("错误信息: %v", err)
配置管理
// 设置配置
err := p.context.SetConfig("interval", 60)
err := p.context.SetConfig("enabled", true)
err := p.context.SetConfig("api_key", "secret-key")
// 获取配置
interval, err := p.context.GetConfig("interval")
enabled, err := p.context.GetConfig("enabled")
数据存储
// 存储数据
data := map[string]interface{}{
"last_update": time.Now().Unix(),
"counter": 0,
"status": "active",
}
err := p.context.SetData("my_data", data, "app_state")
// 读取数据
retrievedData, err := p.context.GetData("my_data", "app_state")
// 删除数据
err := p.context.DeleteData("my_data", "app_state")
数据库访问
// 获取数据库连接
db := p.context.GetDB()
if gormDB, ok := db.(*gorm.DB); ok {
// 执行数据库操作
var count int64
err := gormDB.Model(&entity.Resource{}).Count(&count).Error
if err != nil {
p.context.LogError("查询失败: %v", err)
} else {
p.context.LogInfo("资源数量: %d", count)
}
}
任务调度
// 注册定时任务
err := p.context.RegisterTask("my-periodic-task", func() {
p.context.LogInfo("执行定时任务于 %s", time.Now().Format(time.RFC3339))
// 任务逻辑...
})
if err != nil {
p.context.LogError("注册任务失败: %v", err)
}
自动注册插件
package myplugin
import (
"github.com/ctwj/urldb/plugin"
"github.com/ctwj/urldb/plugin/types"
)
// init 函数在包导入时自动调用
func init() {
plugin := NewMyPlugin()
RegisterPlugin(plugin)
}
// RegisterPlugin 注册插件到全局管理器
func RegisterPlugin(pluginInstance types.Plugin) {
if plugin.GetManager() != nil {
plugin.GetManager().RegisterPlugin(pluginInstance)
}
}
完整示例插件
package demo
import (
"time"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/plugin/types"
"gorm.io/gorm"
)
// FullDemoPlugin 完整功能演示插件
type FullDemoPlugin struct {
name string
version string
description string
author string
context types.PluginContext
}
func NewFullDemoPlugin() *FullDemoPlugin {
return &FullDemoPlugin{
name: "full-demo-plugin",
version: "1.0.0",
description: "完整功能演示插件",
author: "urlDB Team",
}
}
// ... 实现接口方法
func (p *FullDemoPlugin) Initialize(ctx types.PluginContext) error {
p.context = ctx
p.context.LogInfo("演示插件初始化")
// 设置配置
p.context.SetConfig("interval", 60)
p.context.SetConfig("enabled", true)
// 存储初始数据
data := map[string]interface{}{
"start_time": time.Now().Format(time.RFC3339),
"counter": 0,
}
p.context.SetData("demo_stats", data, "monitoring")
return nil
}
func (p *FullDemoPlugin) Start() error {
p.context.LogInfo("演示插件启动")
// 注册定时任务
err := p.context.RegisterTask("demo-task", p.demoTask)
if err != nil {
return err
}
// 演示数据库访问
p.demoDatabaseAccess()
return nil
}
func (p *FullDemoPlugin) demoTask() {
p.context.LogInfo("执行演示任务")
// 更新计数器
data, err := p.context.GetData("demo_stats", "monitoring")
if err == nil {
if stats, ok := data.(map[string]interface{}); ok {
counter, _ := stats["counter"].(float64)
stats["counter"] = counter + 1
stats["last_update"] = time.Now().Format(time.RFC3339)
p.context.SetData("demo_stats", stats, "monitoring")
}
}
}
最佳实践
- 错误处理:始终检查错误并适当处理
- 资源清理:在Cleanup方法中释放所有资源
- 配置验证:在初始化时验证配置有效性
- 日志记录:使用适当的日志级别记录重要事件
- 性能考虑:避免在插件中执行阻塞操作
常见问题
Q: 插件如何访问数据库?
A: 通过 p.context.GetDB() 获取数据库连接,转换为 *gorm.DB 后使用。
Q: 插件如何存储持久化数据?
A: 使用 SetData()、GetData()、DeleteData() 方法。
Q: 插件如何注册定时任务?
A: 使用 RegisterTask() 方法注册任务函数。
Q: 插件如何记录日志?
A: 使用 LogDebug()、LogInfo()、LogWarn()、LogError() 方法。
部署流程
- 将插件代码放在
plugin/目录下 - 确保包含自动注册的
init()函数 - 构建主应用程序:
go build -o main . - 启动应用程序,插件将自动注册
- 通过API或管理界面启用插件
API参考
PluginContext 接口
LogDebug(msg string, args ...interface{})- 调试日志LogInfo(msg string, args ...interface{})- 信息日志LogWarn(msg string, args ...interface{})- 警告日志LogError(msg string, args ...interface{})- 错误日志GetConfig(key string) (interface{}, error)- 获取配置SetConfig(key string, value interface{}) error- 设置配置GetData(key string, dataType string) (interface{}, error)- 获取数据SetData(key string, value interface{}, dataType string) error- 设置数据DeleteData(key string, dataType string) error- 删除数据RegisterTask(name string, taskFunc func()) error- 注册任务GetDB() interface{}- 获取数据库连接
Plugin 接口
Name() string- 插件名称Version() string- 插件版本Description() string- 插件描述Author() string- 插件作者Initialize(ctx PluginContext) error- 初始化插件Start() error- 启动插件Stop() error- 停止插件Cleanup() error- 清理插件Dependencies() []string- 获取依赖CheckDependencies() map[string]bool- 检查依赖