1868 lines
46 KiB
Go
1868 lines
46 KiB
Go
package plugins
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io/fs"
|
||
"log"
|
||
"os"
|
||
"path/filepath"
|
||
"plugin"
|
||
"reflect"
|
||
"runtime"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// 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]IPlugin
|
||
pluginsByType map[PluginType]map[string]IPlugin
|
||
configs map[string]map[string]interface{}
|
||
mu sync.RWMutex
|
||
dynamicLoadingSupported bool // 是否支持动态加载插件
|
||
eventHandlers map[PluginEventType][]PluginEventHandler // 全局事件处理器
|
||
}
|
||
|
||
// NewPluginManager 创建插件管理器
|
||
func NewPluginManager(pluginsDir string) *PluginManager {
|
||
// 检查当前系统是否支持动态加载插件
|
||
dynamicLoadingSupported := runtime.GOOS == "linux" || runtime.GOOS == "darwin"
|
||
|
||
return &PluginManager{
|
||
pluginsDir: pluginsDir,
|
||
plugins: make(map[string]IPlugin),
|
||
pluginsByType: make(map[PluginType]map[string]IPlugin),
|
||
configs: make(map[string]map[string]interface{}),
|
||
dynamicLoadingSupported: dynamicLoadingSupported,
|
||
eventHandlers: make(map[PluginEventType][]PluginEventHandler),
|
||
}
|
||
}
|
||
|
||
// 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")
|
||
|
||
// 先检查配置文件是否存在
|
||
_, err := os.Stat(configPath)
|
||
if os.IsNotExist(err) {
|
||
// 配置文件不存在,创建一个空的
|
||
// 注意:这里的文件IO操作在锁之外执行
|
||
file, err := os.Create(configPath)
|
||
if err != nil {
|
||
return fmt.Errorf("创建插件配置文件失败: %v", err)
|
||
}
|
||
file.Write([]byte("{}"))
|
||
file.Close()
|
||
|
||
// 初始化空配置
|
||
pm.mu.Lock()
|
||
pm.configs = make(map[string]map[string]interface{})
|
||
pm.mu.Unlock()
|
||
return nil
|
||
} else if err != nil {
|
||
return fmt.Errorf("检查插件配置文件状态失败: %v", err)
|
||
}
|
||
|
||
// 读取配置文件 - 在锁之外执行IO操作
|
||
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.mu.Lock()
|
||
defer pm.mu.Unlock()
|
||
|
||
// 如果配置为nil,初始化为空映射
|
||
if configs == nil {
|
||
configs = make(map[string]map[string]interface{})
|
||
}
|
||
|
||
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 := make(map[string]interface{})
|
||
// 获取并复制现有配置
|
||
if existingConfig, ok := pm.configs[name]; ok {
|
||
for k, v := range existingConfig {
|
||
// 对于复杂类型,执行深度复制
|
||
switch val := v.(type) {
|
||
case map[string]interface{}:
|
||
nestedMap := make(map[string]interface{})
|
||
for nk, nv := range val {
|
||
nestedMap[nk] = nv
|
||
}
|
||
config[k] = nestedMap
|
||
case []interface{}:
|
||
nestedArray := make([]interface{}, len(val))
|
||
copy(nestedArray, val)
|
||
config[k] = nestedArray
|
||
default:
|
||
config[k] = v
|
||
}
|
||
}
|
||
}
|
||
// 添加基本信息
|
||
config["enabled"] = plugin.IsEnabled()
|
||
config["type"] = string(plugin.Type())
|
||
configs[name] = config
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
// 在释放锁后执行所有IO操作
|
||
// 序列化配置
|
||
data, err := json.MarshalIndent(configs, "", " ")
|
||
if err != nil {
|
||
return fmt.Errorf("序列化插件配置失败: %v", err)
|
||
}
|
||
|
||
// 创建临时文件
|
||
tmpDir := filepath.Dir(configPath)
|
||
// 确保目录存在
|
||
if err := os.MkdirAll(tmpDir, 0755); err != nil {
|
||
return fmt.Errorf("创建配置目录失败: %v", err)
|
||
}
|
||
|
||
// 使用一个唯一的临时文件名
|
||
tmpFile := fmt.Sprintf("%s.%d.tmp", configPath, time.Now().UnixNano())
|
||
if err := os.WriteFile(tmpFile, data, 0o644); err != nil {
|
||
return fmt.Errorf("写入临时配置文件失败: %v", err)
|
||
}
|
||
|
||
// 重命名临时文件为正式文件(原子操作)
|
||
if err := os.Rename(tmpFile, configPath); err != nil {
|
||
// 如果重命名失败,确保清理临时文件
|
||
os.Remove(tmpFile)
|
||
return fmt.Errorf("更新配置文件失败: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// CheckDependencies 检查插件依赖关系
|
||
func (pm *PluginManager) CheckDependencies(plugin IPlugin) error {
|
||
dependencies := plugin.Dependencies()
|
||
if len(dependencies) == 0 {
|
||
return nil // 没有依赖,直接返回
|
||
}
|
||
|
||
for _, dep := range dependencies {
|
||
depPlugin, exists := pm.plugins[dep.Name]
|
||
if !exists {
|
||
if dep.IsOptional {
|
||
continue // 可选依赖,忽略
|
||
}
|
||
return fmt.Errorf("依赖的插件 %s 不存在", dep.Name)
|
||
}
|
||
|
||
// 验证版本兼容性
|
||
if dep.MinVersion != "" || dep.MaxVersion != "" {
|
||
currentVersion := depPlugin.Version()
|
||
|
||
if dep.MinVersion != "" {
|
||
result, err := compareVersions(currentVersion, dep.MinVersion)
|
||
if err != nil {
|
||
return fmt.Errorf("版本比较错误: %v", err)
|
||
}
|
||
|
||
if result < 0 {
|
||
return fmt.Errorf("依赖插件 %s 版本 %s 低于最低版本要求 %s",
|
||
dep.Name, currentVersion, dep.MinVersion)
|
||
}
|
||
}
|
||
|
||
if dep.MaxVersion != "" {
|
||
result, err := compareVersions(currentVersion, dep.MaxVersion)
|
||
if err != nil {
|
||
return fmt.Errorf("版本比较错误: %v", err)
|
||
}
|
||
|
||
if result > 0 {
|
||
return fmt.Errorf("依赖插件 %s 版本 %s 高于最高版本要求 %s",
|
||
dep.Name, currentVersion, dep.MaxVersion)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检查依赖插件是否启用
|
||
if !depPlugin.IsEnabled() && !dep.IsOptional {
|
||
if dep.AutoDisableWith {
|
||
// 自动禁用当前插件
|
||
plugin.SetEnabled(false)
|
||
return fmt.Errorf("依赖插件 %s 已禁用,当前插件自动禁用", dep.Name)
|
||
}
|
||
return fmt.Errorf("依赖插件 %s 已禁用", dep.Name)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// InitializeWithDependencies 根据依赖关系初始化插件
|
||
func (pm *PluginManager) InitializeWithDependencies(ctx context.Context) error {
|
||
// 构建依赖图
|
||
dependencyGraph := make(map[string][]string)
|
||
pluginDeps := make(map[string][]PluginDependency)
|
||
|
||
pm.mu.RLock()
|
||
for name, plugin := range pm.plugins {
|
||
if !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
deps := plugin.Dependencies()
|
||
pluginDeps[name] = deps
|
||
|
||
dependencyGraph[name] = []string{}
|
||
for _, dep := range deps {
|
||
if !dep.IsOptional && dep.InitAfter {
|
||
dependencyGraph[name] = append(dependencyGraph[name], dep.Name)
|
||
}
|
||
}
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
// 拓扑排序
|
||
initOrder, err := topologicalSort(dependencyGraph)
|
||
if err != nil {
|
||
return fmt.Errorf("解析依赖关系失败: %v", err)
|
||
}
|
||
|
||
// 按依赖顺序初始化插件
|
||
for _, name := range initOrder {
|
||
pm.mu.RLock()
|
||
plugin, exists := pm.plugins[name]
|
||
config := pm.configs[name]
|
||
pm.mu.RUnlock()
|
||
|
||
if !exists || !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
if err := plugin.Init(ctx, config); err != nil {
|
||
return fmt.Errorf("初始化插件 %s 失败: %v", name, err)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// SubscribeEvent 订阅全局插件事件
|
||
func (pm *PluginManager) SubscribeEvent(eventType PluginEventType, handler PluginEventHandler) {
|
||
pm.mu.Lock()
|
||
defer pm.mu.Unlock()
|
||
|
||
if pm.eventHandlers[eventType] == nil {
|
||
pm.eventHandlers[eventType] = []PluginEventHandler{}
|
||
}
|
||
pm.eventHandlers[eventType] = append(pm.eventHandlers[eventType], handler)
|
||
}
|
||
|
||
// UnsubscribeEvent 取消订阅全局插件事件
|
||
func (pm *PluginManager) UnsubscribeEvent(eventType PluginEventType, handler PluginEventHandler) {
|
||
pm.mu.Lock()
|
||
defer pm.mu.Unlock()
|
||
|
||
if handlers, exists := pm.eventHandlers[eventType]; exists {
|
||
for i, h := range handlers {
|
||
if fmt.Sprintf("%p", h) == fmt.Sprintf("%p", handler) {
|
||
pm.eventHandlers[eventType] = append(handlers[:i], handlers[i+1:]...)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// HandleEvent 处理全局插件事件
|
||
func (pm *PluginManager) HandleEvent(event PluginEvent) {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
if handlers, exists := pm.eventHandlers[event.Type]; exists {
|
||
for _, handler := range handlers {
|
||
handler(event) // 忽略错误,不影响其他处理器
|
||
}
|
||
}
|
||
}
|
||
|
||
// BroadcastEvent 广播插件事件到所有处理器
|
||
func (pm *PluginManager) BroadcastEvent(event PluginEvent) {
|
||
// 先处理全局事件
|
||
pm.HandleEvent(event)
|
||
|
||
// 再传播到特定插件
|
||
if event.PluginID != "" {
|
||
pm.mu.RLock()
|
||
plugin, exists := pm.plugins[event.PluginID]
|
||
pm.mu.RUnlock()
|
||
|
||
if exists {
|
||
plugin.EmitEvent(event)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 加载插件时的事件通知
|
||
func (pm *PluginManager) notifyPluginLoaded(plugin IPlugin) {
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventLoaded,
|
||
PluginID: plugin.Name(),
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"name": plugin.Name(),
|
||
"version": plugin.Version(),
|
||
"type": plugin.Type(),
|
||
},
|
||
})
|
||
}
|
||
|
||
// loadPlugin 加载单个插件
|
||
func (pm *PluginManager) loadPlugin(path string) error {
|
||
if !strings.HasSuffix(path, ".so") && !strings.HasSuffix(path, ".dll") {
|
||
return nil
|
||
}
|
||
|
||
// 打开插件
|
||
plug, err := plugin.Open(path)
|
||
if err != nil {
|
||
return fmt.Errorf("打开插件失败: %v", err)
|
||
}
|
||
|
||
// 查找 Plugin 符号
|
||
symPlugin, err := plug.Lookup("Plugin")
|
||
if err != nil {
|
||
return fmt.Errorf("查找 Plugin 符号失败: %v", err)
|
||
}
|
||
|
||
// 尝试直接类型断言
|
||
fmt.Printf("插件类型: %T\n", symPlugin)
|
||
if p, ok := symPlugin.(IPlugin); ok {
|
||
pm.registerPlugin(p)
|
||
pm.notifyPluginLoaded(p)
|
||
return nil
|
||
}
|
||
|
||
// 直接类型断言失败,尝试通过反射获取值
|
||
fmt.Println("直接类型断言失败,尝试通过反射获取值")
|
||
|
||
// 获取原始插件值,用于存储在适配器中
|
||
origValue := reflect.ValueOf(symPlugin)
|
||
|
||
// 尝试在所有指针级别上查找方法
|
||
// 保存每一级指针值,用于查找方法
|
||
pointerValues := []reflect.Value{origValue}
|
||
currentValue := origValue
|
||
|
||
// 解引用并保存每一级指针
|
||
for currentValue.Kind() == reflect.Ptr && currentValue.Elem().IsValid() {
|
||
currentValue = currentValue.Elem()
|
||
pointerValues = append(pointerValues, currentValue)
|
||
}
|
||
|
||
// 尝试在不同级别的指针上查找Name和Version方法
|
||
var nameMethod reflect.Value
|
||
var versionMethod reflect.Value
|
||
var methodPointerLevel reflect.Value
|
||
|
||
for _, ptrValue := range pointerValues {
|
||
nm := ptrValue.MethodByName("Name")
|
||
vm := ptrValue.MethodByName("Version")
|
||
|
||
if nm.IsValid() && vm.IsValid() {
|
||
nameMethod = nm
|
||
versionMethod = vm
|
||
methodPointerLevel = ptrValue
|
||
break
|
||
}
|
||
}
|
||
|
||
if !nameMethod.IsValid() || !versionMethod.IsValid() {
|
||
return fmt.Errorf("插件缺少必需的方法: Name 或 Version")
|
||
}
|
||
|
||
// 调用 Name 和 Version 方法获取基本信息
|
||
nameResult := nameMethod.Call(nil)
|
||
versionResult := versionMethod.Call(nil)
|
||
|
||
if len(nameResult) == 0 || len(versionResult) == 0 {
|
||
return fmt.Errorf("插件方法返回无效结果")
|
||
}
|
||
|
||
pluginName := nameResult[0].String()
|
||
pluginVersion := versionResult[0].String()
|
||
|
||
fmt.Printf("找到插件: %s (版本 %s)\n", pluginName, pluginVersion)
|
||
|
||
// 创建适配器以包装插件
|
||
adapter := &PluginAdapter{
|
||
symPlugin: symPlugin,
|
||
pluginValue: methodPointerLevel, // 使用找到有效方法的指针级别
|
||
pluginName: pluginName,
|
||
pluginVersion: pluginVersion,
|
||
}
|
||
|
||
// 使用找到方法的同一级别指针值检查是否具有Execute方法
|
||
executeMethod := methodPointerLevel.MethodByName("Execute")
|
||
if !executeMethod.IsValid() {
|
||
fmt.Printf("插件未实现 Execute 方法,尝试查找特定操作方法\n")
|
||
|
||
// 查找常见的操作方法,如果找到,也可以认为是有效插件
|
||
methodFound := false
|
||
commonMethods := []string{"Log", "Info", "Error", "GetStat", "SaveFile", "LoadFile"}
|
||
|
||
for _, methodName := range commonMethods {
|
||
if method := methodPointerLevel.MethodByName(methodName); method.IsValid() {
|
||
methodFound = true
|
||
break
|
||
}
|
||
}
|
||
|
||
if !methodFound {
|
||
return fmt.Errorf("插件类型错误: 未实现 Execute 方法或任何已知的操作方法")
|
||
}
|
||
}
|
||
|
||
pm.registerPlugin(adapter)
|
||
pm.notifyPluginLoaded(adapter)
|
||
return nil
|
||
}
|
||
|
||
// registerPlugin 注册插件到插件管理器
|
||
func (pm *PluginManager) registerPlugin(plugin IPlugin) {
|
||
name := plugin.Name()
|
||
|
||
// 检查插件名称是否已存在
|
||
pm.mu.Lock()
|
||
defer pm.mu.Unlock()
|
||
|
||
if _, exists := pm.plugins[name]; exists {
|
||
log.Printf("警告: 插件 %s 已存在,将被覆盖", name)
|
||
}
|
||
|
||
// 设置插件启用状态
|
||
if config, exists := pm.configs[name]; exists {
|
||
if enabled, ok := config["enabled"].(bool); ok {
|
||
plugin.SetEnabled(enabled)
|
||
} else {
|
||
plugin.SetEnabled(true) // 默认启用
|
||
}
|
||
} else {
|
||
plugin.SetEnabled(true) // 默认启用
|
||
}
|
||
|
||
// 检查依赖关系
|
||
if err := pm.CheckDependencies(plugin); err != nil {
|
||
log.Printf("警告: 插件 %s 依赖检查失败: %v", name, err)
|
||
}
|
||
|
||
// 添加到插件映射
|
||
pm.plugins[name] = plugin
|
||
|
||
// 添加到类型映射
|
||
pluginType := plugin.Type()
|
||
if pm.pluginsByType[pluginType] == nil {
|
||
pm.pluginsByType[pluginType] = make(map[string]IPlugin)
|
||
}
|
||
pm.pluginsByType[pluginType][name] = plugin
|
||
|
||
log.Printf("插件 %s (类型: %s, 版本: %s) 已注册", name, pluginType, plugin.Version())
|
||
}
|
||
|
||
// RegisterPlugin 注册内置插件, 用于在不支持动态加载的平台上注册插件
|
||
func (pm *PluginManager) RegisterPlugin(plugin IPlugin) 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) // 默认启用
|
||
}
|
||
|
||
// 检查依赖关系
|
||
if err := pm.CheckDependencies(plugin); err != nil {
|
||
return fmt.Errorf("依赖检查失败: %v", err)
|
||
}
|
||
|
||
// 注册插件
|
||
pm.registerPlugin(plugin)
|
||
|
||
// 通知插件已加载
|
||
go pm.notifyPluginLoaded(plugin)
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetPlugin 获取插件
|
||
func (pm *PluginManager) GetPlugin(name string) (IPlugin, bool) {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugin, exists := pm.plugins[name]
|
||
return plugin, exists
|
||
}
|
||
|
||
// GetPluginsByType 按类型获取插件
|
||
func (pm *PluginManager) GetPluginsByType(pluginType PluginType) []IPlugin {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugins := make([]IPlugin, 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) []IPlugin {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugins := make([]IPlugin, 0)
|
||
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||
for _, plugin := range typePlugins {
|
||
plugins = append(plugins, plugin)
|
||
}
|
||
}
|
||
return plugins
|
||
}
|
||
|
||
// GetAllPlugins 获取所有插件
|
||
func (pm *PluginManager) GetAllPlugins() []IPlugin {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugins := make([]IPlugin, 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.RLock()
|
||
plugin, exists := pm.plugins[name]
|
||
pm.mu.RUnlock()
|
||
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
// 设置插件状态
|
||
plugin.SetEnabled(true)
|
||
|
||
// 更新配置
|
||
config := make(map[string]interface{})
|
||
pm.mu.RLock()
|
||
if existingConfig, ok := pm.configs[name]; ok {
|
||
// 复制现有配置
|
||
for k, v := range existingConfig {
|
||
config[k] = v
|
||
}
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
config["enabled"] = true
|
||
|
||
// 使用单独的锁来更新配置
|
||
pm.mu.Lock()
|
||
pm.configs[name] = config
|
||
pm.mu.Unlock()
|
||
|
||
// 保存配置到文件
|
||
return pm.savePluginConfigs()
|
||
}
|
||
|
||
// DisablePlugin 禁用插件
|
||
func (pm *PluginManager) DisablePlugin(name string) error {
|
||
// 先获取插件,避免长时间持有锁
|
||
pm.mu.RLock()
|
||
plugin, exists := pm.plugins[name]
|
||
pm.mu.RUnlock()
|
||
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
// 设置插件状态
|
||
plugin.SetEnabled(false)
|
||
|
||
// 更新配置
|
||
config := make(map[string]interface{})
|
||
pm.mu.RLock()
|
||
if existingConfig, ok := pm.configs[name]; ok {
|
||
// 复制现有配置
|
||
for k, v := range existingConfig {
|
||
config[k] = v
|
||
}
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
config["enabled"] = false
|
||
|
||
// 使用单独的锁来更新配置
|
||
pm.mu.Lock()
|
||
pm.configs[name] = config
|
||
pm.mu.Unlock()
|
||
|
||
// 保存配置到文件
|
||
return pm.savePluginConfigs()
|
||
}
|
||
|
||
// InitPlugins 初始化所有插件
|
||
func (pm *PluginManager) InitPlugins(ctx context.Context) error {
|
||
// 使用基于依赖的初始化
|
||
return pm.InitializeWithDependencies(ctx)
|
||
}
|
||
|
||
// 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.RLock()
|
||
_, exists := pm.plugins[name]
|
||
pm.mu.RUnlock()
|
||
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
// 创建配置的深度副本
|
||
configCopy := make(map[string]interface{})
|
||
for k, v := range config {
|
||
// 对复杂类型进行深度复制
|
||
switch val := v.(type) {
|
||
case map[string]interface{}:
|
||
// 复制嵌套的map
|
||
nestedMap := make(map[string]interface{})
|
||
for nk, nv := range val {
|
||
nestedMap[nk] = nv
|
||
}
|
||
configCopy[k] = nestedMap
|
||
case []interface{}:
|
||
// 复制数组
|
||
nestedArray := make([]interface{}, len(val))
|
||
copy(nestedArray, val)
|
||
configCopy[k] = nestedArray
|
||
default:
|
||
// 简单类型直接复制
|
||
configCopy[k] = v
|
||
}
|
||
}
|
||
|
||
// 使用写锁更新配置,但尽量减少锁持有时间
|
||
pm.mu.Lock()
|
||
pm.configs[name] = configCopy
|
||
pm.mu.Unlock()
|
||
|
||
// 创建一个带有超时的上下文
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
// 使用 channel 来处理保存操作
|
||
errChan := make(chan error, 1)
|
||
go func() {
|
||
errChan <- pm.savePluginConfigs()
|
||
}()
|
||
|
||
// 等待保存完成或超时
|
||
select {
|
||
case err := <-errChan:
|
||
return err
|
||
case <-ctx.Done():
|
||
return fmt.Errorf("保存配置超时")
|
||
}
|
||
}
|
||
|
||
// 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 {
|
||
return make(map[string]interface{}), nil
|
||
}
|
||
|
||
// 创建配置的深度副本
|
||
result := make(map[string]interface{})
|
||
for k, v := range config {
|
||
// 对复杂类型进行深度复制
|
||
switch val := v.(type) {
|
||
case map[string]interface{}:
|
||
// 复制嵌套的map
|
||
nestedMap := make(map[string]interface{})
|
||
for nk, nv := range val {
|
||
nestedMap[nk] = nv
|
||
}
|
||
result[k] = nestedMap
|
||
case []interface{}:
|
||
// 复制数组
|
||
nestedArray := make([]interface{}, len(val))
|
||
copy(nestedArray, val)
|
||
result[k] = nestedArray
|
||
default:
|
||
// 简单类型直接复制
|
||
result[k] = v
|
||
}
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// ExecutePlugin 执行指定插件的操作
|
||
func (pm *PluginManager) ExecutePlugin(ctx context.Context, name string, action string, params map[string]interface{}) (interface{}, error) {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugin, exists := pm.plugins[name]
|
||
if !exists {
|
||
return nil, fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
if !plugin.IsEnabled() {
|
||
return nil, fmt.Errorf("插件 %s 已禁用", name)
|
||
}
|
||
|
||
return plugin.Execute(ctx, action, params)
|
||
}
|
||
|
||
// ExecutePluginsByType 对指定类型的所有插件执行操作
|
||
func (pm *PluginManager) ExecutePluginsByType(ctx context.Context, pluginType PluginType, action string, params map[string]interface{}) map[string]interface{} {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
results := make(map[string]interface{})
|
||
|
||
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||
for name, plugin := range typePlugins {
|
||
if !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
result, err := plugin.Execute(ctx, action, params)
|
||
results[name] = map[string]interface{}{
|
||
"result": result,
|
||
"error": err,
|
||
}
|
||
}
|
||
}
|
||
|
||
return results
|
||
}
|
||
|
||
// ExecuteAllPlugins 对所有插件执行操作
|
||
func (pm *PluginManager) ExecuteAllPlugins(ctx context.Context, action string, params map[string]interface{}) map[string]interface{} {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
results := make(map[string]interface{})
|
||
|
||
for name, plugin := range pm.plugins {
|
||
if !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
result, err := plugin.Execute(ctx, action, params)
|
||
results[name] = map[string]interface{}{
|
||
"result": result,
|
||
"error": err,
|
||
}
|
||
}
|
||
|
||
return results
|
||
}
|
||
|
||
// GetPluginOperationInfo 获取插件特定操作的参数信息
|
||
func (pm *PluginManager) GetPluginOperationInfo(name string, operation string) (*OperationInfo, error) {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugin, exists := pm.plugins[name]
|
||
if !exists {
|
||
return nil, fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
if !plugin.IsEnabled() {
|
||
return nil, fmt.Errorf("插件 %s 已禁用", name)
|
||
}
|
||
|
||
return plugin.GetOperationInfo(operation)
|
||
}
|
||
|
||
// GetPluginAllOperations 获取插件所有操作及其参数信息
|
||
func (pm *PluginManager) GetPluginAllOperations(name string) (*PluginOperations, error) {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
plugin, exists := pm.plugins[name]
|
||
if !exists {
|
||
return nil, fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
if !plugin.IsEnabled() {
|
||
return nil, fmt.Errorf("插件 %s 已禁用", name)
|
||
}
|
||
|
||
ops := plugin.GetAllOperations()
|
||
|
||
return &PluginOperations{
|
||
PluginName: plugin.Name(),
|
||
PluginType: plugin.Type(),
|
||
Operations: ops,
|
||
}, nil
|
||
}
|
||
|
||
// GetOperationsByType 获取指定类型插件的所有操作信息
|
||
func (pm *PluginManager) GetOperationsByType(pluginType PluginType) []*PluginOperations {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
result := make([]*PluginOperations, 0)
|
||
|
||
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
|
||
for _, plugin := range typePlugins {
|
||
if !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
ops := plugin.GetAllOperations()
|
||
|
||
result = append(result, &PluginOperations{
|
||
PluginName: plugin.Name(),
|
||
PluginType: plugin.Type(),
|
||
Operations: ops,
|
||
})
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// GetAllPluginsOperations 获取所有插件的所有操作信息
|
||
func (pm *PluginManager) GetAllPluginsOperations() []*PluginOperations {
|
||
pm.mu.RLock()
|
||
defer pm.mu.RUnlock()
|
||
|
||
result := make([]*PluginOperations, 0, len(pm.plugins))
|
||
|
||
for _, plugin := range pm.plugins {
|
||
if !plugin.IsEnabled() {
|
||
continue
|
||
}
|
||
|
||
ops := plugin.GetAllOperations()
|
||
|
||
result = append(result, &PluginOperations{
|
||
PluginName: plugin.Name(),
|
||
PluginType: plugin.Type(),
|
||
Operations: ops,
|
||
})
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// ReloadPlugin 重新加载单个插件
|
||
func (pm *PluginManager) ReloadPlugin(ctx context.Context, name string) error {
|
||
pm.mu.Lock()
|
||
plugin, exists := pm.plugins[name]
|
||
config := pm.configs[name]
|
||
pm.mu.Unlock()
|
||
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
// 发出重载事件
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventCustom,
|
||
PluginID: name,
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"action": "reloading",
|
||
},
|
||
})
|
||
|
||
// 执行重载
|
||
if err := plugin.Reload(ctx, config); err != nil {
|
||
// 发送错误事件
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventError,
|
||
PluginID: name,
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"error": err.Error(),
|
||
"context": "reload",
|
||
},
|
||
})
|
||
return fmt.Errorf("重载插件 %s 失败: %v", name, err)
|
||
}
|
||
|
||
// 发送重载完成事件
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventCustom,
|
||
PluginID: name,
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"action": "reloaded",
|
||
},
|
||
})
|
||
|
||
return nil
|
||
}
|
||
|
||
// ReloadAllPlugins 重新加载所有插件
|
||
func (pm *PluginManager) ReloadAllPlugins(ctx context.Context) map[string]error {
|
||
errors := make(map[string]error)
|
||
|
||
pm.mu.RLock()
|
||
pluginNames := make([]string, 0, len(pm.plugins))
|
||
for name := range pm.plugins {
|
||
pluginNames = append(pluginNames, name)
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
for _, name := range pluginNames {
|
||
if err := pm.ReloadPlugin(ctx, name); err != nil {
|
||
errors[name] = err
|
||
}
|
||
}
|
||
|
||
return errors
|
||
}
|
||
|
||
// InstallErrorHandler 为插件安装错误处理器
|
||
func (pm *PluginManager) InstallErrorHandler() {
|
||
pm.SubscribeEvent(PluginEventError, func(event PluginEvent) error {
|
||
errData, ok := event.Data["error"].(string)
|
||
if !ok {
|
||
errData = "未知错误"
|
||
}
|
||
|
||
context, _ := event.Data["context"].(string)
|
||
if context == "" {
|
||
context = "general"
|
||
}
|
||
|
||
fmt.Printf("[错误] 插件 %s 在 %s 上下文中发生错误: %s\n",
|
||
event.PluginID, context, errData)
|
||
return nil
|
||
})
|
||
}
|
||
|
||
// RecoverPlugin 尝试恢复错误状态的插件
|
||
func (pm *PluginManager) RecoverPlugin(ctx context.Context, name string) error {
|
||
pm.mu.Lock()
|
||
plugin, exists := pm.plugins[name]
|
||
config := pm.configs[name]
|
||
pm.mu.Unlock()
|
||
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
if plugin.Status() != PluginStatusError {
|
||
return nil // 插件不在错误状态,无需恢复
|
||
}
|
||
|
||
// 尝试清理、重新初始化和启动
|
||
if err := plugin.Cleanup(ctx); err != nil {
|
||
return fmt.Errorf("清理插件失败: %v", err)
|
||
}
|
||
|
||
if err := plugin.Init(ctx, config); err != nil {
|
||
return fmt.Errorf("重新初始化插件失败: %v", err)
|
||
}
|
||
|
||
if plugin.IsEnabled() {
|
||
if err := plugin.Start(ctx); err != nil {
|
||
return fmt.Errorf("重新启动插件失败: %v", err)
|
||
}
|
||
}
|
||
|
||
// 发送恢复事件
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventCustom,
|
||
PluginID: name,
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"action": "recovered",
|
||
},
|
||
})
|
||
|
||
return nil
|
||
}
|
||
|
||
// RecoverAllPlugins 尝试恢复所有错误状态的插件
|
||
func (pm *PluginManager) RecoverAllPlugins(ctx context.Context) map[string]error {
|
||
errors := make(map[string]error)
|
||
|
||
pm.mu.RLock()
|
||
plugins := make([]IPlugin, 0)
|
||
for _, plugin := range pm.plugins {
|
||
if plugin.Status() == PluginStatusError {
|
||
plugins = append(plugins, plugin)
|
||
}
|
||
}
|
||
pm.mu.RUnlock()
|
||
|
||
for _, plugin := range plugins {
|
||
name := plugin.Name()
|
||
if err := pm.RecoverPlugin(ctx, name); err != nil {
|
||
errors[name] = err
|
||
}
|
||
}
|
||
|
||
return errors
|
||
}
|
||
|
||
// UnloadPlugin 卸载插件
|
||
func (pm *PluginManager) UnloadPlugin(ctx context.Context, name string) error {
|
||
pm.mu.Lock()
|
||
defer pm.mu.Unlock()
|
||
|
||
plugin, exists := pm.plugins[name]
|
||
if !exists {
|
||
return fmt.Errorf("插件 %s 不存在", name)
|
||
}
|
||
|
||
// 检查是否有其他插件依赖该插件
|
||
for otherName, otherPlugin := range pm.plugins {
|
||
if otherName == name {
|
||
continue
|
||
}
|
||
|
||
for _, dep := range otherPlugin.Dependencies() {
|
||
if dep.Name == name && !dep.IsOptional {
|
||
return fmt.Errorf("无法卸载插件 %s: 插件 %s 依赖它", name, otherName)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 停止并清理插件
|
||
if plugin.Status() == PluginStatusRunning {
|
||
if err := plugin.Stop(ctx); err != nil {
|
||
return fmt.Errorf("停止插件失败: %v", err)
|
||
}
|
||
}
|
||
|
||
if err := plugin.Cleanup(ctx); err != nil {
|
||
return fmt.Errorf("清理插件失败: %v", err)
|
||
}
|
||
|
||
// 从管理器中移除插件
|
||
delete(pm.plugins, name)
|
||
if typePlugins, exists := pm.pluginsByType[plugin.Type()]; exists {
|
||
delete(typePlugins, name)
|
||
}
|
||
|
||
// 发送卸载事件
|
||
pm.BroadcastEvent(PluginEvent{
|
||
Type: PluginEventCustom,
|
||
PluginID: name,
|
||
Timestamp: time.Now(),
|
||
Data: map[string]interface{}{
|
||
"action": "unloaded",
|
||
},
|
||
})
|
||
|
||
return nil
|
||
}
|
||
|
||
// topologicalSort 拓扑排序,解决依赖顺序问题
|
||
func topologicalSort(graph map[string][]string) ([]string, error) {
|
||
result := make([]string, 0, len(graph))
|
||
visited := make(map[string]bool)
|
||
temp := make(map[string]bool)
|
||
|
||
var visit func(string) error
|
||
visit = func(node string) error {
|
||
if temp[node] {
|
||
return fmt.Errorf("检测到循环依赖: %s", node)
|
||
}
|
||
if visited[node] {
|
||
return nil
|
||
}
|
||
temp[node] = true
|
||
|
||
for _, dep := range graph[node] {
|
||
if err := visit(dep); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
temp[node] = false
|
||
visited[node] = true
|
||
result = append(result, node)
|
||
return nil
|
||
}
|
||
|
||
for node := range graph {
|
||
if !visited[node] {
|
||
if err := visit(node); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// 简单的版本比较函数
|
||
func compareVersions(v1, v2 string) (int, error) {
|
||
// 移除可能的'v'前缀
|
||
v1 = strings.TrimPrefix(v1, "v")
|
||
v2 = strings.TrimPrefix(v2, "v")
|
||
|
||
// 分割版本号
|
||
parts1 := strings.Split(v1, ".")
|
||
parts2 := strings.Split(v2, ".")
|
||
|
||
// 确保有足够的部分进行比较
|
||
for len(parts1) < 3 {
|
||
parts1 = append(parts1, "0")
|
||
}
|
||
for len(parts2) < 3 {
|
||
parts2 = append(parts2, "0")
|
||
}
|
||
|
||
// 比较各部分
|
||
for i := 0; i < 3; i++ {
|
||
n1, err := strconv.Atoi(parts1[i])
|
||
if err != nil {
|
||
return 0, fmt.Errorf("无效的版本号部分 %s: %v", parts1[i], err)
|
||
}
|
||
|
||
n2, err := strconv.Atoi(parts2[i])
|
||
if err != nil {
|
||
return 0, fmt.Errorf("无效的版本号部分 %s: %v", parts2[i], err)
|
||
}
|
||
|
||
if n1 < n2 {
|
||
return -1, nil // v1 < v2
|
||
} else if n1 > n2 {
|
||
return 1, nil // v1 > v2
|
||
}
|
||
}
|
||
|
||
return 0, nil // v1 == v2
|
||
}
|
||
|
||
// PluginAdapter 插件适配器
|
||
// 用于将通过反射获取的插件包装为 IPlugin 接口
|
||
type PluginAdapter struct {
|
||
symPlugin interface{}
|
||
pluginValue reflect.Value
|
||
pluginName string
|
||
pluginVersion string
|
||
}
|
||
|
||
// Name 获取插件名称
|
||
func (p *PluginAdapter) Name() string {
|
||
return p.pluginName
|
||
}
|
||
|
||
// Version 获取插件版本
|
||
func (p *PluginAdapter) Version() string {
|
||
return p.pluginVersion
|
||
}
|
||
|
||
// Description 获取插件描述
|
||
func (p *PluginAdapter) Description() string {
|
||
method := p.pluginValue.MethodByName("Description")
|
||
if !method.IsValid() {
|
||
return "未提供描述"
|
||
}
|
||
return method.Call(nil)[0].String()
|
||
}
|
||
|
||
// Author 获取插件作者
|
||
func (p *PluginAdapter) Author() string {
|
||
method := p.pluginValue.MethodByName("Author")
|
||
if !method.IsValid() {
|
||
return "未知作者"
|
||
}
|
||
return method.Call(nil)[0].String()
|
||
}
|
||
|
||
// Type 获取插件类型
|
||
func (p *PluginAdapter) Type() PluginType {
|
||
method := p.pluginValue.MethodByName("Type")
|
||
if !method.IsValid() {
|
||
return PluginTypeGeneral
|
||
}
|
||
return PluginType(method.Call(nil)[0].String())
|
||
}
|
||
|
||
// Status 获取插件状态
|
||
func (p *PluginAdapter) Status() PluginStatus {
|
||
method := p.pluginValue.MethodByName("Status")
|
||
if !method.IsValid() {
|
||
return PluginStatusUninitialized
|
||
}
|
||
return PluginStatus(method.Call(nil)[0].String())
|
||
}
|
||
|
||
// Dependencies 获取插件依赖
|
||
func (p *PluginAdapter) Dependencies() []PluginDependency {
|
||
method := p.pluginValue.MethodByName("Dependencies")
|
||
if !method.IsValid() {
|
||
return []PluginDependency{}
|
||
}
|
||
|
||
result := method.Call(nil)[0]
|
||
if result.IsNil() {
|
||
return []PluginDependency{}
|
||
}
|
||
|
||
// 尝试直接类型断言
|
||
if dependencies, ok := result.Interface().([]PluginDependency); ok {
|
||
return dependencies
|
||
}
|
||
|
||
// 尝试使用反射迭代切片并转换每个元素
|
||
if result.Kind() == reflect.Slice {
|
||
length := result.Len()
|
||
dependencies := make([]PluginDependency, 0, length)
|
||
|
||
for i := 0; i < length; i++ {
|
||
item := result.Index(i).Interface()
|
||
|
||
// 尝试将元素转换为PluginDependency
|
||
if dep, ok := item.(PluginDependency); ok {
|
||
dependencies = append(dependencies, dep)
|
||
} else {
|
||
// 如果无法直接转换,尝试使用反射读取字段
|
||
depValue := reflect.ValueOf(item)
|
||
if depValue.Kind() == reflect.Struct || (depValue.Kind() == reflect.Ptr && depValue.Elem().Kind() == reflect.Struct) {
|
||
// 解引用指针
|
||
if depValue.Kind() == reflect.Ptr {
|
||
depValue = depValue.Elem()
|
||
}
|
||
|
||
dependency := PluginDependency{}
|
||
|
||
// 获取字段值
|
||
if nameField := depValue.FieldByName("Name"); nameField.IsValid() {
|
||
dependency.Name = nameField.String()
|
||
}
|
||
if minVersionField := depValue.FieldByName("MinVersion"); minVersionField.IsValid() {
|
||
dependency.MinVersion = minVersionField.String()
|
||
}
|
||
if maxVersionField := depValue.FieldByName("MaxVersion"); maxVersionField.IsValid() {
|
||
dependency.MaxVersion = maxVersionField.String()
|
||
}
|
||
if isOptionalField := depValue.FieldByName("IsOptional"); isOptionalField.IsValid() && isOptionalField.Kind() == reflect.Bool {
|
||
dependency.IsOptional = isOptionalField.Bool()
|
||
}
|
||
if loadAfterField := depValue.FieldByName("LoadAfter"); loadAfterField.IsValid() && loadAfterField.Kind() == reflect.Bool {
|
||
dependency.LoadAfter = loadAfterField.Bool()
|
||
}
|
||
if initAfterField := depValue.FieldByName("InitAfter"); initAfterField.IsValid() && initAfterField.Kind() == reflect.Bool {
|
||
dependency.InitAfter = initAfterField.Bool()
|
||
}
|
||
if strictVersionsField := depValue.FieldByName("StrictVersions"); strictVersionsField.IsValid() && strictVersionsField.Kind() == reflect.Bool {
|
||
dependency.StrictVersions = strictVersionsField.Bool()
|
||
}
|
||
if autoDisableWithField := depValue.FieldByName("AutoDisableWith"); autoDisableWithField.IsValid() && autoDisableWithField.Kind() == reflect.Bool {
|
||
dependency.AutoDisableWith = autoDisableWithField.Bool()
|
||
}
|
||
|
||
dependencies = append(dependencies, dependency)
|
||
}
|
||
}
|
||
}
|
||
|
||
return dependencies
|
||
}
|
||
|
||
return []PluginDependency{}
|
||
}
|
||
|
||
// Init 初始化插件
|
||
func (p *PluginAdapter) Init(ctx context.Context, config map[string]interface{}) error {
|
||
method := p.pluginValue.MethodByName("Init")
|
||
if !method.IsValid() {
|
||
fmt.Printf("插件 %s 没有 Init 方法,跳过初始化\n", p.Name())
|
||
return nil
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
reflect.ValueOf(config),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Start 启动插件
|
||
func (p *PluginAdapter) Start(ctx context.Context) error {
|
||
method := p.pluginValue.MethodByName("Start")
|
||
if !method.IsValid() {
|
||
fmt.Printf("插件 %s 没有 Start 方法,跳过启动\n", p.Name())
|
||
return nil
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Stop 停止插件
|
||
func (p *PluginAdapter) Stop(ctx context.Context) error {
|
||
method := p.pluginValue.MethodByName("Stop")
|
||
if !method.IsValid() {
|
||
return fmt.Errorf("插件未实现 Stop 方法")
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// IsEnabled 插件是否启用
|
||
func (p *PluginAdapter) IsEnabled() bool {
|
||
method := p.pluginValue.MethodByName("IsEnabled")
|
||
if !method.IsValid() {
|
||
return true
|
||
}
|
||
|
||
return method.Call(nil)[0].Bool()
|
||
}
|
||
|
||
// SetEnabled 设置插件启用状态
|
||
func (p *PluginAdapter) SetEnabled(enabled bool) {
|
||
method := p.pluginValue.MethodByName("SetEnabled")
|
||
if !method.IsValid() {
|
||
return
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(enabled),
|
||
}
|
||
|
||
method.Call(args)
|
||
}
|
||
|
||
// GetOperationInfo 获取操作的参数信息
|
||
func (p *PluginAdapter) GetOperationInfo(operation string) (*OperationInfo, error) {
|
||
method := p.pluginValue.MethodByName("GetOperationInfo")
|
||
if !method.IsValid() {
|
||
return nil, fmt.Errorf("插件未实现 GetOperationInfo 方法")
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(operation),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 1 && !result[1].IsNil() {
|
||
return nil, result[1].Interface().(error)
|
||
}
|
||
|
||
if result[0].IsNil() {
|
||
return nil, nil
|
||
}
|
||
|
||
// 尝试直接类型断言
|
||
if opInfo, ok := result[0].Interface().(*OperationInfo); ok {
|
||
return opInfo, nil
|
||
}
|
||
|
||
// 如果直接断言失败,尝试使用反射获取字段值
|
||
opValue := reflect.Indirect(result[0])
|
||
if opValue.Kind() != reflect.Struct {
|
||
// 如果不是结构体,返回基本信息
|
||
return &OperationInfo{
|
||
Name: operation,
|
||
Description: "通过适配器调用的操作",
|
||
Params: []OperationParamInfo{},
|
||
}, nil
|
||
}
|
||
|
||
// 创建操作信息对象
|
||
opInfo := &OperationInfo{
|
||
Name: operation,
|
||
Description: "",
|
||
Params: []OperationParamInfo{},
|
||
Extra: make(map[string]interface{}),
|
||
}
|
||
|
||
// 获取描述字段
|
||
if descField := opValue.FieldByName("Description"); descField.IsValid() && descField.Kind() == reflect.String {
|
||
opInfo.Description = descField.String()
|
||
}
|
||
|
||
// 获取参数列表
|
||
if paramsField := opValue.FieldByName("Params"); paramsField.IsValid() && paramsField.Kind() == reflect.Slice {
|
||
length := paramsField.Len()
|
||
opInfo.Params = make([]OperationParamInfo, 0, length)
|
||
|
||
for i := 0; i < length; i++ {
|
||
paramValue := reflect.Indirect(paramsField.Index(i))
|
||
if paramValue.Kind() != reflect.Struct {
|
||
continue
|
||
}
|
||
|
||
param := OperationParamInfo{}
|
||
|
||
// 获取参数字段
|
||
if nameField := paramValue.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||
param.Name = nameField.String()
|
||
}
|
||
if typeField := paramValue.FieldByName("Type"); typeField.IsValid() && typeField.Kind() == reflect.String {
|
||
param.Type = typeField.String()
|
||
}
|
||
if requiredField := paramValue.FieldByName("Required"); requiredField.IsValid() && requiredField.Kind() == reflect.Bool {
|
||
param.Required = requiredField.Bool()
|
||
}
|
||
if defaultField := paramValue.FieldByName("Default"); defaultField.IsValid() {
|
||
param.Default = defaultField.Interface()
|
||
}
|
||
if descField := paramValue.FieldByName("Description"); descField.IsValid() && descField.Kind() == reflect.String {
|
||
param.Description = descField.String()
|
||
}
|
||
|
||
opInfo.Params = append(opInfo.Params, param)
|
||
}
|
||
}
|
||
|
||
// 获取额外信息
|
||
if extraField := opValue.FieldByName("Extra"); extraField.IsValid() && extraField.Kind() == reflect.Map {
|
||
for _, key := range extraField.MapKeys() {
|
||
if key.Kind() == reflect.String {
|
||
opInfo.Extra[key.String()] = extraField.MapIndex(key).Interface()
|
||
}
|
||
}
|
||
}
|
||
|
||
return opInfo, nil
|
||
}
|
||
|
||
// GetAllOperations 获取所有操作及其参数信息
|
||
func (p *PluginAdapter) GetAllOperations() []*OperationInfo {
|
||
method := p.pluginValue.MethodByName("GetAllOperations")
|
||
if !method.IsValid() {
|
||
return []*OperationInfo{}
|
||
}
|
||
|
||
result := method.Call(nil)[0]
|
||
if result.IsNil() {
|
||
return []*OperationInfo{}
|
||
}
|
||
|
||
// 解析返回的操作信息并返回
|
||
if operations, ok := result.Interface().([]*OperationInfo); ok {
|
||
return operations
|
||
}
|
||
|
||
// 尝试使用反射获取切片内容
|
||
if result.Kind() == reflect.Slice {
|
||
length := result.Len()
|
||
operations := make([]*OperationInfo, 0, length)
|
||
|
||
for i := 0; i < length; i++ {
|
||
item := result.Index(i).Interface()
|
||
if op, ok := item.(*OperationInfo); ok {
|
||
operations = append(operations, op)
|
||
}
|
||
}
|
||
|
||
return operations
|
||
}
|
||
|
||
// 如果无法解析,返回空数组
|
||
return []*OperationInfo{}
|
||
}
|
||
|
||
// Execute 执行插件功能
|
||
func (p *PluginAdapter) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
|
||
// 首先尝试调用 Execute 方法
|
||
method := p.pluginValue.MethodByName("Execute")
|
||
if method.IsValid() {
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
reflect.ValueOf(action),
|
||
reflect.ValueOf(params),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
|
||
var retValue interface{}
|
||
var retError error
|
||
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
retValue = result[0].Interface()
|
||
}
|
||
|
||
if len(result) > 1 && !result[1].IsNil() {
|
||
retError = result[1].Interface().(error)
|
||
}
|
||
|
||
return retValue, retError
|
||
}
|
||
|
||
return nil, nil
|
||
}
|
||
|
||
// SubscribeEvent 订阅插件事件
|
||
func (p *PluginAdapter) SubscribeEvent(eventType PluginEventType, handler PluginEventHandler) {
|
||
method := p.pluginValue.MethodByName("SubscribeEvent")
|
||
if !method.IsValid() {
|
||
return
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(eventType),
|
||
reflect.ValueOf(handler),
|
||
}
|
||
|
||
method.Call(args)
|
||
}
|
||
|
||
// UnsubscribeEvent 取消订阅插件事件
|
||
func (p *PluginAdapter) UnsubscribeEvent(eventType PluginEventType, handler PluginEventHandler) {
|
||
method := p.pluginValue.MethodByName("UnsubscribeEvent")
|
||
if !method.IsValid() {
|
||
return
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(eventType),
|
||
reflect.ValueOf(handler),
|
||
}
|
||
|
||
method.Call(args)
|
||
}
|
||
|
||
// EmitEvent 发送插件事件
|
||
func (p *PluginAdapter) EmitEvent(event PluginEvent) error {
|
||
method := p.pluginValue.MethodByName("EmitEvent")
|
||
if !method.IsValid() {
|
||
return nil
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(event),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Reload 重新加载插件
|
||
func (p *PluginAdapter) Reload(ctx context.Context, config map[string]interface{}) error {
|
||
method := p.pluginValue.MethodByName("Reload")
|
||
if !method.IsValid() {
|
||
// 默认实现:先停止,然后重新初始化和启动
|
||
if err := p.Stop(ctx); err != nil {
|
||
return fmt.Errorf("停止插件失败: %v", err)
|
||
}
|
||
|
||
if err := p.Init(ctx, config); err != nil {
|
||
return fmt.Errorf("重新初始化插件失败: %v", err)
|
||
}
|
||
|
||
if p.IsEnabled() {
|
||
if err := p.Start(ctx); err != nil {
|
||
return fmt.Errorf("重新启动插件失败: %v", err)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
reflect.ValueOf(config),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Cleanup 清理插件资源
|
||
func (p *PluginAdapter) Cleanup(ctx context.Context) error {
|
||
method := p.pluginValue.MethodByName("Cleanup")
|
||
if !method.IsValid() {
|
||
// 默认实现:停止插件
|
||
if p.Status() == PluginStatusRunning {
|
||
return p.Stop(ctx)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(ctx),
|
||
}
|
||
|
||
result := method.Call(args)
|
||
if len(result) > 0 && !result[0].IsNil() {
|
||
return result[0].Interface().(error)
|
||
}
|
||
|
||
return nil
|
||
}
|