将 CoroutinePoolWarmup 字段移至 CoroutineStackSize 后, 使协程相关配置字段集中在一起,便于理解和维护。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
185 lines
4.9 KiB
Go
185 lines
4.9 KiB
Go
// Package lua 提供 Lua 中间件配置
|
||
package lua
|
||
|
||
import (
|
||
"fmt"
|
||
"time"
|
||
)
|
||
|
||
// MiddlewareConfig Lua 中间件配置(配置文件格式)
|
||
type MiddlewareConfig struct {
|
||
Scripts []ScriptConfig `yaml:"scripts"`
|
||
GlobalSettings GlobalLuaSettings `yaml:"global_settings"`
|
||
Enabled bool `yaml:"enabled"`
|
||
}
|
||
|
||
// ScriptConfig 单个脚本配置
|
||
type ScriptConfig 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"`
|
||
}
|
||
|
||
// GlobalLuaSettings 全局 Lua 设置
|
||
type GlobalLuaSettings struct {
|
||
// MaxConcurrentCoroutines 最大并发协程数
|
||
MaxConcurrentCoroutines int `yaml:"max_concurrent_coroutines"`
|
||
|
||
// CoroutineTimeout 协程执行超时
|
||
CoroutineTimeout time.Duration `yaml:"coroutine_timeout"`
|
||
|
||
// CodeCacheSize 字节码缓存条目数
|
||
CodeCacheSize int `yaml:"code_cache_size"`
|
||
|
||
// MaxExecutionTime 单脚本最大执行时间
|
||
MaxExecutionTime time.Duration `yaml:"max_execution_time"`
|
||
|
||
// CoroutineStackSize 协程栈大小(默认64,最大256)
|
||
// 较小的栈减少内存分配,适用于简单脚本
|
||
CoroutineStackSize int `yaml:"coroutine_stack_size"`
|
||
|
||
// CoroutinePoolWarmup 协程池预热数量,启动时预创建
|
||
CoroutinePoolWarmup int `yaml:"coroutine_pool_warmup"`
|
||
|
||
// EnableFileWatch 启用文件变更检测
|
||
EnableFileWatch bool `yaml:"enable_file_watch"`
|
||
|
||
// MinimizeStackMemory 启用栈内存自动收缩以减少内存占用
|
||
MinimizeStackMemory bool `yaml:"minimize_stack_memory"`
|
||
}
|
||
|
||
// DefaultMiddlewareConfig 默认 Lua 中间件配置
|
||
func DefaultMiddlewareConfig() *MiddlewareConfig {
|
||
return &MiddlewareConfig{
|
||
Enabled: false,
|
||
Scripts: []ScriptConfig{},
|
||
GlobalSettings: GlobalLuaSettings{
|
||
MaxConcurrentCoroutines: 1000,
|
||
CoroutineTimeout: 30 * time.Second,
|
||
CodeCacheSize: 1000,
|
||
EnableFileWatch: true,
|
||
MaxExecutionTime: 30 * time.Second,
|
||
},
|
||
}
|
||
}
|
||
|
||
// Validate 验证 Lua 中间件配置
|
||
func (c *MiddlewareConfig) Validate() error {
|
||
if !c.Enabled {
|
||
return nil
|
||
}
|
||
|
||
// 验证脚本配置
|
||
for i, script := range c.Scripts {
|
||
if script.Path == "" {
|
||
return fmt.Errorf("scripts[%d].path is required", i)
|
||
}
|
||
|
||
// 验证 Phase 值
|
||
if err := validatePhase(script.Phase); err != nil {
|
||
return fmt.Errorf("scripts[%d]: %w", i, err)
|
||
}
|
||
|
||
// 验证超时时间
|
||
if script.Timeout > 0 && script.Timeout < time.Second {
|
||
return fmt.Errorf("scripts[%d].timeout must be at least 1s", i)
|
||
}
|
||
}
|
||
|
||
// 验证全局设置
|
||
if c.GlobalSettings.MaxConcurrentCoroutines < 1 {
|
||
return fmt.Errorf("global_settings.max_concurrent_coroutines must be at least 1")
|
||
}
|
||
|
||
if c.GlobalSettings.CoroutineTimeout > 0 && c.GlobalSettings.CoroutineTimeout < time.Second {
|
||
return fmt.Errorf("global_settings.coroutine_timeout must be at least 1s")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// validatePhase 验证阶段值
|
||
func validatePhase(phase string) error {
|
||
if phase == "" {
|
||
return fmt.Errorf("phase is required")
|
||
}
|
||
|
||
validPhases := map[string]bool{
|
||
"rewrite": true,
|
||
"access": true,
|
||
"content": true,
|
||
"log": true,
|
||
"header_filter": true,
|
||
"body_filter": true,
|
||
}
|
||
|
||
if !validPhases[phase] {
|
||
return fmt.Errorf("invalid phase '%s', must be one of: rewrite, access, content, log, header_filter, body_filter", phase)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ParsePhase 将字符串转换为 Phase 常量
|
||
func ParsePhase(s string) (Phase, error) {
|
||
switch s {
|
||
case "rewrite":
|
||
return PhaseRewrite, nil
|
||
case "access":
|
||
return PhaseAccess, nil
|
||
case "content":
|
||
return PhaseContent, nil
|
||
case "log":
|
||
return PhaseLog, nil
|
||
case "header_filter":
|
||
return PhaseHeaderFilter, nil
|
||
case "body_filter":
|
||
return PhaseBodyFilter, nil
|
||
default:
|
||
return PhaseInit, fmt.Errorf("unknown phase: %s", s)
|
||
}
|
||
}
|
||
|
||
// ToEngineConfig 将全局设置转换为引擎配置
|
||
func (s *GlobalLuaSettings) ToEngineConfig() *Config {
|
||
cfg := &Config{
|
||
MaxConcurrentCoroutines: s.MaxConcurrentCoroutines,
|
||
CoroutineTimeout: s.CoroutineTimeout,
|
||
CodeCacheSize: s.CodeCacheSize,
|
||
CodeCacheTTL: time.Hour, // 默认值
|
||
EnableFileWatch: s.EnableFileWatch,
|
||
MaxExecutionTime: s.MaxExecutionTime,
|
||
EnableOSLib: false, // 安全默认值
|
||
EnableIOLib: false,
|
||
EnableLoadLib: false,
|
||
}
|
||
|
||
// 设置协程栈优化选项
|
||
if s.CoroutineStackSize > 0 {
|
||
cfg.CoroutineStackSize = s.CoroutineStackSize
|
||
} else {
|
||
cfg.CoroutineStackSize = 64 // 默认优化值
|
||
}
|
||
|
||
// 设置栈内存优化选项
|
||
cfg.MinimizeStackMemory = s.MinimizeStackMemory
|
||
|
||
// 设置协程池预热
|
||
if s.CoroutinePoolWarmup > 0 {
|
||
cfg.CoroutinePoolWarmup = s.CoroutinePoolWarmup
|
||
} else {
|
||
cfg.CoroutinePoolWarmup = 4 // 默认预热数量
|
||
}
|
||
|
||
return cfg
|
||
}
|