feat(config): 添加 Lua 中间件配置结构和验证
- 定义 LuaMiddlewareConfig、LuaScriptConfig、LuaGlobalSettings - 添加 validateLua 验证脚本路径、阶段和超时配置 - 添加 lua_config_test.go 测试配置验证逻辑 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bfab449241
commit
1e545717fb
@ -281,6 +281,10 @@ type ServerConfig struct {
|
||||
// CacheAPI 缓存 API 配置
|
||||
// 用于主动清理代理缓存
|
||||
CacheAPI *CacheAPIConfig `yaml:"cache_api"`
|
||||
|
||||
// Lua Lua 中间件配置
|
||||
// 用于嵌入 Lua 脚本处理请求
|
||||
Lua *LuaMiddlewareConfig `yaml:"lua"`
|
||||
}
|
||||
|
||||
// StaticConfig 静态文件服务配置。
|
||||
@ -1525,6 +1529,102 @@ type CacheAPIAuthConfig struct {
|
||||
Token string `yaml:"token"`
|
||||
}
|
||||
|
||||
// LuaMiddlewareConfig Lua 中间件配置(配置文件格式)
|
||||
//
|
||||
// 用于配置 Lua 中间件的行为,包括脚本路径、执行阶段和全局设置。
|
||||
//
|
||||
// 注意事项:
|
||||
// - Enabled 为 true 时启用 Lua 中间件
|
||||
// - Scripts 配置要执行的脚本列表
|
||||
// - GlobalSettings 控制 Lua 引擎的全局行为
|
||||
//
|
||||
// 使用示例:
|
||||
//
|
||||
// lua:
|
||||
// enabled: true
|
||||
// scripts:
|
||||
// - path: "/scripts/auth.lua"
|
||||
// phase: "access"
|
||||
// timeout: 10s
|
||||
// global_settings:
|
||||
// max_concurrent_coroutines: 1000
|
||||
// coroutine_timeout: 30s
|
||||
type LuaMiddlewareConfig struct {
|
||||
// Enabled 是否启用 Lua 中间件
|
||||
Enabled bool `yaml:"enabled"`
|
||||
|
||||
// Scripts 脚本配置列表
|
||||
Scripts []LuaScriptConfig `yaml:"scripts"`
|
||||
|
||||
// GlobalSettings 全局设置
|
||||
GlobalSettings LuaGlobalSettings `yaml:"global_settings"`
|
||||
}
|
||||
|
||||
// LuaScriptConfig 单个脚本配置
|
||||
//
|
||||
// 定义单个 Lua 脚本的执行参数。
|
||||
//
|
||||
// 注意事项:
|
||||
// - Path 为脚本文件路径,必需字段
|
||||
// - Phase 为执行阶段,必需字段
|
||||
// - Timeout 控制脚本执行超时
|
||||
//
|
||||
// 使用示例:
|
||||
//
|
||||
// scripts:
|
||||
// - path: "/scripts/auth.lua"
|
||||
// phase: "access"
|
||||
// timeout: 10s
|
||||
// enabled: true
|
||||
type LuaScriptConfig struct {
|
||||
// Path 脚本路径
|
||||
Path string `yaml:"path"`
|
||||
|
||||
// Phase 执行阶段
|
||||
// 可选值:rewrite、access、content、log、header_filter、body_filter
|
||||
Phase string `yaml:"phase"`
|
||||
|
||||
// Timeout 执行超时
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
|
||||
// Enabled 是否启用此脚本(默认 true)
|
||||
Enabled bool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
// LuaGlobalSettings 全局 Lua 设置
|
||||
//
|
||||
// 控制 Lua 引擎的全局行为。
|
||||
//
|
||||
// 注意事项:
|
||||
// - MaxConcurrentCoroutines 控制最大并发协程数
|
||||
// - CoroutineTimeout 控制协程执行超时
|
||||
// - CodeCacheSize 控制字节码缓存大小
|
||||
//
|
||||
// 使用示例:
|
||||
//
|
||||
// global_settings:
|
||||
// max_concurrent_coroutines: 1000
|
||||
// coroutine_timeout: 30s
|
||||
// code_cache_size: 1000
|
||||
// enable_file_watch: true
|
||||
// max_execution_time: 30s
|
||||
type LuaGlobalSettings struct {
|
||||
// MaxConcurrentCoroutines 最大并发协程数
|
||||
MaxConcurrentCoroutines int `yaml:"max_concurrent_coroutines"`
|
||||
|
||||
// CoroutineTimeout 协程执行超时
|
||||
CoroutineTimeout time.Duration `yaml:"coroutine_timeout"`
|
||||
|
||||
// CodeCacheSize 字节码缓存条目数
|
||||
CodeCacheSize int `yaml:"code_cache_size"`
|
||||
|
||||
// EnableFileWatch 启用文件变更检测
|
||||
EnableFileWatch bool `yaml:"enable_file_watch"`
|
||||
|
||||
// MaxExecutionTime 单脚本最大执行时间
|
||||
MaxExecutionTime time.Duration `yaml:"max_execution_time"`
|
||||
}
|
||||
|
||||
// StreamConfig TCP/UDP Stream 代理配置。
|
||||
//
|
||||
// 用于四层网络代理,如数据库、Redis 等 TCP/UDP 服务。
|
||||
|
||||
156
internal/config/lua_config_test.go
Normal file
156
internal/config/lua_config_test.go
Normal file
@ -0,0 +1,156 @@
|
||||
// Package config 提供 Lua 配置测试
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestLuaMiddlewareConfigValidation 测试 Lua 配置验证
|
||||
func TestLuaMiddlewareConfigValidation(t *testing.T) {
|
||||
// 未配置时跳过验证
|
||||
cfg := &LuaMiddlewareConfig{}
|
||||
require.NoError(t, validateLua(cfg))
|
||||
|
||||
// 禁用时跳过验证
|
||||
cfg = &LuaMiddlewareConfig{Enabled: false}
|
||||
require.NoError(t, validateLua(cfg))
|
||||
|
||||
// 启用但无脚本也允许
|
||||
cfg = &LuaMiddlewareConfig{Enabled: true}
|
||||
require.NoError(t, validateLua(cfg))
|
||||
|
||||
// 有效配置
|
||||
cfg = &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "/scripts/test.lua", Phase: "rewrite", Timeout: 10 * time.Second},
|
||||
},
|
||||
GlobalSettings: LuaGlobalSettings{
|
||||
MaxConcurrentCoroutines: 1000,
|
||||
CoroutineTimeout: 30 * time.Second,
|
||||
CodeCacheSize: 100,
|
||||
EnableFileWatch: true,
|
||||
MaxExecutionTime: 30 * time.Second,
|
||||
},
|
||||
}
|
||||
require.NoError(t, validateLua(cfg))
|
||||
}
|
||||
|
||||
// TestLuaMiddlewareConfigInvalidPhase 测试无效阶段
|
||||
func TestLuaMiddlewareConfigInvalidPhase(t *testing.T) {
|
||||
cfg := &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "/scripts/test.lua", Phase: "invalid_phase"},
|
||||
},
|
||||
}
|
||||
|
||||
err := validateLua(cfg)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scripts[0].phase 无效")
|
||||
}
|
||||
|
||||
// TestLuaMiddlewareConfigMissingPath 测试缺少路径
|
||||
func TestLuaMiddlewareConfigMissingPath(t *testing.T) {
|
||||
cfg := &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Phase: "rewrite"},
|
||||
},
|
||||
}
|
||||
|
||||
err := validateLua(cfg)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "scripts[0].path 必填")
|
||||
}
|
||||
|
||||
// TestLuaMiddlewareConfigNegativeTimeout 测试负超时
|
||||
func TestLuaMiddlewareConfigNegativeTimeout(t *testing.T) {
|
||||
cfg := &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "/scripts/test.lua", Phase: "rewrite", Timeout: -5 * time.Second},
|
||||
},
|
||||
}
|
||||
|
||||
err := validateLua(cfg)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "timeout 不能为负数")
|
||||
}
|
||||
|
||||
// TestLuaMiddlewareConfigGlobalSettingsValidation 测试全局设置验证
|
||||
func TestLuaMiddlewareConfigGlobalSettingsValidation(t *testing.T) {
|
||||
// MaxConcurrentCoroutines 为负
|
||||
cfg := &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
GlobalSettings: LuaGlobalSettings{
|
||||
MaxConcurrentCoroutines: -1,
|
||||
},
|
||||
}
|
||||
err := validateLua(cfg)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "max_concurrent_coroutines 不能为负数")
|
||||
|
||||
// CoroutineTimeout 为负
|
||||
cfg = &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
GlobalSettings: LuaGlobalSettings{
|
||||
CoroutineTimeout: -1 * time.Second,
|
||||
},
|
||||
}
|
||||
err = validateLua(cfg)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "coroutine_timeout 不能为负数")
|
||||
}
|
||||
|
||||
// TestServerConfigLuaField 测试 ServerConfig 包含 Lua 字段
|
||||
func TestServerConfigLuaField(t *testing.T) {
|
||||
cfg := &ServerConfig{
|
||||
Listen: ":8080",
|
||||
Lua: &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "/scripts/auth.lua", Phase: "access"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
require.NotNil(t, cfg.Lua)
|
||||
assert.True(t, cfg.Lua.Enabled)
|
||||
assert.Len(t, cfg.Lua.Scripts, 1)
|
||||
assert.Equal(t, "/scripts/auth.lua", cfg.Lua.Scripts[0].Path)
|
||||
assert.Equal(t, "access", cfg.Lua.Scripts[0].Phase)
|
||||
}
|
||||
|
||||
// TestValidateServerWithLuaConfig 测试服务器验证包含 Lua
|
||||
func TestValidateServerWithLuaConfig(t *testing.T) {
|
||||
// 有效 Lua 配置
|
||||
cfg := &ServerConfig{
|
||||
Listen: ":8080",
|
||||
Lua: &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "/scripts/test.lua", Phase: "content"},
|
||||
},
|
||||
},
|
||||
}
|
||||
require.NoError(t, validateServer(cfg, false))
|
||||
|
||||
// 无效 Lua 配置
|
||||
cfg = &ServerConfig{
|
||||
Listen: ":8080",
|
||||
Lua: &LuaMiddlewareConfig{
|
||||
Enabled: true,
|
||||
Scripts: []LuaScriptConfig{
|
||||
{Path: "", Phase: "content"}, // 空路径
|
||||
},
|
||||
},
|
||||
}
|
||||
err := validateServer(cfg, false)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "lua:")
|
||||
}
|
||||
@ -94,6 +94,11 @@ func validateServer(s *ServerConfig, isDefault bool) error {
|
||||
return fmt.Errorf("compression: %w", err)
|
||||
}
|
||||
|
||||
// 验证 Lua 中间件配置
|
||||
if err := validateLua(s.Lua); err != nil {
|
||||
return fmt.Errorf("lua: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1025,3 +1030,68 @@ func validateVariables(v *VariablesConfig) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateLua 验证 Lua 中间件配置。
|
||||
//
|
||||
// 检查 Lua 脚本配置的有效性,包括脚本路径、执行阶段和全局设置。
|
||||
//
|
||||
// 参数:
|
||||
// - l: Lua 配置对象
|
||||
//
|
||||
// 返回值:
|
||||
// - error: 验证失败时返回错误信息,成功返回 nil
|
||||
//
|
||||
// 验证规则:
|
||||
// - scripts[].path 必填
|
||||
// - scripts[].phase 必须是有效阶段
|
||||
// - global_settings.max_concurrent_coroutines 必须 >= 1
|
||||
func validateLua(l *LuaMiddlewareConfig) error {
|
||||
// 未配置时跳过
|
||||
if l == nil || !l.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 验证脚本配置
|
||||
for i, script := range l.Scripts {
|
||||
if script.Path == "" {
|
||||
return fmt.Errorf("scripts[%d].path 必填", i)
|
||||
}
|
||||
|
||||
// 验证阶段值
|
||||
validPhases := []string{"rewrite", "access", "content", "log", "header_filter", "body_filter"}
|
||||
valid := false
|
||||
for _, phase := range validPhases {
|
||||
if script.Phase == phase {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
return fmt.Errorf("scripts[%d].phase 无效: %s(仅支持 rewrite, access, content, log, header_filter, body_filter)", i, script.Phase)
|
||||
}
|
||||
|
||||
// 超时时间验证
|
||||
if script.Timeout < 0 {
|
||||
return fmt.Errorf("scripts[%d].timeout 不能为负数", i)
|
||||
}
|
||||
}
|
||||
|
||||
// 验证全局设置
|
||||
if l.GlobalSettings.MaxConcurrentCoroutines < 0 {
|
||||
return errors.New("global_settings.max_concurrent_coroutines 不能为负数")
|
||||
}
|
||||
if l.GlobalSettings.MaxConcurrentCoroutines > 0 && l.GlobalSettings.MaxConcurrentCoroutines < 1 {
|
||||
return errors.New("global_settings.max_concurrent_coroutines 至少为 1")
|
||||
}
|
||||
if l.GlobalSettings.CoroutineTimeout < 0 {
|
||||
return errors.New("global_settings.coroutine_timeout 不能为负数")
|
||||
}
|
||||
if l.GlobalSettings.CodeCacheSize < 0 {
|
||||
return errors.New("global_settings.code_cache_size 不能为负数")
|
||||
}
|
||||
if l.GlobalSettings.MaxExecutionTime < 0 {
|
||||
return errors.New("global_settings.max_execution_time 不能为负数")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user