- 在插件管理器中引入 DynamicPlugin 结构体,支持动态加载和管理插件,提升插件的灵活性和可扩展性。 - 更新插件接口,添加插件名称、版本、描述、作者、类型和启用状态的获取和设置方法,增强插件信息的管理能力。 - 修改现有插件实现,确保兼容新的动态插件结构,提升插件的统一性和可维护性。 - 更新示例程序,展示如何使用新的动态插件功能,提升用户体验。 此更新提升了插件系统的灵活性和可扩展性,便于开发者更好地管理和使用插件功能。
297 lines
7.4 KiB
Go
297 lines
7.4 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"sync"
|
||
"time"
|
||
|
||
"github.com/darkit/goproxy/examples/plugin"
|
||
)
|
||
|
||
// StatsPlugin 统计插件
|
||
// 用于收集和记录系统运行时统计数据
|
||
type StatsPlugin struct {
|
||
plugin.Plugin // 嵌入接口,确保类型检查
|
||
name string // 插件名称
|
||
version string // 插件版本
|
||
description string // 插件描述
|
||
author string // 插件作者
|
||
pluginType plugin.PluginType // 插件类型
|
||
enabled bool // 是否启用
|
||
stats map[string]int64
|
||
startTime time.Time
|
||
mu sync.RWMutex
|
||
tickerStop chan bool
|
||
ticker *time.Ticker
|
||
config map[string]interface{}
|
||
}
|
||
|
||
// StatsParams 统计请求参数结构体
|
||
// 允许通过结构体传递参数,简化调用
|
||
type StatsParams struct {
|
||
Name string `json:"name"` // 统计项名称
|
||
Value int64 `json:"value"` // 统计值
|
||
BytesReceived int64 `json:"bytesReceived"` // 接收字节数
|
||
BytesSent int64 `json:"bytesSent"` // 发送字节数
|
||
IsError bool `json:"isError"` // 是否为错误请求
|
||
}
|
||
|
||
// Plugin 导出的插件变量
|
||
var Plugin = &StatsPlugin{
|
||
name: "StatsPlugin",
|
||
version: "1.0.0",
|
||
description: "系统运行时统计插件",
|
||
author: "开发者",
|
||
pluginType: plugin.PluginTypeUtils, // 指定为工具类插件
|
||
enabled: true,
|
||
stats: make(map[string]int64),
|
||
tickerStop: make(chan bool),
|
||
}
|
||
|
||
// Name 返回插件名称
|
||
func (p *StatsPlugin) Name() string {
|
||
return p.name
|
||
}
|
||
|
||
// Version 返回插件版本
|
||
func (p *StatsPlugin) Version() string {
|
||
return p.version
|
||
}
|
||
|
||
// Description 返回插件描述
|
||
func (p *StatsPlugin) Description() string {
|
||
return p.description
|
||
}
|
||
|
||
// Author 返回插件作者
|
||
func (p *StatsPlugin) Author() string {
|
||
return p.author
|
||
}
|
||
|
||
// Type 返回插件类型
|
||
func (p *StatsPlugin) Type() plugin.PluginType {
|
||
return p.pluginType
|
||
}
|
||
|
||
// IsEnabled 返回插件是否启用
|
||
func (p *StatsPlugin) IsEnabled() bool {
|
||
return p.enabled
|
||
}
|
||
|
||
// SetEnabled 设置插件启用状态
|
||
func (p *StatsPlugin) SetEnabled(enabled bool) {
|
||
p.enabled = enabled
|
||
}
|
||
|
||
// GetOperationInfo 获取操作的参数信息
|
||
func (p *StatsPlugin) GetOperationInfo(operation string) (map[string]interface{}, error) {
|
||
return map[string]interface{}{}, nil
|
||
}
|
||
|
||
// GetAllOperations 获取所有操作及其参数信息
|
||
func (p *StatsPlugin) GetAllOperations() map[string]map[string]interface{} {
|
||
return map[string]map[string]interface{}{}
|
||
}
|
||
|
||
// Init 初始化插件
|
||
func (p *StatsPlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
||
p.config = config
|
||
|
||
// 初始化统计指标
|
||
p.mu.Lock()
|
||
p.stats["requests"] = 0
|
||
p.stats["errors"] = 0
|
||
p.stats["bytes_sent"] = 0
|
||
p.stats["bytes_received"] = 0
|
||
p.mu.Unlock()
|
||
|
||
fmt.Println("统计插件初始化完成")
|
||
return nil
|
||
}
|
||
|
||
// Start 启动插件
|
||
func (p *StatsPlugin) Start(ctx context.Context) error {
|
||
p.startTime = time.Now()
|
||
|
||
// 启动定时统计任务
|
||
interval := 60 * time.Second // 默认60秒
|
||
|
||
// 从配置中获取统计间隔
|
||
if intervalSec, ok := p.config["interval_seconds"].(float64); ok {
|
||
interval = time.Duration(intervalSec) * time.Second
|
||
}
|
||
|
||
p.ticker = time.NewTicker(interval)
|
||
|
||
go func() {
|
||
for {
|
||
select {
|
||
case <-p.ticker.C:
|
||
p.logStats()
|
||
case <-p.tickerStop:
|
||
p.ticker.Stop()
|
||
return
|
||
case <-ctx.Done():
|
||
p.ticker.Stop()
|
||
return
|
||
}
|
||
}
|
||
}()
|
||
|
||
fmt.Println("统计插件已启动")
|
||
return nil
|
||
}
|
||
|
||
// Stop 停止插件
|
||
func (p *StatsPlugin) Stop(ctx context.Context) error {
|
||
if p.ticker != nil {
|
||
p.tickerStop <- true
|
||
}
|
||
|
||
// 输出最终统计信息
|
||
p.logStats()
|
||
|
||
fmt.Println("统计插件已停止")
|
||
return nil
|
||
}
|
||
|
||
// 以下方法将被自动注册为可通过Execute调用的操作
|
||
|
||
// IncrementStat 增加统计值
|
||
// 会被自动注册为"incrementstat"操作
|
||
func (p *StatsPlugin) IncrementStat(name string, value int64) error {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
|
||
if _, exists := p.stats[name]; exists {
|
||
p.stats[name] += value
|
||
} else {
|
||
p.stats[name] = value
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetStat 获取统计值
|
||
// 会被自动注册为"getstat"操作
|
||
func (p *StatsPlugin) GetStat(name string) (int64, error) {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
if value, exists := p.stats[name]; exists {
|
||
return value, nil
|
||
}
|
||
return 0, fmt.Errorf("统计项 %s 不存在", name)
|
||
}
|
||
|
||
// RecordRequest 记录请求
|
||
// 会被自动注册为"recordrequest"操作
|
||
func (p *StatsPlugin) RecordRequest(ctx context.Context, params StatsParams) error {
|
||
p.IncrementStat("requests", 1)
|
||
p.IncrementStat("bytes_received", params.BytesReceived)
|
||
p.IncrementStat("bytes_sent", params.BytesSent)
|
||
|
||
if params.IsError {
|
||
p.IncrementStat("errors", 1)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ResetStats 重置统计数据
|
||
// 会被自动注册为"resetstats"操作
|
||
func (p *StatsPlugin) ResetStats() error {
|
||
p.mu.Lock()
|
||
defer p.mu.Unlock()
|
||
|
||
p.stats = make(map[string]int64)
|
||
p.stats["requests"] = 0
|
||
p.stats["errors"] = 0
|
||
p.stats["bytes_sent"] = 0
|
||
p.stats["bytes_received"] = 0
|
||
p.startTime = time.Now()
|
||
|
||
return nil
|
||
}
|
||
|
||
// GenerateStatsReport 生成统计报告
|
||
// 会被自动注册为"generatestatsreport"操作
|
||
func (p *StatsPlugin) GenerateStatsReport() (map[string]interface{}, error) {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
uptime := time.Since(p.startTime).Seconds()
|
||
report := map[string]interface{}{
|
||
"uptime_seconds": uptime,
|
||
"stats": p.stats,
|
||
}
|
||
|
||
if uptime > 0 && p.stats["requests"] > 0 {
|
||
report["requests_per_second"] = float64(p.stats["requests"]) / uptime
|
||
report["error_rate"] = float64(p.stats["errors"]) * 100 / float64(p.stats["requests"])
|
||
}
|
||
|
||
return report, nil
|
||
}
|
||
|
||
// GetAllStats 获取所有统计数据
|
||
// 会被自动注册为"getallstats"操作
|
||
func (p *StatsPlugin) GetAllStats() (map[string]int64, error) {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
// 创建一个副本
|
||
statsCopy := make(map[string]int64, len(p.stats))
|
||
for k, v := range p.stats {
|
||
statsCopy[k] = v
|
||
}
|
||
|
||
// 添加运行时间
|
||
statsCopy["uptime_seconds"] = int64(time.Since(p.startTime).Seconds())
|
||
|
||
return statsCopy, nil
|
||
}
|
||
|
||
// logStats 记录当前统计信息
|
||
// 不会被注册为操作,因为它是内部方法
|
||
func (p *StatsPlugin) logStats() {
|
||
p.mu.RLock()
|
||
defer p.mu.RUnlock()
|
||
|
||
uptime := time.Since(p.startTime).Seconds()
|
||
|
||
fmt.Printf("===== 系统统计信息 =====\n")
|
||
fmt.Printf("运行时间: %.2f 秒\n", uptime)
|
||
fmt.Printf("总请求数: %d\n", p.stats["requests"])
|
||
fmt.Printf("错误数: %d\n", p.stats["errors"])
|
||
fmt.Printf("发送字节: %d\n", p.stats["bytes_sent"])
|
||
fmt.Printf("接收字节: %d\n", p.stats["bytes_received"])
|
||
|
||
if uptime > 0 && p.stats["requests"] > 0 {
|
||
fmt.Printf("平均请求/秒: %.2f\n", float64(p.stats["requests"])/uptime)
|
||
fmt.Printf("错误率: %.2f%%\n", float64(p.stats["errors"])*100/float64(p.stats["requests"]))
|
||
}
|
||
|
||
fmt.Printf("=======================\n")
|
||
}
|
||
|
||
// GetAvailableOperations 获取可用操作列表
|
||
// 这是一个帮助方法,列出所有可通过Execute调用的操作
|
||
func (p *StatsPlugin) GetAvailableOperations() []string {
|
||
// 返回硬编码的操作列表,而不是调用不存在的方法
|
||
return []string{
|
||
"incrementstat",
|
||
"getstat",
|
||
"recordrequest",
|
||
"resetstats",
|
||
"generatestatsreport",
|
||
"getallstats",
|
||
}
|
||
}
|
||
|
||
// main 函数是必须的,但不会被调用
|
||
func main() {
|
||
// 不会被执行,仅用于编译插件
|
||
}
|