feat(variable): 新增全局变量支持,自动注入请求上下文
This commit is contained in:
parent
412bfebdd8
commit
668ecde6db
@ -67,6 +67,50 @@ var pool = sync.Pool{
|
||||
},
|
||||
}
|
||||
|
||||
// 全局自定义变量存储
|
||||
var (
|
||||
globalVariables map[string]string
|
||||
globalVariablesLock sync.RWMutex
|
||||
)
|
||||
|
||||
// SetGlobalVariables 设置全局自定义变量。
|
||||
// 在应用启动或配置重载时调用。
|
||||
func SetGlobalVariables(vars map[string]string) {
|
||||
globalVariablesLock.Lock()
|
||||
defer globalVariablesLock.Unlock()
|
||||
globalVariables = make(map[string]string, len(vars))
|
||||
for k, v := range vars {
|
||||
globalVariables[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetGlobalVariable 获取全局变量值。
|
||||
func GetGlobalVariable(name string) (string, bool) {
|
||||
globalVariablesLock.RLock()
|
||||
defer globalVariablesLock.RUnlock()
|
||||
if globalVariables == nil {
|
||||
return "", false
|
||||
}
|
||||
v, ok := globalVariables[name]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// GetAllGlobalVariables 获取所有全局变量的副本。
|
||||
// 用于在 NewVariableContext 中批量注入。
|
||||
func GetAllGlobalVariables() map[string]string {
|
||||
globalVariablesLock.RLock()
|
||||
defer globalVariablesLock.RUnlock()
|
||||
if globalVariables == nil {
|
||||
return nil
|
||||
}
|
||||
// 返回副本,避免外部修改影响全局存储
|
||||
result := make(map[string]string, len(globalVariables))
|
||||
for k, v := range globalVariables {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// builtinVars 内置变量注册表
|
||||
var builtinVars = make(map[string]*BuiltinVariable)
|
||||
|
||||
@ -80,7 +124,7 @@ func GetBuiltin(name string) *BuiltinVariable {
|
||||
return builtinVars[name]
|
||||
}
|
||||
|
||||
// NewVariableContext 从池中获取 VariableContext
|
||||
// NewVariableContext 从池中获取 VariableContext,并注入全局变量。
|
||||
func NewVariableContext(ctx *fasthttp.RequestCtx) *VariableContext {
|
||||
vc := pool.Get().(*VariableContext)
|
||||
vc.ctx = ctx
|
||||
@ -97,10 +141,15 @@ func NewVariableContext(ctx *fasthttp.RequestCtx) *VariableContext {
|
||||
for k := range vc.cache {
|
||||
delete(vc.cache, k)
|
||||
}
|
||||
// 清空自定义变量
|
||||
// 清空自定义变量 store,然后注入全局变量
|
||||
for k := range vc.store {
|
||||
delete(vc.store, k)
|
||||
}
|
||||
// 注入全局变量
|
||||
globals := GetAllGlobalVariables()
|
||||
for name, value := range globals {
|
||||
vc.store[name] = value
|
||||
}
|
||||
return vc
|
||||
}
|
||||
|
||||
|
||||
@ -1035,3 +1035,101 @@ func BenchmarkUpstreamVariables(b *testing.B) {
|
||||
_, _ = vc.Get(VarUpstreamResponseTime)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGlobalVariables 测试全局变量功能
|
||||
func TestGlobalVariables(t *testing.T) {
|
||||
// 清理
|
||||
SetGlobalVariables(nil)
|
||||
|
||||
// 测试设置全局变量
|
||||
SetGlobalVariables(map[string]string{
|
||||
"app_name": "lolly",
|
||||
"version": "1.0.0",
|
||||
})
|
||||
|
||||
// 测试 GetGlobalVariable
|
||||
if v, ok := GetGlobalVariable("app_name"); !ok || v != "lolly" {
|
||||
t.Errorf("GetGlobalVariable('app_name') = %q, %v, want 'lolly', true", v, ok)
|
||||
}
|
||||
|
||||
if v, ok := GetGlobalVariable("notexist"); ok {
|
||||
t.Errorf("GetGlobalVariable('notexist') = %q, %v, want '', false", v, ok)
|
||||
}
|
||||
|
||||
// 测试 GetAllGlobalVariables
|
||||
globals := GetAllGlobalVariables()
|
||||
if globals == nil {
|
||||
t.Error("GetAllGlobalVariables() returned nil")
|
||||
}
|
||||
if globals["app_name"] != "lolly" {
|
||||
t.Errorf("globals['app_name'] = %q, want 'lolly'", globals["app_name"])
|
||||
}
|
||||
|
||||
// 测试返回副本而非引用
|
||||
globals["app_name"] = "modified"
|
||||
if v, _ := GetGlobalVariable("app_name"); v != "lolly" {
|
||||
t.Error("GetAllGlobalVariables() should return a copy, not a reference")
|
||||
}
|
||||
|
||||
// 清理
|
||||
SetGlobalVariables(nil)
|
||||
}
|
||||
|
||||
// TestNewVariableContextWithGlobals 测试全局变量注入到请求上下文
|
||||
func TestNewVariableContextWithGlobals(t *testing.T) {
|
||||
// 设置全局变量
|
||||
SetGlobalVariables(map[string]string{
|
||||
"global_var": "global_value",
|
||||
})
|
||||
defer SetGlobalVariables(nil)
|
||||
|
||||
ctx := mockRequestCtx(t)
|
||||
vc := NewVariableContext(ctx)
|
||||
defer ReleaseVariableContext(vc)
|
||||
|
||||
// 全局变量应该被注入
|
||||
if v, ok := vc.Get("global_var"); !ok || v != "global_value" {
|
||||
t.Errorf("Get('global_var') = %q, %v, want 'global_value', true", v, ok)
|
||||
}
|
||||
|
||||
// 展开应该包含全局变量
|
||||
result := vc.Expand("$global_var")
|
||||
if result != "global_value" {
|
||||
t.Errorf("Expand('$global_var') = %q, want 'global_value'", result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGlobalVariablesConcurrent 测试全局变量并发访问
|
||||
func TestGlobalVariablesConcurrent(t *testing.T) {
|
||||
SetGlobalVariables(map[string]string{
|
||||
"counter": "0",
|
||||
})
|
||||
defer SetGlobalVariables(nil)
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
// 并发读取
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 100; j++ {
|
||||
_, _ = GetGlobalVariable("counter")
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// 并发写入
|
||||
for i := 0; i < 5; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 50; j++ {
|
||||
SetGlobalVariables(map[string]string{"counter": "updated"})
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// 等待所有 goroutine 完成
|
||||
for i := 0; i < 15; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user