Files
goproxy/examples/plugin/plugin.go
DarkiT cc4c677553 增强插件系统:添加参数验证功能
- 在插件助手中新增 ValidateParams 函数,用于验证传入参数是否符合定义,确保参数的完整性和正确性。
- 更新 ExecuteAction 方法,集成参数验证逻辑,提升插件执行的安全性和可靠性。
- 示例程序中添加新的选项,展示如何生成插件API文档和OpenAPI/Swagger文档,增强用户体验。

此更新提升了插件系统的健壮性,便于开发者更好地管理和使用插件功能。
2025-03-14 13:32:36 +08:00

1464 lines
38 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

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

package plugin
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"plugin"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
)
// Plugin 插件接口
type Plugin interface {
// Name 插件名称
Name() string
// Version 插件版本
Version() string
// Description 插件描述
Description() string
// Author 插件作者
Author() string
// Type 插件类型
Type() PluginType
// Init 初始化插件
Init(ctx context.Context, config map[string]interface{}) error
// Start 启动插件
Start(ctx context.Context) error
// Stop 停止插件
Stop(ctx context.Context) error
// IsEnabled 插件是否启用
IsEnabled() bool
// SetEnabled 设置插件启用状态
SetEnabled(enabled bool)
// Execute 执行插件功能
// action: 要执行的操作名称
// params: 操作所需的参数
// 返回操作结果和可能的错误
Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error)
// GetOperationInfo 获取操作的参数信息
GetOperationInfo(operation string) (map[string]interface{}, error)
// GetAllOperations 获取所有操作及其参数信息
GetAllOperations() map[string]map[string]interface{}
}
// PluginHelper 插件辅助器
// 用于自动发现和注册插件方法简化Execute方法的实现
type PluginHelper struct {
instance interface{} // 插件实例
methods map[string]reflect.Method // 注册的方法
methodParams map[string][]reflect.Type // 方法的参数类型
methodRetValues map[string][]reflect.Type // 方法的返回值类型
}
// NewPluginHelper 创建一个新的插件辅助器
func NewPluginHelper(instance interface{}) *PluginHelper {
helper := &PluginHelper{
instance: instance,
methods: make(map[string]reflect.Method),
methodParams: make(map[string][]reflect.Type),
methodRetValues: make(map[string][]reflect.Type),
}
helper.discoverMethods()
return helper
}
// discoverMethods 发现插件的所有可用方法
func (h *PluginHelper) discoverMethods() {
instanceType := reflect.TypeOf(h.instance)
// 遍历实例的所有方法
for i := 0; i < instanceType.NumMethod(); i++ {
method := instanceType.Method(i)
// 跳过特定的内部方法和接口方法
if shouldSkipMethod(method.Name) {
continue
}
// 获取方法的参数和返回值类型
var paramTypes []reflect.Type
var returnTypes []reflect.Type
// 跳过接收者参数 (第一个参数)
for j := 1; j < method.Type.NumIn(); j++ {
paramTypes = append(paramTypes, method.Type.In(j))
}
for j := 0; j < method.Type.NumOut(); j++ {
returnTypes = append(returnTypes, method.Type.Out(j))
}
// 注册方法
actionName := strings.ToLower(method.Name)
h.methods[actionName] = method
h.methodParams[actionName] = paramTypes
h.methodRetValues[actionName] = returnTypes
}
}
// shouldSkipMethod 检查是否应该跳过某些方法
func shouldSkipMethod(name string) bool {
// 跳过Plugin接口的方法和特定的内部方法
skipMethods := map[string]bool{
"Name": true,
"Version": true,
"Description": true,
"Author": true,
"Type": true,
"Init": true,
"Start": true,
"Stop": true,
"IsEnabled": true,
"SetEnabled": true,
"Execute": true,
}
return skipMethods[name]
}
// GetAvailableActions 获取所有可用的动作
func (h *PluginHelper) GetAvailableActions() []string {
actions := make([]string, 0, len(h.methods))
for action := range h.methods {
actions = append(actions, action)
}
return actions
}
// ValidateParams 验证传入的参数是否符合操作的参数定义
func ValidateParams(paramsDef map[string]interface{}, params map[string]interface{}) error {
// 检查参数定义是否存在
if paramsDef == nil {
return nil // 没有参数定义,不需要验证
}
// 获取参数定义中的每个参数
paramsInfo, ok := paramsDef["parameters"].(map[string]interface{})
if !ok {
return nil // 参数定义格式不正确,跳过验证
}
// 遍历每个参数定义进行验证
errors := make([]string, 0)
for paramName, paramInfo := range paramsInfo {
info, ok := paramInfo.(map[string]interface{})
if !ok {
continue // 参数信息格式不正确,跳过
}
// 检查是否为必需参数
required, ok := info["required"].(bool)
if ok && required {
// 对于结构体参数,要检查至少有一个字段被提供
if info["type"] == "struct" {
// 结构体参数的验证
if fields, ok := info["fields"].(map[string]interface{}); ok {
// 检查必填的结构体字段
for fieldName, fieldInfo := range fields {
if fieldInfoMap, ok := fieldInfo.(map[string]interface{}); ok {
fieldRequired, ok := fieldInfoMap["required"].(bool)
if ok && fieldRequired {
if _, exists := params[fieldName]; !exists {
errors = append(errors, fmt.Sprintf("缺少必需的结构体字段: %s", fieldName))
}
}
}
}
}
} else {
// 普通参数验证是否存在
if _, exists := params[paramName]; !exists {
errors = append(errors, fmt.Sprintf("缺少必需参数: %s", paramName))
}
}
}
// 如果参数存在,验证其类型
if value, exists := params[paramName]; exists && info["type"] != nil {
expectedType := info["type"].(string)
// 根据期望的类型验证参数
switch expectedType {
case "string":
if _, ok := value.(string); !ok {
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为字符串", paramName))
}
case "integer":
// 支持多种整数类型
switch value.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
// 这些类型都是可接受的
default:
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为整数", paramName))
}
case "float":
switch value.(type) {
case float32, float64:
// 这些类型是可接受的
default:
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为浮点数", paramName))
}
case "boolean":
if _, ok := value.(bool); !ok {
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为布尔值", paramName))
}
case "array":
if _, ok := value.([]interface{}); !ok {
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为数组", paramName))
}
case "object":
if _, ok := value.(map[string]interface{}); !ok {
errors = append(errors, fmt.Sprintf("参数 %s 类型错误,应为对象", paramName))
}
}
}
}
// 如果有错误,返回组合的错误信息
if len(errors) > 0 {
return fmt.Errorf("参数验证失败: %s", strings.Join(errors, "; "))
}
return nil
}
// ExecuteAction 执行指定的动作
func (h *PluginHelper) ExecuteAction(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
// 转换为小写以实现不区分大小写的匹配
action = strings.ToLower(action)
method, exists := h.methods[action]
if !exists {
return nil, fmt.Errorf("未知的操作: %s", action)
}
// 获取操作的参数信息并验证参数
opInfo, err := h.GetParameterInfo(action)
if err == nil {
// 验证参数
if err := ValidateParams(opInfo, params); err != nil {
return nil, err
}
}
paramTypes := h.methodParams[action]
// 准备参数
var args []reflect.Value
// 添加接收者参数
args = append(args, reflect.ValueOf(h.instance))
// 处理context参数
if len(paramTypes) > 0 && paramTypes[0].String() == "context.Context" {
args = append(args, reflect.ValueOf(ctx))
paramTypes = paramTypes[1:] // 移除已处理的context参数
}
// 处理其他参数
for i, paramType := range paramTypes {
paramName := fmt.Sprintf("arg%d", i)
// 如果是结构体参数尝试将整个params映射转换为该结构体
if paramType.Kind() == reflect.Struct {
structValue := reflect.New(paramType).Elem()
if err := mapToStruct(params, structValue); err != nil {
return nil, fmt.Errorf("转换参数失败: %v", err)
}
args = append(args, structValue)
continue
}
// 从params中获取参数
paramValue, ok := params[paramName]
if !ok {
// 尝试使用参数类型名称作为键
typeName := paramType.Name()
paramValue, ok = params[strings.ToLower(typeName)]
if !ok {
return nil, fmt.Errorf("缺少必需参数: %s", paramName)
}
}
// 转换参数类型
convertedValue, err := convertParamValue(paramValue, paramType)
if err != nil {
return nil, err
}
args = append(args, convertedValue)
}
// 调用方法
result := method.Func.Call(args)
// 处理返回值
if len(result) == 0 {
return nil, nil
} else if len(result) == 1 {
return result[0].Interface(), nil
} else {
// 处理多个返回值通常最后一个是error
lastIndex := len(result) - 1
if result[lastIndex].Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
if !result[lastIndex].IsNil() {
return nil, result[lastIndex].Interface().(error)
}
if lastIndex == 0 {
return nil, nil
}
return result[lastIndex-1].Interface(), nil
}
// 将所有返回值打包成一个映射
resultMap := make(map[string]interface{})
for i, v := range result {
resultMap[fmt.Sprintf("result%d", i)] = v.Interface()
}
return resultMap, nil
}
}
// mapToStruct 将map转换为结构体
func mapToStruct(m map[string]interface{}, structValue reflect.Value) error {
structType := structValue.Type()
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
fieldValue := structValue.Field(i)
if !fieldValue.CanSet() {
continue
}
// 尝试不同的命名方式
fieldName := field.Name
jsonTag := field.Tag.Get("json")
if jsonTag != "" && jsonTag != "-" {
parts := strings.Split(jsonTag, ",")
fieldName = parts[0]
}
// 检查不同大小写
value, ok := m[fieldName]
if !ok {
value, ok = m[strings.ToLower(fieldName)]
}
if !ok {
continue // 跳过未找到的字段
}
// 转换并设置字段值
convertedValue, err := convertParamValue(value, field.Type)
if err != nil {
return err
}
fieldValue.Set(convertedValue)
}
return nil
}
// convertParamValue 将接口值转换为指定类型
func convertParamValue(value interface{}, targetType reflect.Type) (reflect.Value, error) {
// 处理nil值
if value == nil {
return reflect.Zero(targetType), nil
}
valueType := reflect.TypeOf(value)
// 如果类型已经匹配,直接返回
if valueType.AssignableTo(targetType) {
return reflect.ValueOf(value), nil
}
// 类型转换
switch targetType.Kind() {
case reflect.String:
return reflect.ValueOf(fmt.Sprintf("%v", value)), nil
case reflect.Bool:
switch v := value.(type) {
case bool:
return reflect.ValueOf(v), nil
case string:
b, err := strconv.ParseBool(v)
if err != nil {
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为布尔值", value)
}
return reflect.ValueOf(b), nil
case float64:
return reflect.ValueOf(v != 0), nil
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var intVal int64
switch v := value.(type) {
case int:
intVal = int64(v)
case int8:
intVal = int64(v)
case int16:
intVal = int64(v)
case int32:
intVal = int64(v)
case int64:
intVal = v
case float32:
intVal = int64(v)
case float64:
intVal = int64(v)
case string:
var err error
intVal, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为整数", value)
}
default:
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为整数", value)
}
switch targetType.Kind() {
case reflect.Int:
return reflect.ValueOf(int(intVal)), nil
case reflect.Int8:
return reflect.ValueOf(int8(intVal)), nil
case reflect.Int16:
return reflect.ValueOf(int16(intVal)), nil
case reflect.Int32:
return reflect.ValueOf(int32(intVal)), nil
case reflect.Int64:
return reflect.ValueOf(intVal), nil
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
var uintVal uint64
switch v := value.(type) {
case uint:
uintVal = uint64(v)
case uint8:
uintVal = uint64(v)
case uint16:
uintVal = uint64(v)
case uint32:
uintVal = uint64(v)
case uint64:
uintVal = v
case int:
if v < 0 {
return reflect.Value{}, fmt.Errorf("无法将负数 %v 转换为无符号整数", value)
}
uintVal = uint64(v)
case float64:
if v < 0 {
return reflect.Value{}, fmt.Errorf("无法将负数 %v 转换为无符号整数", value)
}
uintVal = uint64(v)
case string:
var err error
uintVal, err = strconv.ParseUint(v, 10, 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为无符号整数", value)
}
default:
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为无符号整数", value)
}
switch targetType.Kind() {
case reflect.Uint:
return reflect.ValueOf(uint(uintVal)), nil
case reflect.Uint8:
return reflect.ValueOf(uint8(uintVal)), nil
case reflect.Uint16:
return reflect.ValueOf(uint16(uintVal)), nil
case reflect.Uint32:
return reflect.ValueOf(uint32(uintVal)), nil
case reflect.Uint64:
return reflect.ValueOf(uintVal), nil
}
case reflect.Float32, reflect.Float64:
var floatVal float64
switch v := value.(type) {
case float32:
floatVal = float64(v)
case float64:
floatVal = v
case int:
floatVal = float64(v)
case int64:
floatVal = float64(v)
case string:
var err error
floatVal, err = strconv.ParseFloat(v, 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为浮点数", value)
}
default:
return reflect.Value{}, fmt.Errorf("无法将 %v 转换为浮点数", value)
}
if targetType.Kind() == reflect.Float32 {
return reflect.ValueOf(float32(floatVal)), nil
}
return reflect.ValueOf(floatVal), nil
case reflect.Slice:
// 处理切片类型
srcVal := reflect.ValueOf(value)
if srcVal.Kind() == reflect.Slice {
// 创建目标类型的新切片
elemType := targetType.Elem()
newSlice := reflect.MakeSlice(targetType, srcVal.Len(), srcVal.Cap())
// 转换每个元素
for i := 0; i < srcVal.Len(); i++ {
elemValue, err := convertParamValue(srcVal.Index(i).Interface(), elemType)
if err != nil {
return reflect.Value{}, err
}
newSlice.Index(i).Set(elemValue)
}
return newSlice, nil
}
case reflect.Map:
// 处理映射类型
srcVal := reflect.ValueOf(value)
if srcVal.Kind() == reflect.Map {
keyType := targetType.Key()
elemType := targetType.Elem()
newMap := reflect.MakeMap(targetType)
iter := srcVal.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
newKey, err := convertParamValue(k.Interface(), keyType)
if err != nil {
return reflect.Value{}, err
}
newValue, err := convertParamValue(v.Interface(), elemType)
if err != nil {
return reflect.Value{}, err
}
newMap.SetMapIndex(newKey, newValue)
}
return newMap, nil
}
case reflect.Ptr:
// 处理指针类型
elemType := targetType.Elem()
elemValue, err := convertParamValue(value, elemType)
if err != nil {
return reflect.Value{}, err
}
ptrValue := reflect.New(elemType)
ptrValue.Elem().Set(elemValue)
return ptrValue, nil
}
return reflect.Value{}, fmt.Errorf("不支持将 %T 类型转换为 %s", value, targetType)
}
// GetParameterInfo 获取操作的参数信息
func (h *PluginHelper) GetParameterInfo(action string) (map[string]interface{}, error) {
action = strings.ToLower(action)
method, exists := h.methods[action]
if !exists {
return nil, fmt.Errorf("未知的操作: %s", action)
}
paramTypes := h.methodParams[action]
returnTypes := h.methodRetValues[action]
result := map[string]interface{}{
"name": action,
"description": fmt.Sprintf("%s 操作", method.Name),
"parameters": make(map[string]interface{}),
"returns": make(map[string]interface{}),
}
// 处理参数信息
paramsInfo := make(map[string]interface{})
// 首先检查是否有context参数
hasContext := false
if len(paramTypes) > 0 && paramTypes[0].String() == "context.Context" {
hasContext = true
result["hasContext"] = true
paramTypes = paramTypes[1:] // 跳过context参数
}
for i, paramType := range paramTypes {
// 如果是结构体参数,展开其字段
if paramType.Kind() == reflect.Struct {
structInfo := getStructInfo(paramType)
structInfo["position"] = i + 1 // 考虑到接收者和可能的context
if hasContext {
structInfo["position"] = i + 2
}
paramsInfo[paramType.Name()] = structInfo
} else {
// 基本类型参数
paramName := fmt.Sprintf("arg%d", i)
typeInfo := getTypeInfo(paramType)
typeInfo["position"] = i + 1 // 考虑到接收者
if hasContext {
typeInfo["position"] = i + 2
}
paramsInfo[paramName] = typeInfo
}
}
result["parameters"] = paramsInfo
// 处理返回值信息
returnsInfo := make(map[string]interface{})
for i, returnType := range returnTypes {
returnName := fmt.Sprintf("return%d", i)
if i == len(returnTypes)-1 && returnType.String() == "error" {
returnName = "error"
} else if i == 0 && len(returnTypes) == 2 && returnTypes[1].String() == "error" {
returnName = "result"
}
returnsInfo[returnName] = getTypeInfo(returnType)
}
result["returns"] = returnsInfo
return result, nil
}
// getStructInfo 获取结构体类型的详细信息
func getStructInfo(t reflect.Type) map[string]interface{} {
info := map[string]interface{}{
"type": "struct",
"name": t.Name(),
"package": t.PkgPath(),
"fields": make(map[string]interface{}),
"fieldCount": t.NumField(),
}
fields := make(map[string]interface{})
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// 跳过非导出字段
if field.PkgPath != "" {
continue
}
fieldName := field.Name
jsonTag := field.Tag.Get("json")
if jsonTag != "" && jsonTag != "-" {
parts := strings.Split(jsonTag, ",")
if parts[0] != "" {
fieldName = parts[0]
}
}
fieldInfo := getTypeInfo(field.Type)
fieldInfo["name"] = field.Name
fieldInfo["jsonName"] = fieldName
fieldInfo["position"] = i
fieldInfo["tags"] = string(field.Tag)
fields[fieldName] = fieldInfo
}
info["fields"] = fields
return info
}
// getTypeInfo 获取类型的基本信息
func getTypeInfo(t reflect.Type) map[string]interface{} {
info := map[string]interface{}{
"typeName": t.String(),
"kind": t.Kind().String(),
"type": typeKindToString(t.Kind()),
}
// 为不同类型添加特定信息
switch t.Kind() {
case reflect.Slice, reflect.Array:
info["elemType"] = getTypeInfo(t.Elem())
case reflect.Map:
info["keyType"] = getTypeInfo(t.Key())
info["valueType"] = getTypeInfo(t.Elem())
case reflect.Ptr:
info["elemType"] = getTypeInfo(t.Elem())
case reflect.Struct:
// 对于结构体,提供简略信息
info["structName"] = t.Name()
info["package"] = t.PkgPath()
info["fieldCount"] = t.NumField()
}
return info
}
// typeKindToString 将类型Kind转换为字符串表示
func typeKindToString(kind reflect.Kind) string {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return "integer"
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return "unsigned integer"
case reflect.Float32, reflect.Float64:
return "float"
case reflect.Bool:
return "boolean"
case reflect.String:
return "string"
case reflect.Slice, reflect.Array:
return "array"
case reflect.Map:
return "map"
case reflect.Struct:
return "object"
case reflect.Ptr:
return "pointer"
case reflect.Interface:
return "interface"
default:
return kind.String()
}
}
// BasePluginImpl 提供插件接口的基本实现用于适配Plugin接口
// 这个结构体包装了BasePlugin以便兼容context参数
type BasePluginImpl struct {
*BasePlugin
helper *PluginHelper // 添加插件辅助器
}
// NewPlugin 创建一个基本插件实现,带有插件类型
func NewPlugin(name, version, description, author string, pluginType PluginType) *BasePluginImpl {
plugin := &BasePluginImpl{
BasePlugin: NewBasePlugin(name, version, description, author, pluginType),
}
plugin.helper = NewPluginHelper(plugin)
return plugin
}
// NewPluginWithDefaultType 创建一个基本插件实现,使用默认的通用插件类型
func NewPluginWithDefaultType(name, version, description, author string) *BasePluginImpl {
plugin := &BasePluginImpl{
BasePlugin: NewBasePluginWithDefaultType(name, version, description, author),
}
plugin.helper = NewPluginHelper(plugin)
return plugin
}
// Init 适配Init方法以支持context参数
func (p *BasePluginImpl) Init(ctx context.Context, config map[string]interface{}) error {
return p.BasePlugin.Init(config)
}
// Start 适配Start方法以支持context参数
func (p *BasePluginImpl) Start(ctx context.Context) error {
return p.BasePlugin.Start()
}
// Stop 适配Stop方法以支持context参数
func (p *BasePluginImpl) Stop(ctx context.Context) error {
return p.BasePlugin.Stop()
}
// Execute 通过辅助器自动执行插件方法
func (p *BasePluginImpl) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
// 首先尝试通过辅助器执行方法
result, err := p.helper.ExecuteAction(ctx, action, params)
if err == nil {
return result, nil
}
// 如果辅助器执行失败,检查错误类型
if strings.Contains(err.Error(), "未知的操作") {
// 回退到基础实现
return p.BasePlugin.Execute(action, params)
}
return nil, err
}
// GetAvailableActions 获取插件支持的所有操作
func (p *BasePluginImpl) GetAvailableActions() []string {
return p.helper.GetAvailableActions()
}
// GetOperationInfo 获取操作的参数信息
func (p *BasePluginImpl) GetOperationInfo(operation string) (map[string]interface{}, error) {
return p.helper.GetParameterInfo(operation)
}
// GetAllOperations 获取所有操作及其参数信息
func (p *BasePluginImpl) GetAllOperations() map[string]map[string]interface{} {
operations := make(map[string]map[string]interface{})
for _, action := range p.helper.GetAvailableActions() {
info, err := p.helper.GetParameterInfo(action)
if err == nil {
operations[action] = info
}
}
return operations
}
// PluginInfo 插件信息
type PluginInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Author string `json:"author"`
Type PluginType `json:"type"`
Enabled bool `json:"enabled"`
Config map[string]interface{} `json:"config,omitempty"`
}
// PluginManager 插件管理器
type PluginManager struct {
pluginsDir string
plugins map[string]Plugin
pluginsByType map[PluginType]map[string]Plugin
configs map[string]map[string]interface{}
mu sync.RWMutex
dynamicLoadingSupported bool // 是否支持动态加载插件
}
// NewPluginManager 创建插件管理器
func NewPluginManager(pluginsDir string) *PluginManager {
// 检查当前系统是否支持动态加载插件
dynamicLoadingSupported := runtime.GOOS == "linux" || runtime.GOOS == "darwin"
return &PluginManager{
pluginsDir: pluginsDir,
plugins: make(map[string]Plugin),
pluginsByType: make(map[PluginType]map[string]Plugin),
configs: make(map[string]map[string]interface{}),
dynamicLoadingSupported: dynamicLoadingSupported,
}
}
// IsDynamicLoadingSupported 检查是否支持动态加载插件
func (pm *PluginManager) IsDynamicLoadingSupported() bool {
return pm.dynamicLoadingSupported
}
// LoadPlugins 加载插件
func (pm *PluginManager) LoadPlugins() error {
// 确保插件目录存在
if err := os.MkdirAll(pm.pluginsDir, 0o755); err != nil {
return fmt.Errorf("创建插件目录失败: %v", err)
}
// 加载插件配置
if err := pm.loadPluginConfigs(); err != nil {
return fmt.Errorf("加载插件配置失败: %v", err)
}
// 如果不支持动态加载,则返回
if !pm.dynamicLoadingSupported {
fmt.Printf("警告: 当前系统(%s)不支持动态加载插件,跳过加载\n", runtime.GOOS)
return nil
}
// 遍历插件目录
err := filepath.Walk(pm.pluginsDir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
// 跳过目录和非.so文件
if info.IsDir() || filepath.Ext(path) != ".so" {
return nil
}
// 加载插件
if err := pm.loadPlugin(path); err != nil {
fmt.Printf("加载插件 %s 失败: %v\n", path, err)
}
return nil
})
return err
}
// loadPluginConfigs 加载插件配置
func (pm *PluginManager) loadPluginConfigs() error {
configPath := filepath.Join(pm.pluginsDir, "plugins.json")
// 如果配置文件不存在,创建一个空的
if _, err := os.Stat(configPath); os.IsNotExist(err) {
file, err := os.Create(configPath)
if err != nil {
return fmt.Errorf("创建插件配置文件失败: %v", err)
}
file.Write([]byte("{}"))
file.Close()
return nil
}
// 读取配置文件
data, err := os.ReadFile(configPath)
if err != nil {
return fmt.Errorf("读取插件配置文件失败: %v", err)
}
// 解析配置
var configs map[string]map[string]interface{}
if err := json.Unmarshal(data, &configs); err != nil {
return fmt.Errorf("解析插件配置文件失败: %v", err)
}
pm.configs = configs
return nil
}
// savePluginConfigs 保存插件配置
func (pm *PluginManager) savePluginConfigs() error {
configPath := filepath.Join(pm.pluginsDir, "plugins.json")
// 创建配置数据
configs := make(map[string]map[string]interface{})
pm.mu.RLock()
for name, plugin := range pm.plugins {
config := pm.configs[name]
if config == nil {
config = make(map[string]interface{})
}
config["enabled"] = plugin.IsEnabled()
config["type"] = string(plugin.Type()) // 保存插件类型
configs[name] = config
}
pm.mu.RUnlock()
// 序列化配置
data, err := json.MarshalIndent(configs, "", " ")
if err != nil {
return fmt.Errorf("序列化插件配置失败: %v", err)
}
// 写入文件
if err := os.WriteFile(configPath, data, 0o644); err != nil {
return fmt.Errorf("写入插件配置文件失败: %v", err)
}
return nil
}
// loadPlugin 加载单个插件
func (pm *PluginManager) loadPlugin(path string) error {
// 打开插件文件
p, err := plugin.Open(path)
if err != nil {
return fmt.Errorf("打开插件失败: %v", err)
}
// 查找Plugin变量
symPlugin, err := p.Lookup("Plugin")
if err != nil {
return fmt.Errorf("查找Plugin变量失败: %v", err)
}
// 类型断言
plugin, ok := symPlugin.(Plugin)
if !ok {
return errors.New("插件类型错误")
}
// 检查插件名称是否已存在
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.plugins[plugin.Name()]; exists {
return fmt.Errorf("插件 %s 已存在", plugin.Name())
}
// 设置插件启用状态
if config, exists := pm.configs[plugin.Name()]; exists {
if enabled, ok := config["enabled"].(bool); ok {
plugin.SetEnabled(enabled)
} else {
plugin.SetEnabled(true) // 默认启用
}
} else {
plugin.SetEnabled(true) // 默认启用
}
// 注册插件
pm.registerPlugin(plugin)
return nil
}
// registerPlugin 注册插件到插件管理器
func (pm *PluginManager) registerPlugin(plugin Plugin) {
pluginType := plugin.Type()
// 将插件添加到按名称索引的映射
pm.plugins[plugin.Name()] = plugin
// 将插件添加到按类型索引的映射
if pm.pluginsByType[pluginType] == nil {
pm.pluginsByType[pluginType] = make(map[string]Plugin)
}
pm.pluginsByType[pluginType][plugin.Name()] = plugin
}
// RegisterPlugin 注册内置插件
// 用于在不支持动态加载的平台上注册插件
func (pm *PluginManager) RegisterPlugin(plugin Plugin) error {
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.plugins[plugin.Name()]; exists {
return fmt.Errorf("插件 %s 已存在", plugin.Name())
}
// 设置插件启用状态
if config, exists := pm.configs[plugin.Name()]; exists {
if enabled, ok := config["enabled"].(bool); ok {
plugin.SetEnabled(enabled)
} else {
plugin.SetEnabled(true) // 默认启用
}
} else {
plugin.SetEnabled(true) // 默认启用
}
// 注册插件
pm.registerPlugin(plugin)
return nil
}
// GetPlugin 获取插件
func (pm *PluginManager) GetPlugin(name string) (Plugin, bool) {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugin, exists := pm.plugins[name]
return plugin, exists
}
// GetPluginsByType 按类型获取插件
func (pm *PluginManager) GetPluginsByType(pluginType PluginType) []Plugin {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugins := make([]Plugin, 0)
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for _, plugin := range typePlugins {
if plugin.IsEnabled() {
plugins = append(plugins, plugin)
}
}
}
return plugins
}
// GetAllPluginsByType 获取所有指定类型的插件,无论是否启用
func (pm *PluginManager) GetAllPluginsByType(pluginType PluginType) []Plugin {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugins := make([]Plugin, 0)
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for _, plugin := range typePlugins {
plugins = append(plugins, plugin)
}
}
return plugins
}
// GetAllPlugins 获取所有插件
func (pm *PluginManager) GetAllPlugins() []Plugin {
pm.mu.RLock()
defer pm.mu.RUnlock()
plugins := make([]Plugin, 0, len(pm.plugins))
for _, plugin := range pm.plugins {
plugins = append(plugins, plugin)
}
return plugins
}
// GetPluginInfos 获取所有插件信息
func (pm *PluginManager) GetPluginInfos() []PluginInfo {
pm.mu.RLock()
defer pm.mu.RUnlock()
infos := make([]PluginInfo, 0, len(pm.plugins))
for name, plugin := range pm.plugins {
info := PluginInfo{
Name: plugin.Name(),
Version: plugin.Version(),
Description: plugin.Description(),
Author: plugin.Author(),
Type: plugin.Type(),
Enabled: plugin.IsEnabled(),
Config: pm.configs[name],
}
infos = append(infos, info)
}
return infos
}
// GetPluginInfosByType 按类型获取插件信息
func (pm *PluginManager) GetPluginInfosByType(pluginType PluginType) []PluginInfo {
pm.mu.RLock()
defer pm.mu.RUnlock()
infos := make([]PluginInfo, 0)
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for name, plugin := range typePlugins {
info := PluginInfo{
Name: plugin.Name(),
Version: plugin.Version(),
Description: plugin.Description(),
Author: plugin.Author(),
Type: plugin.Type(),
Enabled: plugin.IsEnabled(),
Config: pm.configs[name],
}
infos = append(infos, info)
}
}
return infos
}
// EnablePlugin 启用插件
func (pm *PluginManager) EnablePlugin(name string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
plugin.SetEnabled(true)
// 更新配置
if pm.configs[name] == nil {
pm.configs[name] = make(map[string]interface{})
}
pm.configs[name]["enabled"] = true
// 保存配置
return pm.savePluginConfigs()
}
// DisablePlugin 禁用插件
func (pm *PluginManager) DisablePlugin(name string) error {
pm.mu.Lock()
defer pm.mu.Unlock()
plugin, exists := pm.plugins[name]
if !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
plugin.SetEnabled(false)
// 更新配置
if pm.configs[name] == nil {
pm.configs[name] = make(map[string]interface{})
}
pm.configs[name]["enabled"] = false
// 保存配置
return pm.savePluginConfigs()
}
// InitPlugins 初始化所有插件
func (pm *PluginManager) InitPlugins(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
config := pm.configs[name]
if err := plugin.Init(ctx, config); err != nil {
return fmt.Errorf("初始化插件 %s 失败: %v", name, err)
}
}
return nil
}
// InitPluginsByType 初始化指定类型的所有插件
func (pm *PluginManager) InitPluginsByType(ctx context.Context, pluginType PluginType) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for name, plugin := range typePlugins {
if !plugin.IsEnabled() {
continue
}
config := pm.configs[name]
if err := plugin.Init(ctx, config); err != nil {
return fmt.Errorf("初始化插件 %s 失败: %v", name, err)
}
}
}
return nil
}
// StartPlugins 启动所有插件
func (pm *PluginManager) StartPlugins(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Start(ctx); err != nil {
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
}
}
return nil
}
// StartPluginsByType 启动指定类型的所有插件
func (pm *PluginManager) StartPluginsByType(ctx context.Context, pluginType PluginType) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for name, plugin := range typePlugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Start(ctx); err != nil {
return fmt.Errorf("启动插件 %s 失败: %v", name, err)
}
}
}
return nil
}
// StopPlugins 停止所有插件
func (pm *PluginManager) StopPlugins(ctx context.Context) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Stop(ctx); err != nil {
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
}
}
return nil
}
// StopPluginsByType 停止指定类型的所有插件
func (pm *PluginManager) StopPluginsByType(ctx context.Context, pluginType PluginType) error {
pm.mu.RLock()
defer pm.mu.RUnlock()
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for name, plugin := range typePlugins {
if !plugin.IsEnabled() {
continue
}
if err := plugin.Stop(ctx); err != nil {
return fmt.Errorf("停止插件 %s 失败: %v", name, err)
}
}
}
return nil
}
// SetPluginConfig 设置插件配置
func (pm *PluginManager) SetPluginConfig(name string, config map[string]interface{}) error {
pm.mu.Lock()
defer pm.mu.Unlock()
if _, exists := pm.plugins[name]; !exists {
return fmt.Errorf("插件 %s 不存在", name)
}
pm.configs[name] = config
return pm.savePluginConfigs()
}
// GetPluginConfig 获取插件配置
func (pm *PluginManager) GetPluginConfig(name string) (map[string]interface{}, error) {
pm.mu.RLock()
defer pm.mu.RUnlock()
if _, exists := pm.plugins[name]; !exists {
return nil, fmt.Errorf("插件 %s 不存在", name)
}
config := pm.configs[name]
if config == nil {
config = make(map[string]interface{})
}
return config, nil
}
// 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) (map[string]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.GetOperationInfo(operation)
}
// GetPluginAllOperations 获取插件所有操作及其参数信息
func (pm *PluginManager) GetPluginAllOperations(name string) (map[string]map[string]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.GetAllOperations(), nil
}
// GetOperationsByType 获取指定类型插件的所有操作信息
func (pm *PluginManager) GetOperationsByType(pluginType PluginType) map[string]map[string]map[string]interface{} {
pm.mu.RLock()
defer pm.mu.RUnlock()
result := make(map[string]map[string]map[string]interface{})
if typePlugins, exists := pm.pluginsByType[pluginType]; exists {
for name, plugin := range typePlugins {
if !plugin.IsEnabled() {
continue
}
result[name] = plugin.GetAllOperations()
}
}
return result
}
// GetAllPluginsOperations 获取所有插件的所有操作信息
func (pm *PluginManager) GetAllPluginsOperations() map[string]map[string]map[string]interface{} {
pm.mu.RLock()
defer pm.mu.RUnlock()
result := make(map[string]map[string]map[string]interface{})
for name, plugin := range pm.plugins {
if !plugin.IsEnabled() {
continue
}
result[name] = plugin.GetAllOperations()
}
return result
}