增强插件系统:添加插件类型支持

- 在插件接口和基本插件结构中引入插件类型(PluginType),并定义了多种预定义的插件类型。
- 更新插件管理器以支持按类型管理插件,新增按类型获取、初始化和启动插件的方法。
- 修改现有插件(如日志插件和统计插件)以实现插件类型接口,确保兼容性。
- 优化插件信息输出,包含插件类型信息。

此更新提升了插件系统的灵活性和可扩展性,便于未来添加更多插件类型。
This commit is contained in:
2025-03-14 11:07:53 +08:00
parent d423ed5029
commit 098c721ee9
8 changed files with 469 additions and 13 deletions

View 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所有插件已停止")
}

View File

@@ -1,5 +1,19 @@
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 插件接口
// 这个文件定义了所有插件必须实现的接口
// 注意:这个文件应该与实际插件代码一起编译
@@ -12,6 +26,8 @@ type IPlugin interface {
Description() string
// Author 插件作者
Author() string
// Type 插件类型
Type() PluginType
// Init 初始化插件
Init(config map[string]interface{}) error
// Start 启动插件
@@ -31,16 +47,18 @@ type BasePlugin struct {
version string
description string
author string
pluginType PluginType
enabled bool
}
// NewBasePlugin 创建一个基本插件
func NewBasePlugin(name, version, description, author string) *BasePlugin {
func NewBasePlugin(name, version, description, author string, pluginType PluginType) *BasePlugin {
return &BasePlugin{
name: name,
version: version,
description: description,
author: author,
pluginType: pluginType,
enabled: true,
}
}
@@ -65,6 +83,11 @@ func (p *BasePlugin) Author() string {
return p.author
}
// Type 获取插件类型
func (p *BasePlugin) Type() PluginType {
return p.pluginType
}
// IsEnabled 插件是否启用
func (p *BasePlugin) IsEnabled() bool {
return p.enabled

View File

@@ -17,6 +17,7 @@ type LogPlugin struct {
author string
enabled bool
level string
pluginType plugin.PluginType
}
// 创建内置日志插件
@@ -26,6 +27,7 @@ func NewLogPlugin() *LogPlugin {
version: "1.0.0",
description: "内置日志插件,在不支持动态加载插件的平台上使用",
author: "开发者",
pluginType: plugin.PluginTypeUtils, // 设置为工具类插件
enabled: true,
level: "info",
}
@@ -48,6 +50,11 @@ func (p *LogPlugin) Author() string {
return p.author
}
// Type 实现插件类型方法
func (p *LogPlugin) Type() plugin.PluginType {
return p.pluginType
}
func (p *LogPlugin) IsEnabled() bool {
return p.enabled
}
@@ -130,8 +137,8 @@ func main() {
if !info.Enabled {
status = "禁用"
}
fmt.Printf("[%d] %s (v%s) - %s [%s]\n作者: %s\n",
i, info.Name, info.Version, info.Description, status, info.Author)
fmt.Printf("[%d] %s (v%s) - %s [%s]\n作者: %s\n类型: %s\n",
i, info.Name, info.Version, info.Description, status, info.Author, info.Type)
// 打印插件配置
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正在停止插件...")
if err := pm.StopPlugins(ctx); err != nil {

View File

@@ -23,6 +23,8 @@ type Plugin interface {
Description() string
// Author 插件作者
Author() string
// Type 插件类型
Type() PluginType
// Init 初始化插件
Init(ctx context.Context, config map[string]interface{}) error
// Start 启动插件
@@ -41,6 +43,7 @@ type PluginInfo struct {
Version string `json:"version"`
Description string `json:"description"`
Author string `json:"author"`
Type PluginType `json:"type"`
Enabled bool `json:"enabled"`
Config map[string]interface{} `json:"config,omitempty"`
}
@@ -49,6 +52,7 @@ type PluginInfo struct {
type PluginManager struct {
pluginsDir string
plugins map[string]Plugin
pluginsByType map[PluginType]map[string]Plugin
configs map[string]map[string]interface{}
mu sync.RWMutex
dynamicLoadingSupported bool // 是否支持动态加载插件
@@ -62,6 +66,7 @@ func NewPluginManager(pluginsDir string) *PluginManager {
return &PluginManager{
pluginsDir: pluginsDir,
plugins: make(map[string]Plugin),
pluginsByType: make(map[PluginType]map[string]Plugin),
configs: make(map[string]map[string]interface{}),
dynamicLoadingSupported: dynamicLoadingSupported,
}
@@ -156,6 +161,7 @@ func (pm *PluginManager) savePluginConfigs() error {
config = make(map[string]interface{})
}
config["enabled"] = plugin.IsEnabled()
config["type"] = string(plugin.Type()) // 保存插件类型
configs[name] = config
}
pm.mu.RUnlock()
@@ -213,10 +219,25 @@ func (pm *PluginManager) loadPlugin(path string) error {
plugin.SetEnabled(true) // 默认启用
}
pm.plugins[plugin.Name()] = plugin
// 注册插件
pm.registerPlugin(plugin)
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 注册内置插件
// 用于在不支持动态加载的平台上注册插件
func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
@@ -238,7 +259,8 @@ func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
plugin.SetEnabled(true) // 默认启用
}
pm.plugins[plugin.Name()] = plugin
// 注册插件
pm.registerPlugin(plugin)
return nil
}
@@ -251,6 +273,36 @@ func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
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 获取所有插件
func (pm *PluginManager) GetAllPlugins() []Plugin {
pm.mu.RLock()
@@ -275,6 +327,7 @@ func (pm *PluginManager) GetPluginInfos() []PluginInfo {
Version: plugin.Version(),
Description: plugin.Description(),
Author: plugin.Author(),
Type: plugin.Type(),
Enabled: plugin.IsEnabled(),
Config: pm.configs[name],
}
@@ -283,6 +336,29 @@ func (pm *PluginManager) GetPluginInfos() []PluginInfo {
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 启用插件
func (pm *PluginManager) EnablePlugin(name string) error {
pm.mu.Lock()
@@ -345,6 +421,26 @@ func (pm *PluginManager) InitPlugins(ctx context.Context) error {
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 启动所有插件
func (pm *PluginManager) StartPlugins(ctx context.Context) error {
pm.mu.RLock()
@@ -362,6 +458,25 @@ func (pm *PluginManager) StartPlugins(ctx context.Context) error {
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 停止所有插件
func (pm *PluginManager) StopPlugins(ctx context.Context) error {
pm.mu.RLock()
@@ -379,6 +494,25 @@ func (pm *PluginManager) StopPlugins(ctx context.Context) error {
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 设置插件配置
func (pm *PluginManager) SetPluginConfig(name string, config map[string]interface{}) error {
pm.mu.Lock()

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"log"
"os"
@@ -27,11 +28,12 @@ var Plugin = &LoggerPlugin{
"1.0.0",
"简单的日志记录插件",
"开发者",
plugin.PluginTypeUtils, // 设置插件类型为工具插件
),
}
// 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
// 获取日志文件路径
@@ -63,7 +65,7 @@ func (p *LoggerPlugin) Init(config map[string]interface{}) error {
}
// Start 启动插件
func (p *LoggerPlugin) Start() error {
func (p *LoggerPlugin) Start(ctx context.Context) error {
if p.logger == nil {
return fmt.Errorf("插件未初始化")
}
@@ -74,7 +76,7 @@ func (p *LoggerPlugin) Start() error {
}
// Stop 停止插件
func (p *LoggerPlugin) Stop() error {
func (p *LoggerPlugin) Stop(ctx context.Context) error {
if p.logger != nil {
p.logger.Println("日志插件正在停止")
}

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"sync"
"time"
@@ -27,13 +28,14 @@ var Plugin = &StatsPlugin{
"1.0.0",
"系统运行时统计插件",
"开发者",
plugin.PluginTypeUtils, // 设置为工具类插件
),
stats: make(map[string]int64),
tickerStop: make(chan bool),
}
// 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
// 初始化统计指标
@@ -49,7 +51,7 @@ func (p *StatsPlugin) Init(config map[string]interface{}) error {
}
// Start 启动插件
func (p *StatsPlugin) Start() error {
func (p *StatsPlugin) Start(ctx context.Context) error {
p.startTime = time.Now()
// 启动定时统计任务
@@ -70,6 +72,9 @@ func (p *StatsPlugin) Start() error {
case <-p.tickerStop:
p.ticker.Stop()
return
case <-ctx.Done():
p.ticker.Stop()
return
}
}
}()
@@ -79,7 +84,7 @@ func (p *StatsPlugin) Start() error {
}
// Stop 停止插件
func (p *StatsPlugin) Stop() error {
func (p *StatsPlugin) Stop(ctx context.Context) error {
if p.ticker != nil {
p.tickerStop <- true
}

View 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() {
// 不会被执行,仅用于编译插件
}

View File

@@ -84,10 +84,14 @@ func (d *DefaultDelegate) ParentProxy(req *http.Request) (*url.URL, error) {
}
// WebSocketSendMessage websocket发送消息拦截
func (h *DefaultDelegate) WebSocketSendMessage(ctx *Context, messageType *int, payload *[]byte) {}
func (h *DefaultDelegate) WebSocketSendMessage(ctx *Context, messageType *int, payload *[]byte) {
// 默认实现不做任何处理
}
// WebSocketReceiveMessage websocket接收消息拦截
func (h *DefaultDelegate) WebSocketReceiveMessage(ctx *Context, messageType *int, payload *[]byte) {}
func (h *DefaultDelegate) WebSocketReceiveMessage(ctx *Context, messageType *int, payload *[]byte) {
// 默认实现不做任何处理
}
// ErrorLog 错误日志
func (d *DefaultDelegate) ErrorLog(err error) {