Files
2026-05-10 12:21:27 +08:00

139 lines
4.1 KiB
Go

package plugin
import (
"context"
"sort"
"sync"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/glog"
)
// ---------------------------------------------------------------------------
// 内置事件常量
// ---------------------------------------------------------------------------
const (
// Relay 相关(AI 代理核心流程)
HookRelayBeforeRequest = "relay.before_request" // 请求转发前(可修改请求、中断转发)
HookRelayAfterResponse = "relay.after_response" // 响应返回后(可修改响应、记录日志)
HookRelayOnError = "relay.on_error" // 转发失败(告警、重试决策)
// 计费相关
HookBillingBeforeDeduct = "billing.before_deduct" // 预扣前(可修改价格、跳过计费)
HookBillingAfterSettle = "billing.after_settle" // 结算后(用量分析、额度告警)
HookBillingOnRefund = "billing.on_refund" // 退款时(退款通知)
// 渠道相关
HookChannelBeforeSelect = "channel.before_select" // 渠道选择前(影响调度决策)
HookChannelOnHealthCheck = "channel.on_health_check" // 健康检查(自定义检查逻辑)
// 租户相关
HookTenantOnCreate = "tenant.on_create" // 租户创建后(初始化租户数据)
HookTenantOnSuspend = "tenant.on_suspend" // 租户暂停(清理资源)
// API Key 相关
HookApiKeyOnCreate = "apikey.on_create" // Key 创建后(通知、初始化)
HookApiKeyOnVerify = "apikey.on_verify" // Key 验证时(自定义验证逻辑)
)
// ---------------------------------------------------------------------------
// HookEmitter 事件发射器
// ---------------------------------------------------------------------------
// HookEmitter 全局事件发射器。
type HookEmitter struct {
handlers map[string][]hookEntry
mu sync.RWMutex
}
type hookEntry struct {
PluginName string
Priority int
Handler HookHandler
}
var globalEmitter = &HookEmitter{
handlers: make(map[string][]hookEntry),
}
// GlobalEmitter 获取全局事件发射器。
func GlobalEmitter() *HookEmitter {
return globalEmitter
}
// RegisterHook 注册事件处理器(由插件系统在启动时调用)。
func (e *HookEmitter) RegisterHook(pluginName, event string, priority int, handler HookHandler) {
e.mu.Lock()
defer e.mu.Unlock()
e.handlers[event] = append(e.handlers[event], hookEntry{
PluginName: pluginName,
Priority: priority,
Handler: handler,
})
}
// Emit 同步发射事件(按优先级顺序执行,可被中断)。
func (e *HookEmitter) Emit(ctx context.Context, event string, data g.Map) (HookResult, error) {
e.mu.RLock()
handlers := make([]hookEntry, len(e.handlers[event]))
copy(handlers, e.handlers[event])
e.mu.RUnlock()
// 零开销快速路径:无订阅者直接返回
if len(handlers) == 0 {
return HookResult{Data: data}, nil
}
// 按优先级排序(数字越小越先执行)
sort.Slice(handlers, func(i, j int) bool {
return handlers[i].Priority < handlers[j].Priority
})
result := HookResult{Data: data}
for _, entry := range handlers {
if result.Aborted {
break
}
payload := HookPayload{Event: event, Data: result.Data}
hr, err := entry.Handler(ctx, payload)
if err != nil {
glog.Warningf(ctx, "plugin hook error: plugin=%s event=%s err=%v",
entry.PluginName, event, err)
continue
}
if hr.Aborted {
result.Aborted = true
}
if hr.Data != nil {
for k, v := range hr.Data {
result.Data[k] = v
}
}
}
return result, nil
}
// EmitAsync 异步发射事件(不阻塞主流程,适用于日志、通知等场景)。
func (e *HookEmitter) EmitAsync(ctx context.Context, event string, data g.Map) {
go func() {
_, _ = e.Emit(ctx, event, data)
}()
}
// RemoveHooks 移除指定插件的所有 Hook 注册。
func (e *HookEmitter) RemoveHooks(pluginName string) {
e.mu.Lock()
defer e.mu.Unlock()
for event, entries := range e.handlers {
filtered := make([]hookEntry, 0, len(entries))
for _, entry := range entries {
if entry.PluginName != pluginName {
filtered = append(filtered, entry)
}
}
e.handlers[event] = filtered
}
}