增强插件系统:添加插件类型支持
- 在插件接口和基本插件结构中引入插件类型(PluginType),并定义了多种预定义的插件类型。 - 更新插件管理器以支持按类型管理插件,新增按类型获取、初始化和启动插件的方法。 - 修改现有插件(如日志插件和统计插件)以实现插件类型接口,确保兼容性。 - 优化插件信息输出,包含插件类型信息。 此更新提升了插件系统的灵活性和可扩展性,便于未来添加更多插件类型。
This commit is contained in:
132
examples/plugin/example/main.go
Normal file
132
examples/plugin/example/main.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/darkit/goproxy/examples/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 创建上下文
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 获取插件目录
|
||||||
|
pluginsDir := filepath.Join("..", "plugins")
|
||||||
|
if _, err := os.Stat(pluginsDir); os.IsNotExist(err) {
|
||||||
|
if err := os.MkdirAll(pluginsDir, 0o755); err != nil {
|
||||||
|
fmt.Printf("创建插件目录失败: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建插件管理器
|
||||||
|
pm := plugin.NewPluginManager(pluginsDir)
|
||||||
|
|
||||||
|
// 检查是否支持动态加载插件
|
||||||
|
if pm.IsDynamicLoadingSupported() {
|
||||||
|
fmt.Println("当前系统支持动态加载插件")
|
||||||
|
} else {
|
||||||
|
fmt.Println("当前系统不支持动态加载插件,将使用静态插件")
|
||||||
|
|
||||||
|
// 在不支持动态加载的平台上注册内置插件
|
||||||
|
// 这里需要导入并注册所有内置插件
|
||||||
|
// 例如:pm.RegisterPlugin(logger.Plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载插件
|
||||||
|
if err := pm.LoadPlugins(); err != nil {
|
||||||
|
fmt.Printf("加载插件失败: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化所有插件
|
||||||
|
if err := pm.InitPlugins(ctx); err != nil {
|
||||||
|
fmt.Printf("初始化插件失败: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动所有插件
|
||||||
|
if err := pm.StartPlugins(ctx); err != nil {
|
||||||
|
fmt.Printf("启动插件失败: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印所有插件信息
|
||||||
|
fmt.Println("\n=== 所有已加载的插件 ===")
|
||||||
|
for _, info := range pm.GetPluginInfos() {
|
||||||
|
fmt.Printf("插件名称: %s\n", info.Name)
|
||||||
|
fmt.Printf("版本: %s\n", info.Version)
|
||||||
|
fmt.Printf("描述: %s\n", info.Description)
|
||||||
|
fmt.Printf("作者: %s\n", info.Author)
|
||||||
|
fmt.Printf("类型: %s\n", info.Type)
|
||||||
|
fmt.Printf("启用状态: %v\n", info.Enabled)
|
||||||
|
fmt.Println("---")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按类型获取插件
|
||||||
|
fmt.Println("\n=== 按类型获取插件 ===")
|
||||||
|
|
||||||
|
// 获取所有存储类型插件
|
||||||
|
storagePlugins := pm.GetPluginsByType(plugin.PluginTypeStorage)
|
||||||
|
fmt.Printf("存储插件数量: %d\n", len(storagePlugins))
|
||||||
|
for _, p := range storagePlugins {
|
||||||
|
fmt.Printf("存储插件: %s (版本: %s)\n", p.Name(), p.Version())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有工具类型插件
|
||||||
|
utilsPlugins := pm.GetPluginsByType(plugin.PluginTypeUtils)
|
||||||
|
fmt.Printf("工具插件数量: %d\n", len(utilsPlugins))
|
||||||
|
for _, p := range utilsPlugins {
|
||||||
|
fmt.Printf("工具插件: %s (版本: %s)\n", p.Name(), p.Version())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在生命周期的不同阶段按类型初始化和启动插件
|
||||||
|
fmt.Println("\n=== 按类型初始化和启动插件 ===")
|
||||||
|
|
||||||
|
// 例如,在应用程序启动阶段只初始化工具插件
|
||||||
|
if err := pm.InitPluginsByType(ctx, plugin.PluginTypeUtils); err != nil {
|
||||||
|
fmt.Printf("初始化工具插件失败: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("工具插件初始化成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在需要存储功能时初始化存储插件
|
||||||
|
if err := pm.InitPluginsByType(ctx, plugin.PluginTypeStorage); err != nil {
|
||||||
|
fmt.Printf("初始化存储插件失败: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("存储插件初始化成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用特定类型的插件示例
|
||||||
|
fmt.Println("\n=== 使用特定类型的插件示例 ===")
|
||||||
|
fmt.Println("注意:这部分代码在真实环境中需要使用类型断言或接口来处理")
|
||||||
|
fmt.Println("在实际应用中,应该为每种类型的插件定义专门的接口")
|
||||||
|
|
||||||
|
// 按类型停止插件
|
||||||
|
fmt.Println("\n=== 按类型停止插件 ===")
|
||||||
|
|
||||||
|
// 首先停止存储插件
|
||||||
|
if err := pm.StopPluginsByType(ctx, plugin.PluginTypeStorage); err != nil {
|
||||||
|
fmt.Printf("停止存储插件失败: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("存储插件已停止")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 然后停止工具插件
|
||||||
|
if err := pm.StopPluginsByType(ctx, plugin.PluginTypeUtils); err != nil {
|
||||||
|
fmt.Printf("停止工具插件失败: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("工具插件已停止")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保所有剩余插件都被停止
|
||||||
|
if err := pm.StopPlugins(ctx); err != nil {
|
||||||
|
fmt.Printf("停止剩余插件失败: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n所有插件已停止")
|
||||||
|
}
|
@@ -1,5 +1,19 @@
|
|||||||
package plugin
|
package plugin
|
||||||
|
|
||||||
|
// PluginType 插件类型
|
||||||
|
type PluginType string
|
||||||
|
|
||||||
|
// 预定义的插件类型
|
||||||
|
const (
|
||||||
|
PluginTypeGeneral PluginType = "general" // 通用插件
|
||||||
|
PluginTypeStorage PluginType = "storage" // 存储插件
|
||||||
|
PluginTypeSecurity PluginType = "security" // 安全插件
|
||||||
|
PluginTypeUI PluginType = "ui" // 用户界面插件
|
||||||
|
PluginTypeNetwork PluginType = "network" // 网络插件
|
||||||
|
PluginTypeUtils PluginType = "utils" // 工具插件
|
||||||
|
// 可以根据需求添加更多插件类型
|
||||||
|
)
|
||||||
|
|
||||||
// IPlugin 插件接口
|
// IPlugin 插件接口
|
||||||
// 这个文件定义了所有插件必须实现的接口
|
// 这个文件定义了所有插件必须实现的接口
|
||||||
// 注意:这个文件应该与实际插件代码一起编译
|
// 注意:这个文件应该与实际插件代码一起编译
|
||||||
@@ -12,6 +26,8 @@ type IPlugin interface {
|
|||||||
Description() string
|
Description() string
|
||||||
// Author 插件作者
|
// Author 插件作者
|
||||||
Author() string
|
Author() string
|
||||||
|
// Type 插件类型
|
||||||
|
Type() PluginType
|
||||||
// Init 初始化插件
|
// Init 初始化插件
|
||||||
Init(config map[string]interface{}) error
|
Init(config map[string]interface{}) error
|
||||||
// Start 启动插件
|
// Start 启动插件
|
||||||
@@ -31,16 +47,18 @@ type BasePlugin struct {
|
|||||||
version string
|
version string
|
||||||
description string
|
description string
|
||||||
author string
|
author string
|
||||||
|
pluginType PluginType
|
||||||
enabled bool
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBasePlugin 创建一个基本插件
|
// NewBasePlugin 创建一个基本插件
|
||||||
func NewBasePlugin(name, version, description, author string) *BasePlugin {
|
func NewBasePlugin(name, version, description, author string, pluginType PluginType) *BasePlugin {
|
||||||
return &BasePlugin{
|
return &BasePlugin{
|
||||||
name: name,
|
name: name,
|
||||||
version: version,
|
version: version,
|
||||||
description: description,
|
description: description,
|
||||||
author: author,
|
author: author,
|
||||||
|
pluginType: pluginType,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,6 +83,11 @@ func (p *BasePlugin) Author() string {
|
|||||||
return p.author
|
return p.author
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type 获取插件类型
|
||||||
|
func (p *BasePlugin) Type() PluginType {
|
||||||
|
return p.pluginType
|
||||||
|
}
|
||||||
|
|
||||||
// IsEnabled 插件是否启用
|
// IsEnabled 插件是否启用
|
||||||
func (p *BasePlugin) IsEnabled() bool {
|
func (p *BasePlugin) IsEnabled() bool {
|
||||||
return p.enabled
|
return p.enabled
|
||||||
|
@@ -17,6 +17,7 @@ type LogPlugin struct {
|
|||||||
author string
|
author string
|
||||||
enabled bool
|
enabled bool
|
||||||
level string
|
level string
|
||||||
|
pluginType plugin.PluginType
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建内置日志插件
|
// 创建内置日志插件
|
||||||
@@ -26,6 +27,7 @@ func NewLogPlugin() *LogPlugin {
|
|||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
description: "内置日志插件,在不支持动态加载插件的平台上使用",
|
description: "内置日志插件,在不支持动态加载插件的平台上使用",
|
||||||
author: "开发者",
|
author: "开发者",
|
||||||
|
pluginType: plugin.PluginTypeUtils, // 设置为工具类插件
|
||||||
enabled: true,
|
enabled: true,
|
||||||
level: "info",
|
level: "info",
|
||||||
}
|
}
|
||||||
@@ -48,6 +50,11 @@ func (p *LogPlugin) Author() string {
|
|||||||
return p.author
|
return p.author
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type 实现插件类型方法
|
||||||
|
func (p *LogPlugin) Type() plugin.PluginType {
|
||||||
|
return p.pluginType
|
||||||
|
}
|
||||||
|
|
||||||
func (p *LogPlugin) IsEnabled() bool {
|
func (p *LogPlugin) IsEnabled() bool {
|
||||||
return p.enabled
|
return p.enabled
|
||||||
}
|
}
|
||||||
@@ -130,8 +137,8 @@ func main() {
|
|||||||
if !info.Enabled {
|
if !info.Enabled {
|
||||||
status = "禁用"
|
status = "禁用"
|
||||||
}
|
}
|
||||||
fmt.Printf("[%d] %s (v%s) - %s [%s]\n作者: %s\n",
|
fmt.Printf("[%d] %s (v%s) - %s [%s]\n作者: %s\n类型: %s\n",
|
||||||
i, info.Name, info.Version, info.Description, status, info.Author)
|
i, info.Name, info.Version, info.Description, status, info.Author, info.Type)
|
||||||
|
|
||||||
// 打印插件配置
|
// 打印插件配置
|
||||||
if len(info.Config) > 0 {
|
if len(info.Config) > 0 {
|
||||||
@@ -159,6 +166,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按类型获取和使用插件
|
||||||
|
fmt.Println("\n按类型获取插件:")
|
||||||
|
utilsPlugins := pm.GetPluginsByType(plugin.PluginTypeUtils)
|
||||||
|
fmt.Printf("找到 %d 个工具类插件\n", len(utilsPlugins))
|
||||||
|
for _, p := range utilsPlugins {
|
||||||
|
fmt.Printf("工具类插件: %s\n", p.Name())
|
||||||
|
if logPlugin, ok := p.(*LogPlugin); ok {
|
||||||
|
logPlugin.Log("通过类型获取到的日志插件记录消息")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 停止插件
|
// 停止插件
|
||||||
fmt.Println("\n正在停止插件...")
|
fmt.Println("\n正在停止插件...")
|
||||||
if err := pm.StopPlugins(ctx); err != nil {
|
if err := pm.StopPlugins(ctx); err != nil {
|
||||||
|
@@ -23,6 +23,8 @@ type Plugin interface {
|
|||||||
Description() string
|
Description() string
|
||||||
// Author 插件作者
|
// Author 插件作者
|
||||||
Author() string
|
Author() string
|
||||||
|
// Type 插件类型
|
||||||
|
Type() PluginType
|
||||||
// Init 初始化插件
|
// Init 初始化插件
|
||||||
Init(ctx context.Context, config map[string]interface{}) error
|
Init(ctx context.Context, config map[string]interface{}) error
|
||||||
// Start 启动插件
|
// Start 启动插件
|
||||||
@@ -41,6 +43,7 @@ type PluginInfo struct {
|
|||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Author string `json:"author"`
|
Author string `json:"author"`
|
||||||
|
Type PluginType `json:"type"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Config map[string]interface{} `json:"config,omitempty"`
|
Config map[string]interface{} `json:"config,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -49,6 +52,7 @@ type PluginInfo struct {
|
|||||||
type PluginManager struct {
|
type PluginManager struct {
|
||||||
pluginsDir string
|
pluginsDir string
|
||||||
plugins map[string]Plugin
|
plugins map[string]Plugin
|
||||||
|
pluginsByType map[PluginType]map[string]Plugin
|
||||||
configs map[string]map[string]interface{}
|
configs map[string]map[string]interface{}
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
dynamicLoadingSupported bool // 是否支持动态加载插件
|
dynamicLoadingSupported bool // 是否支持动态加载插件
|
||||||
@@ -62,6 +66,7 @@ func NewPluginManager(pluginsDir string) *PluginManager {
|
|||||||
return &PluginManager{
|
return &PluginManager{
|
||||||
pluginsDir: pluginsDir,
|
pluginsDir: pluginsDir,
|
||||||
plugins: make(map[string]Plugin),
|
plugins: make(map[string]Plugin),
|
||||||
|
pluginsByType: make(map[PluginType]map[string]Plugin),
|
||||||
configs: make(map[string]map[string]interface{}),
|
configs: make(map[string]map[string]interface{}),
|
||||||
dynamicLoadingSupported: dynamicLoadingSupported,
|
dynamicLoadingSupported: dynamicLoadingSupported,
|
||||||
}
|
}
|
||||||
@@ -156,6 +161,7 @@ func (pm *PluginManager) savePluginConfigs() error {
|
|||||||
config = make(map[string]interface{})
|
config = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
config["enabled"] = plugin.IsEnabled()
|
config["enabled"] = plugin.IsEnabled()
|
||||||
|
config["type"] = string(plugin.Type()) // 保存插件类型
|
||||||
configs[name] = config
|
configs[name] = config
|
||||||
}
|
}
|
||||||
pm.mu.RUnlock()
|
pm.mu.RUnlock()
|
||||||
@@ -213,10 +219,25 @@ func (pm *PluginManager) loadPlugin(path string) error {
|
|||||||
plugin.SetEnabled(true) // 默认启用
|
plugin.SetEnabled(true) // 默认启用
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.plugins[plugin.Name()] = plugin
|
// 注册插件
|
||||||
|
pm.registerPlugin(plugin)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// registerPlugin 注册插件到插件管理器
|
||||||
|
func (pm *PluginManager) registerPlugin(plugin Plugin) {
|
||||||
|
pluginType := plugin.Type()
|
||||||
|
|
||||||
|
// 将插件添加到按名称索引的映射
|
||||||
|
pm.plugins[plugin.Name()] = plugin
|
||||||
|
|
||||||
|
// 将插件添加到按类型索引的映射
|
||||||
|
if pm.pluginsByType[pluginType] == nil {
|
||||||
|
pm.pluginsByType[pluginType] = make(map[string]Plugin)
|
||||||
|
}
|
||||||
|
pm.pluginsByType[pluginType][plugin.Name()] = plugin
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterPlugin 注册内置插件
|
// RegisterPlugin 注册内置插件
|
||||||
// 用于在不支持动态加载的平台上注册插件
|
// 用于在不支持动态加载的平台上注册插件
|
||||||
func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
|
func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
|
||||||
@@ -238,7 +259,8 @@ func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
|
|||||||
plugin.SetEnabled(true) // 默认启用
|
plugin.SetEnabled(true) // 默认启用
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.plugins[plugin.Name()] = plugin
|
// 注册插件
|
||||||
|
pm.registerPlugin(plugin)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +273,36 @@ func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
|
|||||||
return plugin, exists
|
return plugin, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPluginsByType 按类型获取插件
|
||||||
|
func (pm *PluginManager) GetPluginsByType(pluginType PluginType) []Plugin {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
plugins := make([]Plugin, 0)
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for _, plugin := range typePlugins {
|
||||||
|
if plugin.IsEnabled() {
|
||||||
|
plugins = append(plugins, plugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllPluginsByType 获取所有指定类型的插件,无论是否启用
|
||||||
|
func (pm *PluginManager) GetAllPluginsByType(pluginType PluginType) []Plugin {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
plugins := make([]Plugin, 0)
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for _, plugin := range typePlugins {
|
||||||
|
plugins = append(plugins, plugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllPlugins 获取所有插件
|
// GetAllPlugins 获取所有插件
|
||||||
func (pm *PluginManager) GetAllPlugins() []Plugin {
|
func (pm *PluginManager) GetAllPlugins() []Plugin {
|
||||||
pm.mu.RLock()
|
pm.mu.RLock()
|
||||||
@@ -275,6 +327,7 @@ func (pm *PluginManager) GetPluginInfos() []PluginInfo {
|
|||||||
Version: plugin.Version(),
|
Version: plugin.Version(),
|
||||||
Description: plugin.Description(),
|
Description: plugin.Description(),
|
||||||
Author: plugin.Author(),
|
Author: plugin.Author(),
|
||||||
|
Type: plugin.Type(),
|
||||||
Enabled: plugin.IsEnabled(),
|
Enabled: plugin.IsEnabled(),
|
||||||
Config: pm.configs[name],
|
Config: pm.configs[name],
|
||||||
}
|
}
|
||||||
@@ -283,6 +336,29 @@ func (pm *PluginManager) GetPluginInfos() []PluginInfo {
|
|||||||
return infos
|
return infos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPluginInfosByType 按类型获取插件信息
|
||||||
|
func (pm *PluginManager) GetPluginInfosByType(pluginType PluginType) []PluginInfo {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
infos := make([]PluginInfo, 0)
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for name, plugin := range typePlugins {
|
||||||
|
info := PluginInfo{
|
||||||
|
Name: plugin.Name(),
|
||||||
|
Version: plugin.Version(),
|
||||||
|
Description: plugin.Description(),
|
||||||
|
Author: plugin.Author(),
|
||||||
|
Type: plugin.Type(),
|
||||||
|
Enabled: plugin.IsEnabled(),
|
||||||
|
Config: pm.configs[name],
|
||||||
|
}
|
||||||
|
infos = append(infos, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return infos
|
||||||
|
}
|
||||||
|
|
||||||
// EnablePlugin 启用插件
|
// EnablePlugin 启用插件
|
||||||
func (pm *PluginManager) EnablePlugin(name string) error {
|
func (pm *PluginManager) EnablePlugin(name string) error {
|
||||||
pm.mu.Lock()
|
pm.mu.Lock()
|
||||||
@@ -345,6 +421,26 @@ func (pm *PluginManager) InitPlugins(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitPluginsByType 初始化指定类型的所有插件
|
||||||
|
func (pm *PluginManager) InitPluginsByType(ctx context.Context, pluginType PluginType) error {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for name, plugin := range typePlugins {
|
||||||
|
if !plugin.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
config := pm.configs[name]
|
||||||
|
if err := plugin.Init(ctx, config); err != nil {
|
||||||
|
return fmt.Errorf("初始化插件 %s 失败: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// StartPlugins 启动所有插件
|
// StartPlugins 启动所有插件
|
||||||
func (pm *PluginManager) StartPlugins(ctx context.Context) error {
|
func (pm *PluginManager) StartPlugins(ctx context.Context) error {
|
||||||
pm.mu.RLock()
|
pm.mu.RLock()
|
||||||
@@ -362,6 +458,25 @@ func (pm *PluginManager) StartPlugins(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartPluginsByType 启动指定类型的所有插件
|
||||||
|
func (pm *PluginManager) StartPluginsByType(ctx context.Context, pluginType PluginType) error {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for name, plugin := range typePlugins {
|
||||||
|
if !plugin.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := plugin.Start(ctx); err != nil {
|
||||||
|
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// StopPlugins 停止所有插件
|
// StopPlugins 停止所有插件
|
||||||
func (pm *PluginManager) StopPlugins(ctx context.Context) error {
|
func (pm *PluginManager) StopPlugins(ctx context.Context) error {
|
||||||
pm.mu.RLock()
|
pm.mu.RLock()
|
||||||
@@ -379,6 +494,25 @@ func (pm *PluginManager) StopPlugins(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopPluginsByType 停止指定类型的所有插件
|
||||||
|
func (pm *PluginManager) StopPluginsByType(ctx context.Context, pluginType PluginType) error {
|
||||||
|
pm.mu.RLock()
|
||||||
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
|
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||||||
|
for name, plugin := range typePlugins {
|
||||||
|
if !plugin.IsEnabled() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := plugin.Stop(ctx); err != nil {
|
||||||
|
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetPluginConfig 设置插件配置
|
// SetPluginConfig 设置插件配置
|
||||||
func (pm *PluginManager) SetPluginConfig(name string, config map[string]interface{}) error {
|
func (pm *PluginManager) SetPluginConfig(name string, config map[string]interface{}) error {
|
||||||
pm.mu.Lock()
|
pm.mu.Lock()
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -27,11 +28,12 @@ var Plugin = &LoggerPlugin{
|
|||||||
"1.0.0",
|
"1.0.0",
|
||||||
"简单的日志记录插件",
|
"简单的日志记录插件",
|
||||||
"开发者",
|
"开发者",
|
||||||
|
plugin.PluginTypeUtils, // 设置插件类型为工具插件
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init 初始化插件
|
// Init 初始化插件
|
||||||
func (p *LoggerPlugin) Init(config map[string]interface{}) error {
|
func (p *LoggerPlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
||||||
p.config = config
|
p.config = config
|
||||||
|
|
||||||
// 获取日志文件路径
|
// 获取日志文件路径
|
||||||
@@ -63,7 +65,7 @@ func (p *LoggerPlugin) Init(config map[string]interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start 启动插件
|
// Start 启动插件
|
||||||
func (p *LoggerPlugin) Start() error {
|
func (p *LoggerPlugin) Start(ctx context.Context) error {
|
||||||
if p.logger == nil {
|
if p.logger == nil {
|
||||||
return fmt.Errorf("插件未初始化")
|
return fmt.Errorf("插件未初始化")
|
||||||
}
|
}
|
||||||
@@ -74,7 +76,7 @@ func (p *LoggerPlugin) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop 停止插件
|
// Stop 停止插件
|
||||||
func (p *LoggerPlugin) Stop() error {
|
func (p *LoggerPlugin) Stop(ctx context.Context) error {
|
||||||
if p.logger != nil {
|
if p.logger != nil {
|
||||||
p.logger.Println("日志插件正在停止")
|
p.logger.Println("日志插件正在停止")
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -27,13 +28,14 @@ var Plugin = &StatsPlugin{
|
|||||||
"1.0.0",
|
"1.0.0",
|
||||||
"系统运行时统计插件",
|
"系统运行时统计插件",
|
||||||
"开发者",
|
"开发者",
|
||||||
|
plugin.PluginTypeUtils, // 设置为工具类插件
|
||||||
),
|
),
|
||||||
stats: make(map[string]int64),
|
stats: make(map[string]int64),
|
||||||
tickerStop: make(chan bool),
|
tickerStop: make(chan bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init 初始化插件
|
// Init 初始化插件
|
||||||
func (p *StatsPlugin) Init(config map[string]interface{}) error {
|
func (p *StatsPlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
||||||
p.config = config
|
p.config = config
|
||||||
|
|
||||||
// 初始化统计指标
|
// 初始化统计指标
|
||||||
@@ -49,7 +51,7 @@ func (p *StatsPlugin) Init(config map[string]interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start 启动插件
|
// Start 启动插件
|
||||||
func (p *StatsPlugin) Start() error {
|
func (p *StatsPlugin) Start(ctx context.Context) error {
|
||||||
p.startTime = time.Now()
|
p.startTime = time.Now()
|
||||||
|
|
||||||
// 启动定时统计任务
|
// 启动定时统计任务
|
||||||
@@ -70,6 +72,9 @@ func (p *StatsPlugin) Start() error {
|
|||||||
case <-p.tickerStop:
|
case <-p.tickerStop:
|
||||||
p.ticker.Stop()
|
p.ticker.Stop()
|
||||||
return
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
p.ticker.Stop()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -79,7 +84,7 @@ func (p *StatsPlugin) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop 停止插件
|
// Stop 停止插件
|
||||||
func (p *StatsPlugin) Stop() error {
|
func (p *StatsPlugin) Stop(ctx context.Context) error {
|
||||||
if p.ticker != nil {
|
if p.ticker != nil {
|
||||||
p.tickerStop <- true
|
p.tickerStop <- true
|
||||||
}
|
}
|
||||||
|
138
examples/plugin/plugins/storage/storage_plugin.go
Normal file
138
examples/plugin/plugins/storage/storage_plugin.go
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/darkit/goproxy/examples/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StoragePlugin 存储插件
|
||||||
|
// 提供简单的文件存储功能
|
||||||
|
type StoragePlugin struct {
|
||||||
|
*plugin.BasePlugin // 嵌入基本插件结构
|
||||||
|
storageDir string // 存储目录
|
||||||
|
config map[string]interface{} // 配置
|
||||||
|
mu sync.RWMutex // 读写锁
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin 导出的插件变量
|
||||||
|
// 注意:变量名必须是Plugin,大小写敏感
|
||||||
|
var Plugin = &StoragePlugin{
|
||||||
|
BasePlugin: plugin.NewBasePlugin(
|
||||||
|
"StoragePlugin",
|
||||||
|
"1.0.0",
|
||||||
|
"简单的文件存储插件",
|
||||||
|
"开发者",
|
||||||
|
plugin.PluginTypeStorage, // 设置插件类型为存储插件
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init 初始化插件
|
||||||
|
func (p *StoragePlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
||||||
|
p.config = config
|
||||||
|
|
||||||
|
// 获取存储目录路径
|
||||||
|
storageDir, ok := config["storage_dir"].(string)
|
||||||
|
if !ok {
|
||||||
|
// 使用默认路径
|
||||||
|
storageDir = "storage"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保存储目录存在
|
||||||
|
if err := os.MkdirAll(storageDir, 0o755); err != nil {
|
||||||
|
return fmt.Errorf("创建存储目录失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.storageDir = storageDir
|
||||||
|
fmt.Println("存储插件初始化完成,存储目录:", storageDir)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动插件
|
||||||
|
func (p *StoragePlugin) Start(ctx context.Context) error {
|
||||||
|
if p.storageDir == "" {
|
||||||
|
return fmt.Errorf("插件未初始化")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("存储插件已启动")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop 停止插件
|
||||||
|
func (p *StoragePlugin) Stop(ctx context.Context) error {
|
||||||
|
fmt.Println("存储插件已停止")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveFile 保存文件
|
||||||
|
func (p *StoragePlugin) SaveFile(filename string, data []byte) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if p.storageDir == "" {
|
||||||
|
return fmt.Errorf("插件未初始化")
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := filepath.Join(p.storageDir, filename)
|
||||||
|
return os.WriteFile(filePath, data, 0o644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFile 加载文件
|
||||||
|
func (p *StoragePlugin) LoadFile(filename string) ([]byte, error) {
|
||||||
|
p.mu.RLock()
|
||||||
|
defer p.mu.RUnlock()
|
||||||
|
|
||||||
|
if p.storageDir == "" {
|
||||||
|
return nil, fmt.Errorf("插件未初始化")
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := filepath.Join(p.storageDir, filename)
|
||||||
|
return os.ReadFile(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFile 删除文件
|
||||||
|
func (p *StoragePlugin) DeleteFile(filename string) error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
if p.storageDir == "" {
|
||||||
|
return fmt.Errorf("插件未初始化")
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := filepath.Join(p.storageDir, filename)
|
||||||
|
return os.Remove(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFiles 列出所有文件
|
||||||
|
func (p *StoragePlugin) ListFiles() ([]string, error) {
|
||||||
|
p.mu.RLock()
|
||||||
|
defer p.mu.RUnlock()
|
||||||
|
|
||||||
|
if p.storageDir == "" {
|
||||||
|
return nil, fmt.Errorf("插件未初始化")
|
||||||
|
}
|
||||||
|
|
||||||
|
var files []string
|
||||||
|
entries, err := os.ReadDir(p.storageDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
files = append(files, entry.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// main 函数是必须的,但不会被调用
|
||||||
|
func main() {
|
||||||
|
// 不会被执行,仅用于编译插件
|
||||||
|
}
|
@@ -84,10 +84,14 @@ func (d *DefaultDelegate) ParentProxy(req *http.Request) (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WebSocketSendMessage websocket发送消息拦截
|
// WebSocketSendMessage websocket发送消息拦截
|
||||||
func (h *DefaultDelegate) WebSocketSendMessage(ctx *Context, messageType *int, payload *[]byte) {}
|
func (h *DefaultDelegate) WebSocketSendMessage(ctx *Context, messageType *int, payload *[]byte) {
|
||||||
|
// 默认实现不做任何处理
|
||||||
|
}
|
||||||
|
|
||||||
// WebSocketReceiveMessage websocket接收消息拦截
|
// WebSocketReceiveMessage websocket接收消息拦截
|
||||||
func (h *DefaultDelegate) WebSocketReceiveMessage(ctx *Context, messageType *int, payload *[]byte) {}
|
func (h *DefaultDelegate) WebSocketReceiveMessage(ctx *Context, messageType *int, payload *[]byte) {
|
||||||
|
// 默认实现不做任何处理
|
||||||
|
}
|
||||||
|
|
||||||
// ErrorLog 错误日志
|
// ErrorLog 错误日志
|
||||||
func (d *DefaultDelegate) ErrorLog(err error) {
|
func (d *DefaultDelegate) ErrorLog(err error) {
|
||||||
|
Reference in New Issue
Block a user