- 在插件接口和基本插件结构中引入插件类型(PluginType),并定义了多种预定义的插件类型。 - 更新插件管理器以支持按类型管理插件,新增按类型获取、初始化和启动插件的方法。 - 修改现有插件(如日志插件和统计插件)以实现插件类型接口,确保兼容性。 - 优化插件信息输出,包含插件类型信息。 此更新提升了插件系统的灵活性和可扩展性,便于未来添加更多插件类型。
545 lines
13 KiB
Go
545 lines
13 KiB
Go
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)
|
|
}
|
|
|
|
// 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
|
|
}
|