- 在插件接口和基本插件实现中新增 Execute 方法,支持插件功能的动态执行。 - 更新各个插件(如日志插件、统计插件、存储插件等)以实现 Execute 方法,允许通过操作名称和参数执行特定功能。 - 在插件管理器中添加 ExecutePlugin、ExecutePluginsByType 和 ExecuteAllPlugins 方法,便于批量执行插件操作。 - 示例程序中更新插件调用方式,展示如何使用 Execute 方法进行操作。 此更新提升了插件系统的灵活性和可扩展性,便于开发者动态管理和执行插件功能。
217 lines
4.8 KiB
Go
217 lines
4.8 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"encoding/base64"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"sync"
|
||
|
||
"github.com/darkit/goproxy/examples/plugin"
|
||
)
|
||
|
||
// StoragePlugin 存储插件
|
||
// 提供简单的文件存储功能
|
||
type StoragePlugin struct {
|
||
*plugin.BasePlugin // 嵌入基本插件结构
|
||
storageDir string // 存储目录
|
||
config map[string]interface{} // 配置
|
||
mu sync.RWMutex // 读写锁
|
||
}
|
||
|
||
// Plugin 导出的插件变量
|
||
// 注意:变量名必须是Plugin,大小写敏感
|
||
var Plugin = &StoragePlugin{
|
||
BasePlugin: plugin.NewBasePlugin(
|
||
"StoragePlugin",
|
||
"1.0.0",
|
||
"简单的文件存储插件",
|
||
"开发者",
|
||
plugin.PluginTypeStorage, // 设置插件类型为存储插件
|
||
),
|
||
}
|
||
|
||
// Init 初始化插件
|
||
func (p *StoragePlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
||
p.config = config
|
||
|
||
// 获取存储目录路径
|
||
storageDir, ok := config["storage_dir"].(string)
|
||
if !ok {
|
||
// 使用默认路径
|
||
storageDir = "storage"
|
||
}
|
||
|
||
// 确保存储目录存在
|
||
if err := os.MkdirAll(storageDir, 0o755); err != nil {
|
||
return fmt.Errorf("创建存储目录失败: %v", err)
|
||
}
|
||
|
||
p.storageDir = storageDir
|
||
fmt.Println("存储插件初始化完成,存储目录:", storageDir)
|
||
|
||
return nil
|
||
}
|
||
|
||
// Start 启动插件
|
||
func (p *StoragePlugin) Start(ctx context.Context) error {
|
||
if p.storageDir == "" {
|
||
return fmt.Errorf("插件未初始化")
|
||
}
|
||
|
||
fmt.Println("存储插件已启动")
|
||
return nil
|
||
}
|
||
|
||
// Stop 停止插件
|
||
func (p *StoragePlugin) Stop(ctx context.Context) error {
|
||
fmt.Println("存储插件已停止")
|
||
return nil
|
||
}
|
||
|
||
// Execute 执行插件功能
|
||
func (p *StoragePlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
|
||
switch action {
|
||
case "saveFile":
|
||
// 需要参数: filename, data
|
||
filename, ok := params["filename"].(string)
|
||
if !ok {
|
||
return nil, fmt.Errorf("缺少必需参数: filename")
|
||
}
|
||
|
||
// 处理两种数据格式:字符串或Base64编码的二进制数据
|
||
var data []byte
|
||
if dataStr, ok := params["data"].(string); ok {
|
||
// 检查是否为Base64编码
|
||
if base64Str, ok := params["isBase64"].(bool); ok && base64Str {
|
||
var err error
|
||
data, err = base64.StdEncoding.DecodeString(dataStr)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("Base64解码失败: %v", err)
|
||
}
|
||
} else {
|
||
data = []byte(dataStr)
|
||
}
|
||
} else {
|
||
return nil, fmt.Errorf("缺少必需参数: data")
|
||
}
|
||
|
||
err := p.SaveFile(filename, data)
|
||
return err == nil, err
|
||
|
||
case "loadFile":
|
||
// 需要参数: filename, returnBase64
|
||
filename, ok := params["filename"].(string)
|
||
if !ok {
|
||
return nil, fmt.Errorf("缺少必需参数: filename")
|
||
}
|
||
|
||
returnBase64, _ := params["returnBase64"].(bool)
|
||
|
||
data, err := p.LoadFile(filename)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if returnBase64 {
|
||
return base64.StdEncoding.EncodeToString(data), nil
|
||
}
|
||
return string(data), nil
|
||
|
||
case "deleteFile":
|
||
// 需要参数: filename
|
||
filename, ok := params["filename"].(string)
|
||
if !ok {
|
||
return nil, fmt.Errorf("缺少必需参数: filename")
|
||
}
|
||
|
||
err := p.DeleteFile(filename)
|
||
return err == nil, err
|
||
|
||
case "listFiles":
|
||
// 不需要参数
|
||
files, err := p.ListFiles()
|
||
return files, err
|
||
|
||
case "getStorageInfo":
|
||
// 不需要参数
|
||
info := map[string]interface{}{
|
||
"storageDir": p.storageDir,
|
||
"config": p.config,
|
||
}
|
||
return info, nil
|
||
|
||
default:
|
||
return nil, fmt.Errorf("未知的操作: %s", action)
|
||
}
|
||
}
|
||
|
||
// SaveFile 保存文件
|
||
func (p *StoragePlugin) SaveFile(filename string, data []byte) error {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
|
||
if p.storageDir == "" {
|
||
return fmt.Errorf("插件未初始化")
|
||
}
|
||
|
||
filePath := filepath.Join(p.storageDir, filename)
|
||
return os.WriteFile(filePath, data, 0o644)
|
||
}
|
||
|
||
// LoadFile 加载文件
|
||
func (p *StoragePlugin) LoadFile(filename string) ([]byte, error) {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
if p.storageDir == "" {
|
||
return nil, fmt.Errorf("插件未初始化")
|
||
}
|
||
|
||
filePath := filepath.Join(p.storageDir, filename)
|
||
return os.ReadFile(filePath)
|
||
}
|
||
|
||
// DeleteFile 删除文件
|
||
func (p *StoragePlugin) DeleteFile(filename string) error {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
|
||
if p.storageDir == "" {
|
||
return fmt.Errorf("插件未初始化")
|
||
}
|
||
|
||
filePath := filepath.Join(p.storageDir, filename)
|
||
return os.Remove(filePath)
|
||
}
|
||
|
||
// ListFiles 列出所有文件
|
||
func (p *StoragePlugin) ListFiles() ([]string, error) {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
if p.storageDir == "" {
|
||
return nil, fmt.Errorf("插件未初始化")
|
||
}
|
||
|
||
var files []string
|
||
entries, err := os.ReadDir(p.storageDir)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for _, entry := range entries {
|
||
if !entry.IsDir() {
|
||
files = append(files, entry.Name())
|
||
}
|
||
}
|
||
|
||
return files, nil
|
||
}
|
||
|
||
// main 函数是必须的,但不会被调用
|
||
func main() {
|
||
// 不会被执行,仅用于编译插件
|
||
}
|