Files
goproxy/examples/plugin/plugin.go
DarkiT 0990e8c42c 增强插件系统:添加硬件插件类型及默认插件构造函数
- 在插件类型中新增硬件插件类型(PluginTypeHardware),以支持更多插件类型的扩展。
- 添加便捷的构造函数 NewBasePluginWithDefaultType 和 NewPluginWithDefaultType,简化插件创建过程,适用于不需要指定特殊类型的场景。
- 更新日志插件和统计插件的创建示例,展示如何使用默认插件类型。

此更新提升了插件系统的灵活性,便于开发者快速创建和管理插件。
2025-03-14 11:14:47 +08:00

580 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package plugin
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"plugin"
"runtime"
"sync"
)
// Plugin 插件接口
type Plugin interface {
// Name 插件名称
Name() string
// Version 插件版本
Version() string
// Description 插件描述
Description() string
// Author 插件作者
Author() string
// Type 插件类型
Type() PluginType
// Init 初始化插件
Init(ctx context.Context, config map[string]interface{}) error
// Start 启动插件
Start(ctx context.Context) error
// Stop 停止插件
Stop(ctx context.Context) error
// IsEnabled 插件是否启用
IsEnabled() bool
// SetEnabled 设置插件启用状态
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"`
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"`
}
// PluginManager 插件管理器
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 // 是否支持动态加载插件
}
// NewPluginManager 创建插件管理器
func NewPluginManager(pluginsDir string) *PluginManager {
// 检查当前系统是否支持动态加载插件
dynamicLoadingSupported := runtime.GOOS == "linux" || runtime.GOOS == "darwin"
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,
}
}
// IsDynamicLoadingSupported 检查是否支持动态加载插件
func (pm *PluginManager) IsDynamicLoadingSupported() bool {
return pm.dynamicLoadingSupported
}
// LoadPlugins 加载插件
func (pm *PluginManager) LoadPlugins() error {
// 确保插件目录存在
if err := os.MkdirAll(pm.pluginsDir, 0o755); err != nil {
return fmt.Errorf("创建插件目录失败: %v", err)
}
// 加载插件配置
if err := pm.loadPluginConfigs(); err != nil {
return fmt.Errorf("加载插件配置失败: %v", err)
}
// 如果不支持动态加载,则返回
if !pm.dynamicLoadingSupported {
fmt.Printf("警告: 当前系统(%s)不支持动态加载插件,跳过加载\n", runtime.GOOS)
return nil
}
// 遍历插件目录
err := filepath.Walk(pm.pluginsDir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
// 跳过目录和非.so文件
if info.IsDir() || filepath.Ext(path) != ".so" {
return nil
}
// 加载插件
if err := pm.loadPlugin(path); err != nil {
fmt.Printf("加载插件 %s 失败: %v\n", path, err)
}
return nil
})
return err
}
// loadPluginConfigs 加载插件配置
func (pm *PluginManager) loadPluginConfigs() error {
configPath := filepath.Join(pm.pluginsDir, "plugins.json")
// 如果配置文件不存在,创建一个空的
if _, err := os.Stat(configPath); os.IsNotExist(err) {
file, err := os.Create(configPath)
if err != nil {
return fmt.Errorf("创建插件配置文件失败: %v", err)
}
file.Write([]byte("{}"))
file.Close()
return nil
}
// 读取配置文件
data, err := os.ReadFile(configPath)
if err != nil {
return fmt.Errorf("读取插件配置文件失败: %v", err)
}
// 解析配置
var configs map[string]map[string]interface{}
if err := json.Unmarshal(data, &configs); err != nil {
return fmt.Errorf("解析插件配置文件失败: %v", err)
}
pm.configs = configs
return nil
}
// savePluginConfigs 保存插件配置
func (pm *PluginManager) savePluginConfigs() error {
configPath := filepath.Join(pm.pluginsDir, "plugins.json")
// 创建配置数据
configs := make(map[string]map[string]interface{})
pm.mu.RLock()
for name, plugin := range pm.plugins {
config := pm.configs[name]
if config == nil {
config = make(map[string]interface{})
}
config["enabled"] = plugin.IsEnabled()
config["type"] = string(plugin.Type()) // 保存插件类型
configs[name] = config
}
pm.mu.RUnlock()
// 序列化配置
data, err := json.MarshalIndent(configs, "", " ")
if err != nil {
return fmt.Errorf("序列化插件配置失败: %v", err)
}
// 写入文件
if err := os.WriteFile(configPath, data, 0o644); err != nil {
return fmt.Errorf("写入插件配置文件失败: %v", err)
}
return nil
}
// loadPlugin 加载单个插件
func (pm *PluginManager) loadPlugin(path string) error {
// 打开插件文件
p, err := plugin.Open(path)
if err != nil {
return fmt.Errorf("打开插件失败: %v", err)
}
// 查找Plugin变量
symPlugin, err := p.Lookup("Plugin")
if err != nil {
return fmt.Errorf("查找Plugin变量失败: %v", err)
}
// 类型断言
plugin, ok := symPlugin.(Plugin)
if !ok {
return errors.New("插件类型错误")
}
// 检查插件名称是否已存在
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.plugins[plugin.Name()]; exists {
return fmt.Errorf("插件 %s 已存在", plugin.Name())
}
// 设置插件启用状态
if config, exists := pm.configs[plugin.Name()]; exists {
if enabled, ok := config["enabled"].(bool); ok {
plugin.SetEnabled(enabled)
} else {
plugin.SetEnabled(true) // 默认启用
}
} else {
plugin.SetEnabled(true) // 默认启用
}
// 注册插件
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 {
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.plugins[plugin.Name()]; exists {
return fmt.Errorf("插件 %s 已存在", plugin.Name())
}
// 设置插件启用状态
if config, exists := pm.configs[plugin.Name()]; exists {
if enabled, ok := config["enabled"].(bool); ok {
plugin.SetEnabled(enabled)
} else {
plugin.SetEnabled(true) // 默认启用
}
} else {
plugin.SetEnabled(true) // 默认启用
}
// 注册插件
pm.registerPlugin(plugin)
return nil
}
// GetPlugin 获取插件
func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugin, exists := pm.plugins[name]
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()
defer pm.mu.RUnlock()
plugins := make([]Plugin, 0, len(pm.plugins))
for _, plugin := range pm.plugins {
plugins = append(plugins, plugin)
}
return plugins
}
// GetPluginInfos 获取所有插件信息
func (pm *PluginManager) GetPluginInfos() []PluginInfo {
pm.mu.RLock()
defer pm.mu.RUnlock()
infos := make([]PluginInfo, 0, len(pm.plugins))
for name, plugin := range pm.plugins {
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
}
// 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()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
plugin.SetEnabled(true)
// 更新配置
if pm.configs[name] == nil {
pm.configs[name] = make(map[string]interface{})
}
pm.configs[name]["enabled"] = true
// 保存配置
return pm.savePluginConfigs()
}
// DisablePlugin 禁用插件
func (pm *PluginManager) DisablePlugin(name string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
plugin.SetEnabled(false)
// 更新配置
if pm.configs[name] == nil {
pm.configs[name] = make(map[string]interface{})
}
pm.configs[name]["enabled"] = false
// 保存配置
return pm.savePluginConfigs()
}
// InitPlugins 初始化所有插件
func (pm *PluginManager) InitPlugins(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
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
}
// 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()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Start(ctx); err != nil {
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
}
}
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()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Stop(ctx); err != nil {
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
}
}
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()
defer pm.mu.Unlock()
if _, exists := pm.plugins[name]; !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
pm.configs[name] = config
return pm.savePluginConfigs()
}
// GetPluginConfig 获取插件配置
func (pm *PluginManager) GetPluginConfig(name string) (map[string]interface{}, error) {
pm.mu.RLock()
defer pm.mu.RUnlock()
if _, exists := pm.plugins[name]; !exists {
return nil, fmt.Errorf("插件 %s 不存在", name)
}
config := pm.configs[name]
if config == nil {
config = make(map[string]interface{})
}
return config, nil
}