diff --git a/examples/plugin/example/dynamic_params.go b/examples/plugin/example/dynamic_params.go new file mode 100644 index 0000000..71f22fb --- /dev/null +++ b/examples/plugin/example/dynamic_params.go @@ -0,0 +1,133 @@ +package main + +import ( + "context" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/darkit/goproxy/examples/plugin" +) + +// 演示动态参数传递功能 +func DynamicParamsExample() { + // 创建上下文 + ctx := context.Background() + + // 获取插件目录 + pluginsDir := filepath.Join("..", "plugins", "dist") + if _, err := os.Stat(pluginsDir); os.IsNotExist(err) { + fmt.Printf("插件目录不存在: %s\n", pluginsDir) + return + } + + // 创建插件管理器 + pm := plugin.NewPluginManager(pluginsDir) + + // 加载插件 + fmt.Println("正在加载插件...") + if err := pm.LoadPlugins(); err != nil { + fmt.Printf("加载插件失败: %v\n", err) + return + } + + // 初始化所有插件 + if err := pm.InitPlugins(ctx); err != nil { + fmt.Printf("初始化插件失败: %v\n", err) + return + } + + // 启动所有插件 + if err := pm.StartPlugins(ctx); err != nil { + fmt.Printf("启动插件失败: %v\n", err) + return + } + + // 打印所有插件信息 + fmt.Println("\n=== 已加载的插件 ===") + for _, info := range pm.GetPluginInfos() { + fmt.Printf("插件: %s (版本: %s, 类型: %s)\n", info.Name, info.Version, info.Type) + } + fmt.Println() + + // 示例1: 调用日志插件 + fmt.Println("=== 示例1: 调用日志插件 ===") + logResult, err := pm.ExecutePlugin(ctx, "LoggerPlugin", "info", map[string]interface{}{ + "message": "这是通过动态参数传递的日志消息", + }) + fmt.Printf("日志插件调用结果: %v, 错误: %v\n", logResult, err) + + // 获取日志状态 + statusResult, err := pm.ExecutePlugin(ctx, "LoggerPlugin", "getLoggerStatus", nil) + fmt.Printf("日志插件状态: %v, 错误: %v\n", statusResult, err) + + // 示例2: 调用存储插件 + fmt.Println("\n=== 示例2: 调用存储插件 ===") + // 保存文件 + saveResult, err := pm.ExecutePlugin(ctx, "StoragePlugin", "saveFile", map[string]interface{}{ + "filename": "test.txt", + "data": "这是通过动态参数传递保存的测试数据", + }) + fmt.Printf("保存文件结果: %v, 错误: %v\n", saveResult, err) + + // 列出文件 + listResult, err := pm.ExecutePlugin(ctx, "StoragePlugin", "listFiles", nil) + fmt.Printf("文件列表: %v, 错误: %v\n", listResult, err) + + // 读取文件 + loadResult, err := pm.ExecutePlugin(ctx, "StoragePlugin", "loadFile", map[string]interface{}{ + "filename": "test.txt", + }) + fmt.Printf("读取文件内容: %v, 错误: %v\n", loadResult, err) + + // 获取存储信息 + infoResult, err := pm.ExecutePlugin(ctx, "StoragePlugin", "getStorageInfo", nil) + fmt.Printf("存储插件信息: %v, 错误: %v\n", infoResult, err) + + // 示例3: 调用统计插件 + fmt.Println("\n=== 示例3: 调用统计插件 ===") + // 记录请求 + pm.ExecutePlugin(ctx, "StatsPlugin", "recordRequest", map[string]interface{}{ + "bytesReceived": 1024.0, + "bytesSent": 2048.0, + "isError": false, + }) + + // 睡眠一段时间以便观察 + time.Sleep(1 * time.Second) + + // 再次记录请求 + pm.ExecutePlugin(ctx, "StatsPlugin", "recordRequest", map[string]interface{}{ + "bytesReceived": 512.0, + "bytesSent": 768.0, + "isError": true, + }) + + // 获取统计报告 + reportResult, err := pm.ExecutePlugin(ctx, "StatsPlugin", "getStatsReport", nil) + fmt.Printf("统计报告: %v, 错误: %v\n", reportResult, err) + + // 示例4: 使用ExecutePluginsByType调用所有工具类插件 + fmt.Println("\n=== 示例4: 按类型调用插件 ===") + typeResults := pm.ExecutePluginsByType(ctx, plugin.PluginTypeUtils, "info", map[string]interface{}{ + "message": "这条消息将发送给所有工具类插件", + }) + fmt.Printf("工具类插件调用结果: %v\n", typeResults) + + // 示例5: 使用ExecuteAllPlugins调用所有插件 + fmt.Println("\n=== 示例5: 调用所有插件 ===") + allResults := pm.ExecuteAllPlugins(ctx, "getLoggerStatus", nil) + fmt.Println("所有插件调用结果:") + for name, result := range allResults { + fmt.Printf(" %s: %v\n", name, result) + } + + // 停止所有插件 + if err := pm.StopPlugins(ctx); err != nil { + fmt.Printf("停止插件失败: %v\n", err) + return + } + + fmt.Println("\n示例结束") +} diff --git a/examples/plugin/example/main.go b/examples/plugin/example/main.go index 09fe2ca..57525ff 100644 --- a/examples/plugin/example/main.go +++ b/examples/plugin/example/main.go @@ -10,15 +10,36 @@ import ( ) func main() { + fmt.Println("==== 插件系统示例 ====") + fmt.Println("请选择要运行的示例:") + fmt.Println("1. 基本插件加载和管理") + fmt.Println("2. 动态参数传递示例") + fmt.Print("请输入选项 (1-2): ") + + var choice int + fmt.Scan(&choice) + + switch choice { + case 1: + BasicPluginExample() + case 2: + DynamicParamsExample() + default: + fmt.Println("无效的选项") + } +} + +// BasicPluginExample 基本的插件加载和管理示例 +func BasicPluginExample() { // 创建上下文 ctx := context.Background() // 获取插件目录 - pluginsDir := filepath.Join("..", "plugins") + pluginsDir := filepath.Join("..", "plugins", "dist") if _, err := os.Stat(pluginsDir); os.IsNotExist(err) { if err := os.MkdirAll(pluginsDir, 0o755); err != nil { fmt.Printf("创建插件目录失败: %v\n", err) - os.Exit(1) + return } } @@ -39,19 +60,19 @@ func main() { // 加载插件 if err := pm.LoadPlugins(); err != nil { fmt.Printf("加载插件失败: %v\n", err) - os.Exit(1) + return } // 初始化所有插件 if err := pm.InitPlugins(ctx); err != nil { fmt.Printf("初始化插件失败: %v\n", err) - os.Exit(1) + return } // 启动所有插件 if err := pm.StartPlugins(ctx); err != nil { fmt.Printf("启动插件失败: %v\n", err) - os.Exit(1) + return } // 打印所有插件信息 @@ -125,7 +146,7 @@ func main() { // 确保所有剩余插件都被停止 if err := pm.StopPlugins(ctx); err != nil { fmt.Printf("停止剩余插件失败: %v\n", err) - os.Exit(1) + return } fmt.Println("\n所有插件已停止") diff --git a/examples/plugin/example/run.sh b/examples/plugin/example/run.sh new file mode 100644 index 0000000..e8fe628 --- /dev/null +++ b/examples/plugin/example/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# 首先编译所有插件 +echo "===== 编译插件 =====" +cd ../plugins +./build.sh +cd ../example + +# 编译示例程序 +echo "===== 编译示例程序 =====" +go build -o plugin_demo + +# 运行示例程序 +echo "===== 运行示例程序 =====" +./plugin_demo \ No newline at end of file diff --git a/examples/plugin/interface.go b/examples/plugin/interface.go index eddd78c..5de303d 100644 --- a/examples/plugin/interface.go +++ b/examples/plugin/interface.go @@ -1,5 +1,9 @@ package plugin +import ( + "fmt" +) + // PluginType 插件类型 type PluginType string @@ -8,10 +12,10 @@ const ( PluginTypeGeneral PluginType = "general" // 通用插件 PluginTypeStorage PluginType = "storage" // 存储插件 PluginTypeSecurity PluginType = "security" // 安全插件 - PluginTypeUI PluginType = "ui" // 用户界面插件 PluginTypeNetwork PluginType = "network" // 网络插件 PluginTypeUtils PluginType = "utils" // 工具插件 PluginTypeHardware PluginType = "hardware" // 硬件插件 + PluginTypeUI PluginType = "ui" // 用户界面插件 // 可以根据需求添加更多插件类型 ) @@ -39,6 +43,11 @@ type IPlugin interface { IsEnabled() bool // SetEnabled 设置插件启用状态 SetEnabled(enabled bool) + // Execute 执行插件功能 + // action: 要执行的操作名称 + // params: 操作所需的参数 + // 返回操作结果和可能的错误 + Execute(action string, params map[string]interface{}) (interface{}, error) } // BasePlugin 提供插件接口的基本实现 @@ -119,3 +128,8 @@ func (p *BasePlugin) Start() error { func (p *BasePlugin) Stop() error { return nil } + +// Execute 执行插件功能,子类需要重写此方法 +func (p *BasePlugin) Execute(action string, params map[string]interface{}) (interface{}, error) { + return nil, fmt.Errorf("插件 %s 不支持 %s 操作", p.name, action) +} diff --git a/examples/plugin/manager/plugin_manager.go b/examples/plugin/manager/plugin_manager.go index 00eb80c..891aefa 100644 --- a/examples/plugin/manager/plugin_manager.go +++ b/examples/plugin/manager/plugin_manager.go @@ -94,6 +94,47 @@ func (p *LogPlugin) Stop(ctx context.Context) error { return nil } +// Execute 实现Execute方法以满足Plugin接口 +func (p *LogPlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) { + switch action { + case "log": + // 需要参数: message + message, ok := params["message"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: message") + } + p.Log(message) + return true, nil + + case "setLevel": + // 需要参数: level + level, ok := params["level"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: level") + } + p.level = level + return true, nil + + case "getLevel": + // 不需要参数,返回当前日志级别 + return p.level, nil + + case "getStatus": + // 返回插件状态信息 + status := map[string]interface{}{ + "name": p.name, + "version": p.version, + "level": p.level, + "enabled": p.enabled, + "type": p.Type(), + } + return status, nil + + default: + return nil, fmt.Errorf("未知的操作: %s", action) + } +} + // Log 记录日志 func (p *LogPlugin) Log(message string) { fmt.Printf("[%s][%s] %s\n", p.name, p.level, message) @@ -179,6 +220,10 @@ func main() { // 这里可以根据插件类型执行特定操作 if logPlugin, ok := p.(*LogPlugin); ok { logPlugin.Log("这是一条测试日志消息") + // 改用Execute方法调用 + logPlugin.Execute(ctx, "log", map[string]interface{}{ + "message": "这是一条测试日志消息", + }) } } break @@ -196,6 +241,10 @@ func main() { fmt.Printf("工具类插件: %s\n", p.Name()) if logPlugin, ok := p.(*LogPlugin); ok { logPlugin.Log("通过类型获取到的日志插件记录消息") + // 改用Execute方法调用 + logPlugin.Execute(ctx, "log", map[string]interface{}{ + "message": "通过类型获取到的日志插件记录消息", + }) } } @@ -206,6 +255,10 @@ func main() { fmt.Printf("通用类型插件: %s\n", p.Name()) if logPlugin, ok := p.(*LogPlugin); ok { logPlugin.Log("通过类型获取到的通用类型插件记录消息") + // 改用Execute方法调用 + logPlugin.Execute(ctx, "log", map[string]interface{}{ + "message": "通过类型获取到的通用类型插件记录消息", + }) } } diff --git a/examples/plugin/plugin.go b/examples/plugin/plugin.go index 03d8670..56402ce 100644 --- a/examples/plugin/plugin.go +++ b/examples/plugin/plugin.go @@ -35,6 +35,11 @@ type Plugin interface { IsEnabled() bool // SetEnabled 设置插件启用状态 SetEnabled(enabled bool) + // Execute 执行插件功能 + // action: 要执行的操作名称 + // params: 操作所需的参数 + // 返回操作结果和可能的错误 + Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) } // BasePluginImpl 提供插件接口的基本实现,用于适配Plugin接口 @@ -72,6 +77,11 @@ func (p *BasePluginImpl) Stop(ctx context.Context) error { return p.BasePlugin.Stop() } +// Execute 适配Execute方法以支持context参数 +func (p *BasePluginImpl) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) { + return p.BasePlugin.Execute(action, params) +} + // PluginInfo 插件信息 type PluginInfo struct { Name string `json:"name"` @@ -577,3 +587,66 @@ func (pm *PluginManager) GetPluginConfig(name string) (map[string]interface{}, e return config, nil } + +// ExecutePlugin 执行指定插件的操作 +func (pm *PluginManager) ExecutePlugin(ctx context.Context, name string, action string, params map[string]interface{}) (interface{}, error) { + pm.mu.RLock() + defer pm.mu.RUnlock() + + plugin, exists := pm.plugins[name] + if !exists { + return nil, fmt.Errorf("插件 %s 不存在", name) + } + + if !plugin.IsEnabled() { + return nil, fmt.Errorf("插件 %s 已禁用", name) + } + + return plugin.Execute(ctx, action, params) +} + +// ExecutePluginsByType 对指定类型的所有插件执行操作 +func (pm *PluginManager) ExecutePluginsByType(ctx context.Context, pluginType PluginType, action string, params map[string]interface{}) map[string]interface{} { + pm.mu.RLock() + defer pm.mu.RUnlock() + + results := make(map[string]interface{}) + + if typePlugins, exists := pm.pluginsByType[pluginType]; exists { + for name, plugin := range typePlugins { + if !plugin.IsEnabled() { + continue + } + + result, err := plugin.Execute(ctx, action, params) + results[name] = map[string]interface{}{ + "result": result, + "error": err, + } + } + } + + return results +} + +// ExecuteAllPlugins 对所有插件执行操作 +func (pm *PluginManager) ExecuteAllPlugins(ctx context.Context, action string, params map[string]interface{}) map[string]interface{} { + pm.mu.RLock() + defer pm.mu.RUnlock() + + results := make(map[string]interface{}) + + for name, plugin := range pm.plugins { + if !plugin.IsEnabled() { + continue + } + + result, err := plugin.Execute(ctx, action, params) + results[name] = map[string]interface{}{ + "result": result, + "error": err, + } + } + + return results +} diff --git a/examples/plugin/plugins/logger/logger_plugin.go b/examples/plugin/plugins/logger/logger_plugin.go index 3cb985e..9092acf 100644 --- a/examples/plugin/plugins/logger/logger_plugin.go +++ b/examples/plugin/plugins/logger/logger_plugin.go @@ -104,6 +104,62 @@ func (p *LoggerPlugin) Stop(ctx context.Context) error { return nil } +// Execute 执行插件功能 +func (p *LoggerPlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) { + switch action { + case "log": + // 需要参数: level, message + level, ok := params["level"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: level") + } + message, ok := params["message"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: message") + } + p.Log(level, message) + return true, nil + + case "info": + // 需要参数: message + message, ok := params["message"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: message") + } + p.Info(message) + return true, nil + + case "warn": + // 需要参数: message + message, ok := params["message"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: message") + } + p.Warn(message) + return true, nil + + case "error": + // 需要参数: message + message, ok := params["message"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: message") + } + p.Error(message) + return true, nil + + case "getLoggerStatus": + // 不需要参数 + status := map[string]interface{}{ + "initialized": p.logger != nil, + "config": p.config, + } + return status, nil + + default: + return nil, fmt.Errorf("未知的操作: %s", action) + } +} + // Log 记录日志 func (p *LoggerPlugin) Log(level, message string) { if p.logger == nil { diff --git a/examples/plugin/plugins/stats/stats_plugin.go b/examples/plugin/plugins/stats/stats_plugin.go index 6cb94da..1015394 100644 --- a/examples/plugin/plugins/stats/stats_plugin.go +++ b/examples/plugin/plugins/stats/stats_plugin.go @@ -109,6 +109,115 @@ func (p *StatsPlugin) Stop(ctx context.Context) error { return nil } +// Execute 执行插件功能 +func (p *StatsPlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) { + switch action { + case "incrementStat": + // 需要参数: name, value + name, ok := params["name"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: name") + } + + // 处理整数值参数 + var value int64 + if floatValue, ok := params["value"].(float64); ok { + value = int64(floatValue) + } else if strValue, ok := params["value"].(string); ok { + var err error + _, err = fmt.Sscanf(strValue, "%d", &value) + if err != nil { + return nil, fmt.Errorf("参数value必须是整数: %v", err) + } + } else { + return nil, fmt.Errorf("缺少必需参数: value") + } + + p.IncrementStat(name, value) + return true, nil + + case "getStat": + // 需要参数: name + name, ok := params["name"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: name") + } + + value := p.GetStat(name) + return value, nil + + case "getAllStats": + // 不需要参数 + return p.GetAllStats(), nil + + case "recordRequest": + // 需要参数: bytesReceived, bytesSent, isError + var bytesReceived, bytesSent int64 + var isError bool + + // 处理bytesReceived参数 + if floatValue, ok := params["bytesReceived"].(float64); ok { + bytesReceived = int64(floatValue) + } else { + return nil, fmt.Errorf("缺少必需参数: bytesReceived") + } + + // 处理bytesSent参数 + if floatValue, ok := params["bytesSent"].(float64); ok { + bytesSent = int64(floatValue) + } else { + return nil, fmt.Errorf("缺少必需参数: bytesSent") + } + + // 处理isError参数 + if value, ok := params["isError"].(bool); ok { + isError = value + } + + p.RecordRequest(bytesReceived, bytesSent, isError) + return true, nil + + case "resetStats": + // 不需要参数 + p.mu.Lock() + p.stats = make(map[string]int64) + p.stats["requests"] = 0 + p.stats["errors"] = 0 + p.stats["bytes_sent"] = 0 + p.stats["bytes_received"] = 0 + p.startTime = time.Now() + p.mu.Unlock() + return true, nil + + case "getStatsReport": + // 生成统计报告 + report := p.generateStatsReport() + return report, nil + + default: + return nil, fmt.Errorf("未知的操作: %s", action) + } +} + +// generateStatsReport 生成统计报告 +func (p *StatsPlugin) generateStatsReport() map[string]interface{} { + p.mu.RLock() + defer p.mu.RUnlock() + + uptime := time.Since(p.startTime).Seconds() + report := map[string]interface{}{ + "uptime_seconds": uptime, + "stats": p.stats, + } + + if uptime > 0 && p.stats["requests"] > 0 { + report["requests_per_second"] = float64(p.stats["requests"]) / uptime + report["error_rate"] = float64(p.stats["errors"]) * 100 / float64(p.stats["requests"]) + } + + return report +} + // logStats 记录当前统计信息 func (p *StatsPlugin) logStats() { p.mu.RLock() diff --git a/examples/plugin/plugins/storage/storage_plugin.go b/examples/plugin/plugins/storage/storage_plugin.go index 786a200..f4f4771 100644 --- a/examples/plugin/plugins/storage/storage_plugin.go +++ b/examples/plugin/plugins/storage/storage_plugin.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/base64" "fmt" "os" "path/filepath" @@ -69,6 +70,83 @@ func (p *StoragePlugin) Stop(ctx context.Context) error { return nil } +// Execute 执行插件功能 +func (p *StoragePlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) { + switch action { + case "saveFile": + // 需要参数: filename, data + filename, ok := params["filename"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: filename") + } + + // 处理两种数据格式:字符串或Base64编码的二进制数据 + var data []byte + if dataStr, ok := params["data"].(string); ok { + // 检查是否为Base64编码 + if base64Str, ok := params["isBase64"].(bool); ok && base64Str { + var err error + data, err = base64.StdEncoding.DecodeString(dataStr) + if err != nil { + return nil, fmt.Errorf("Base64解码失败: %v", err) + } + } else { + data = []byte(dataStr) + } + } else { + return nil, fmt.Errorf("缺少必需参数: data") + } + + err := p.SaveFile(filename, data) + return err == nil, err + + case "loadFile": + // 需要参数: filename, returnBase64 + filename, ok := params["filename"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: filename") + } + + returnBase64, _ := params["returnBase64"].(bool) + + data, err := p.LoadFile(filename) + if err != nil { + return nil, err + } + + if returnBase64 { + return base64.StdEncoding.EncodeToString(data), nil + } + return string(data), nil + + case "deleteFile": + // 需要参数: filename + filename, ok := params["filename"].(string) + if !ok { + return nil, fmt.Errorf("缺少必需参数: filename") + } + + err := p.DeleteFile(filename) + return err == nil, err + + case "listFiles": + // 不需要参数 + files, err := p.ListFiles() + return files, err + + case "getStorageInfo": + // 不需要参数 + info := map[string]interface{}{ + "storageDir": p.storageDir, + "config": p.config, + } + return info, nil + + default: + return nil, fmt.Errorf("未知的操作: %s", action) + } +} + // SaveFile 保存文件 func (p *StoragePlugin) SaveFile(filename string, data []byte) error { p.mu.Lock()