diff --git a/examples/plugin/interface.go b/examples/plugin/interface.go index 3dcc5e9..eddd78c 100644 --- a/examples/plugin/interface.go +++ b/examples/plugin/interface.go @@ -11,6 +11,7 @@ const ( PluginTypeUI PluginType = "ui" // 用户界面插件 PluginTypeNetwork PluginType = "network" // 网络插件 PluginTypeUtils PluginType = "utils" // 工具插件 + PluginTypeHardware PluginType = "hardware" // 硬件插件 // 可以根据需求添加更多插件类型 ) @@ -63,6 +64,12 @@ func NewBasePlugin(name, version, description, author string, pluginType PluginT } } +// NewBasePluginWithDefaultType 创建一个基本插件,使用默认的通用插件类型 +// 这是一个便捷的构造函数,适用于不需要指定特殊类型的场景 +func NewBasePluginWithDefaultType(name, version, description, author string) *BasePlugin { + return NewBasePlugin(name, version, description, author, PluginTypeGeneral) +} + // Name 获取插件名称 func (p *BasePlugin) Name() string { return p.name diff --git a/examples/plugin/manager/plugin_manager.go b/examples/plugin/manager/plugin_manager.go index 7acbd1a..00eb80c 100644 --- a/examples/plugin/manager/plugin_manager.go +++ b/examples/plugin/manager/plugin_manager.go @@ -15,19 +15,32 @@ type LogPlugin struct { version string description string author string + pluginType plugin.PluginType enabled bool level string - pluginType plugin.PluginType } -// 创建内置日志插件 +// 创建内置日志插件 - 示例1:明确指定插件类型 func NewLogPlugin() *LogPlugin { return &LogPlugin{ name: "InternalLogPlugin", version: "1.0.0", description: "内置日志插件,在不支持动态加载插件的平台上使用", author: "开发者", - pluginType: plugin.PluginTypeUtils, // 设置为工具类插件 + pluginType: plugin.PluginTypeUtils, // 明确指定为工具类插件 + enabled: true, + level: "info", + } +} + +// 创建内置日志插件 - 示例2:使用默认插件类型(通用插件) +func NewDefaultLogPlugin() *LogPlugin { + return &LogPlugin{ + name: "DefaultLogPlugin", + version: "1.0.0", + description: "使用默认类型的内置日志插件示例", + author: "开发者", + pluginType: plugin.PluginTypeGeneral, // 自动设置为通用插件类型 enabled: true, level: "info", } @@ -67,23 +80,23 @@ func (p *LogPlugin) Init(ctx context.Context, config map[string]interface{}) err if level, ok := config["level"].(string); ok { p.level = level } - fmt.Println("内置日志插件已初始化,日志级别:", p.level) + fmt.Printf("内置日志插件[%s]已初始化,日志级别: %s, 插件类型: %s\n", p.name, p.level, p.Type()) return nil } func (p *LogPlugin) Start(ctx context.Context) error { - fmt.Println("内置日志插件已启动") + fmt.Printf("内置日志插件[%s]已启动\n", p.name) return nil } func (p *LogPlugin) Stop(ctx context.Context) error { - fmt.Println("内置日志插件已停止") + fmt.Printf("内置日志插件[%s]已停止\n", p.name) return nil } // Log 记录日志 func (p *LogPlugin) Log(message string) { - fmt.Printf("[%s] %s\n", p.level, message) + fmt.Printf("[%s][%s] %s\n", p.name, p.level, message) } func main() { @@ -97,9 +110,16 @@ func main() { } else { fmt.Printf("当前系统(%s)不支持动态加载插件\n", runtime.GOOS) - // 在不支持动态加载的系统上使用内置插件 + // 在不支持动态加载的系统上注册内置插件 + // 示例1:注册明确指定类型的插件 logPlugin := NewLogPlugin() pm.RegisterPlugin(logPlugin) + + // 示例2:注册使用默认类型的插件 + defaultLogPlugin := NewDefaultLogPlugin() + pm.RegisterPlugin(defaultLogPlugin) + + fmt.Println("已注册两个内置插件以展示不同的插件类型设置方式") } // 加载插件 @@ -154,7 +174,7 @@ func main() { if len(plugins) > 0 { for _, info := range plugins { if info.Enabled { - fmt.Printf("正在使用插件: %s\n", info.Name) + fmt.Printf("正在使用插件: %s (类型: %s)\n", info.Name, info.Type) if p, ok := pm.GetPlugin(info.Name); ok { // 这里可以根据插件类型执行特定操作 if logPlugin, ok := p.(*LogPlugin); ok { @@ -168,6 +188,8 @@ func main() { // 按类型获取和使用插件 fmt.Println("\n按类型获取插件:") + + // 获取工具类插件 utilsPlugins := pm.GetPluginsByType(plugin.PluginTypeUtils) fmt.Printf("找到 %d 个工具类插件\n", len(utilsPlugins)) for _, p := range utilsPlugins { @@ -177,6 +199,16 @@ func main() { } } + // 获取通用类型插件 + generalPlugins := pm.GetPluginsByType(plugin.PluginTypeGeneral) + fmt.Printf("找到 %d 个通用类型插件\n", len(generalPlugins)) + for _, p := range generalPlugins { + fmt.Printf("通用类型插件: %s\n", p.Name()) + if logPlugin, ok := p.(*LogPlugin); ok { + logPlugin.Log("通过类型获取到的通用类型插件记录消息") + } + } + // 停止插件 fmt.Println("\n正在停止插件...") if err := pm.StopPlugins(ctx); err != nil { diff --git a/examples/plugin/plugin.go b/examples/plugin/plugin.go index fccb6f0..03d8670 100644 --- a/examples/plugin/plugin.go +++ b/examples/plugin/plugin.go @@ -37,6 +37,41 @@ type Plugin interface { SetEnabled(enabled bool) } +// BasePluginImpl 提供插件接口的基本实现,用于适配Plugin接口 +// 这个结构体包装了BasePlugin,以便兼容context参数 +type BasePluginImpl struct { + *BasePlugin +} + +// NewPlugin 创建一个基本插件实现,带有插件类型 +func NewPlugin(name, version, description, author string, pluginType PluginType) *BasePluginImpl { + return &BasePluginImpl{ + BasePlugin: NewBasePlugin(name, version, description, author, pluginType), + } +} + +// NewPluginWithDefaultType 创建一个基本插件实现,使用默认的通用插件类型 +func NewPluginWithDefaultType(name, version, description, author string) *BasePluginImpl { + return &BasePluginImpl{ + BasePlugin: NewBasePluginWithDefaultType(name, version, description, author), + } +} + +// Init 适配Init方法以支持context参数 +func (p *BasePluginImpl) Init(ctx context.Context, config map[string]interface{}) error { + return p.BasePlugin.Init(config) +} + +// Start 适配Start方法以支持context参数 +func (p *BasePluginImpl) Start(ctx context.Context) error { + return p.BasePlugin.Start() +} + +// Stop 适配Stop方法以支持context参数 +func (p *BasePluginImpl) Stop(ctx context.Context) error { + return p.BasePlugin.Stop() +} + // PluginInfo 插件信息 type PluginInfo struct { Name string `json:"name"` diff --git a/examples/plugin/plugins/build.sh b/examples/plugin/plugins/build.sh index d58aa12..2c1e4b1 100644 --- a/examples/plugin/plugins/build.sh +++ b/examples/plugin/plugins/build.sh @@ -1,22 +1,63 @@ #!/bin/bash -# 编译插件 -go build -buildmode=plugin -o stats.so ./stats/stats.go +# 构建脚本,用于编译所有插件 -# 检查编译结果 +# 确保输出目录存在 +mkdir -p dist + +echo "===== 开始编译插件 =====" + +# 编译带有明确类型的日志插件 +echo "编译日志插件 (明确类型)..." +cd logger +go build -buildmode=plugin -o ../dist/logger.so if [ $? -eq 0 ]; then - echo "插件编译成功: stats.so" + echo "日志插件编译成功!" else - echo "插件编译失败" + echo "日志插件编译失败!" exit 1 -fi +fi +cd .. - -go build -buildmode=plugin -o logger.so ./logger/logger.go -# 检查编译结果 +# 编译使用默认类型的日志插件 +echo "编译默认日志插件 (默认类型)..." +cd defaultlogger +go build -buildmode=plugin -o ../dist/defaultlogger.so if [ $? -eq 0 ]; then - echo "插件编译成功: logger.so" + echo "默认日志插件编译成功!" else - echo "插件编译失败" + echo "默认日志插件编译失败!" exit 1 -fi \ No newline at end of file +fi +cd .. + +# 编译统计插件 +echo "编译统计插件..." +cd stats +go build -buildmode=plugin -o ../dist/stats.so +if [ $? -eq 0 ]; then + echo "统计插件编译成功!" +else + echo "统计插件编译失败!" + exit 1 +fi +cd .. + +# 编译存储插件 +echo "编译存储插件..." +cd storage +go build -buildmode=plugin -o ../dist/storage.so +if [ $? -eq 0 ]; then + echo "存储插件编译成功!" +else + echo "存储插件编译失败!" + exit 1 +fi +cd .. + +echo "===== 所有插件编译完成 =====" +echo "插件文件保存在 dist 目录中:" +ls -la dist/ + +# 对于Windows系统,添加.exe后缀 +# go build -buildmode=plugin -o ../dist/plugin_name.dll \ No newline at end of file diff --git a/examples/plugin/plugins/defaultlogger/default_logger_plugin.go b/examples/plugin/plugins/defaultlogger/default_logger_plugin.go new file mode 100644 index 0000000..fad6541 --- /dev/null +++ b/examples/plugin/plugins/defaultlogger/default_logger_plugin.go @@ -0,0 +1,128 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/darkit/goproxy/examples/plugin" +) + +// DefaultLoggerPlugin 默认日志插件 +// 提供文件日志和控制台日志功能,使用默认插件类型 +type DefaultLoggerPlugin struct { + *plugin.BasePlugin // 嵌入基本插件结构 + logFile *os.File // 日志文件 + logger *log.Logger // 日志记录器 + config map[string]interface{} // 配置 +} + +// Plugin 导出的插件变量 +// 注意:变量名必须是Plugin,大小写敏感 +// 这个插件使用默认的通用插件类型(PluginTypeGeneral) +var Plugin = &DefaultLoggerPlugin{ + BasePlugin: plugin.NewBasePluginWithDefaultType( + "DefaultLoggerPlugin", + "1.0.0", + "使用默认通用类型的日志记录插件", + "开发者", + ), // 将自动使用 PluginTypeGeneral 类型 +} + +// Init 初始化插件 +func (p *DefaultLoggerPlugin) Init(ctx context.Context, config map[string]interface{}) error { + p.config = config + + // 获取日志文件路径 + logPath, ok := config["log_path"].(string) + if !ok { + // 使用默认路径 + logPath = "logs/default" + } + + // 确保日志目录存在 + if err := os.MkdirAll(logPath, 0o755); err != nil { + return fmt.Errorf("创建日志目录失败: %v", err) + } + + // 创建日志文件 + logFilePath := filepath.Join(logPath, fmt.Sprintf("default_app_%s.log", time.Now().Format("2006-01-02"))) + logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) + if err != nil { + return fmt.Errorf("打开日志文件失败: %v", err) + } + + p.logFile = logFile + p.logger = log.New(logFile, "[DefaultLoggerPlugin] ", log.LstdFlags) + + p.logger.Println("默认日志插件初始化完成") + fmt.Printf("默认日志插件初始化完成,日志文件: %s,插件类型: %s\n", logFilePath, p.Type()) + + return nil +} + +// Start 启动插件 +func (p *DefaultLoggerPlugin) Start(ctx context.Context) error { + if p.logger == nil { + return fmt.Errorf("插件未初始化") + } + + p.logger.Println("默认日志插件已启动") + fmt.Println("默认日志插件已启动") + return nil +} + +// Stop 停止插件 +func (p *DefaultLoggerPlugin) Stop(ctx context.Context) error { + if p.logger != nil { + p.logger.Println("默认日志插件正在停止") + } + + if p.logFile != nil { + if err := p.logFile.Close(); err != nil { + return fmt.Errorf("关闭日志文件失败: %v", err) + } + } + + fmt.Println("默认日志插件已停止") + return nil +} + +// Log 记录日志 +func (p *DefaultLoggerPlugin) Log(level, message string) { + if p.logger == nil { + fmt.Printf("[DEFAULT][%s] %s\n", level, message) + return + } + + logMsg := fmt.Sprintf("[%s] %s", level, message) + p.logger.Println(logMsg) + + // 如果配置了同时输出到控制台 + if consoleOutput, ok := p.config["console_output"].(bool); ok && consoleOutput { + fmt.Println(logMsg) + } +} + +// Info 记录信息日志 +func (p *DefaultLoggerPlugin) Info(message string) { + p.Log("INFO", message) +} + +// Warn 记录警告日志 +func (p *DefaultLoggerPlugin) Warn(message string) { + p.Log("WARN", message) +} + +// Error 记录错误日志 +func (p *DefaultLoggerPlugin) Error(message string) { + p.Log("ERROR", message) +} + +// main 函数是必须的,但不会被调用 +func main() { + // 不会被执行,仅用于编译插件 +} diff --git a/examples/plugin/plugins/logger/logger_plugin.go b/examples/plugin/plugins/logger/logger_plugin.go index 42f017b..3cb985e 100644 --- a/examples/plugin/plugins/logger/logger_plugin.go +++ b/examples/plugin/plugins/logger/logger_plugin.go @@ -22,16 +22,29 @@ type LoggerPlugin struct { // Plugin 导出的插件变量 // 注意:变量名必须是Plugin,大小写敏感 +// 使用方式1: 明确指定插件类型 var Plugin = &LoggerPlugin{ BasePlugin: plugin.NewBasePlugin( "LoggerPlugin", "1.0.0", "简单的日志记录插件", "开发者", - plugin.PluginTypeUtils, // 设置插件类型为工具插件 + plugin.PluginTypeUtils, // 明确指定为工具类插件 ), } +// 使用方式2: 使用默认插件类型(通用插件) +// 如果您不关心插件类型或想使用默认的通用插件类型,可以使用以下方式: +// +// var Plugin = &LoggerPlugin{ +// BasePlugin: plugin.NewBasePluginWithDefaultType( +// "LoggerPlugin", +// "1.0.0", +// "简单的日志记录插件", +// "开发者", +// ), // 将自动使用 PluginTypeGeneral 类型 +// } + // Init 初始化插件 func (p *LoggerPlugin) Init(ctx context.Context, config map[string]interface{}) error { p.config = config @@ -59,7 +72,7 @@ func (p *LoggerPlugin) Init(ctx context.Context, config map[string]interface{}) p.logger = log.New(logFile, "[LoggerPlugin] ", log.LstdFlags) p.logger.Println("日志插件初始化完成") - fmt.Println("日志插件初始化完成,日志文件:", logFilePath) + fmt.Printf("日志插件初始化完成,日志文件: %s,插件类型: %s\n", logFilePath, p.Type()) return nil } diff --git a/examples/plugin/plugins/stats/stats_plugin.go b/examples/plugin/plugins/stats/stats_plugin.go index a51cfb7..6cb94da 100644 --- a/examples/plugin/plugins/stats/stats_plugin.go +++ b/examples/plugin/plugins/stats/stats_plugin.go @@ -23,17 +23,30 @@ type StatsPlugin struct { // Plugin 导出的插件变量 var Plugin = &StatsPlugin{ - BasePlugin: plugin.NewBasePlugin( + // 使用默认构造函数,不指定插件类型,将默认为通用插件 + BasePlugin: plugin.NewBasePluginWithDefaultType( "StatsPlugin", "1.0.0", "系统运行时统计插件", "开发者", - plugin.PluginTypeUtils, // 设置为工具类插件 ), stats: make(map[string]int64), tickerStop: make(chan bool), } +// 为展示如何指定类型,我们也可以显式设置插件类型 +// var Plugin = &StatsPlugin{ +// BasePlugin: plugin.NewBasePlugin( +// "StatsPlugin", +// "1.0.0", +// "系统运行时统计插件", +// "开发者", +// plugin.PluginTypeUtils, // 明确指定为工具类插件 +// ), +// stats: make(map[string]int64), +// tickerStop: make(chan bool), +// } + // Init 初始化插件 func (p *StatsPlugin) Init(ctx context.Context, config map[string]interface{}) error { p.config = config