增强插件系统:引入插件辅助器和自动方法发现功能

- 在插件系统中添加 PluginHelper 结构体,简化插件方法的自动发现和注册。
- 更新 BasePluginImpl 以支持通过辅助器执行插件方法,增强 Execute 方法的灵活性。
- 统计插件和示例程序中实现新的方法调用方式,展示如何使用自动注册的方法。
- 通过结构体参数传递,简化插件调用过程,提升用户体验。

此更新提升了插件系统的可扩展性和易用性,便于开发者动态管理和执行插件功能。
This commit is contained in:
2025-03-14 11:37:42 +08:00
parent 9f78cb483b
commit b6bf2c5699
6 changed files with 969 additions and 193 deletions

View File

@@ -9,7 +9,10 @@ import (
"os"
"path/filepath"
"plugin"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
)
@@ -42,24 +45,453 @@ type Plugin interface {
Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error)
}
// 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
}
// 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)
}
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)
}
// BasePluginImpl 提供插件接口的基本实现用于适配Plugin接口
// 这个结构体包装了BasePlugin以便兼容context参数
type BasePluginImpl struct {
*BasePlugin
helper *PluginHelper // 添加插件辅助器
}
// NewPlugin 创建一个基本插件实现,带有插件类型
func NewPlugin(name, version, description, author string, pluginType PluginType) *BasePluginImpl {
return &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 {
return &BasePluginImpl{
plugin := &BasePluginImpl{
BasePlugin: NewBasePluginWithDefaultType(name, version, description, author),
}
plugin.helper = NewPluginHelper(plugin)
return plugin
}
// Init 适配Init方法以支持context参数
@@ -77,9 +509,26 @@ func (p *BasePluginImpl) Stop(ctx context.Context) error {
return p.BasePlugin.Stop()
}
// Execute 适配Execute方法以支持context参数
// Execute 通过辅助器自动执行插件方法
func (p *BasePluginImpl) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
return p.BasePlugin.Execute(action, params)
// 首先尝试通过辅助器执行方法
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()
}
// PluginInfo 插件信息