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
|
|
}
|