lolly/internal/lua/middleware_config.go
xfy ad177e9640 docs(lua): 为 Lua API 模块添加标准化 godoc 注释
为所有 Lua API 文件添加完整的包级和函数级文档注释:
- api_balancer: 负载均衡 API(set_current_peer, set_more_tries 等)
- api_ctx: 请求上下文存储 API(ngx.ctx)
- api_location: 子请求捕获 API(ngx.location.capture)
- api_log: 日志输出 API(ngx.log)
- api_req: 请求对象 API
- api_resp: 响应对象 API
- api_shared_dict: 共享字典 API
- api_socket_tcp: TCP socket API
- api_timer: 定时器 API
- api_var: 变量 API
- engine: Lua 引擎核心
- context: 请求上下文管理
- coroutine: 协程调度器
- middleware: 中间件集成
- filter_writer: 响应过滤器
- cache: Lua 脚本缓存
- shared_dict: 共享字典实现
- socket_manager: socket 连接管理

注释格式遵循 Go 官方风格,包含功能说明、参数说明和注意事项。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 10:59:17 +08:00

199 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package lua 提供 Lua 中间件配置解析与验证。
//
// 该文件定义从配置文件YAML加载的中间件配置结构包括
// - MiddlewareConfig完整的中间件配置含脚本列表、全局设置、启用标记
// - ScriptConfig单个脚本的配置路径、阶段、超时、启用标记
// - GlobalLuaSettings全局 Lua 引擎设置(并发、缓存、栈大小等)
// - ParsePhase字符串到 Phase 常量的转换
// - ToEngineConfig将配置文件的设置转换为引擎配置
//
// 注意事项:
// - Phase 值必须为rewrite、access、content、log、header_filter、body_filter
// - 超时时间至少为 1 秒
// - 最大并发协程数至少为 1
//
// 作者xfy
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
}