// Package lua 提供 Lua 脚本嵌入能力。 // // 该文件包含 Lua 路由处理器的实现,用于将 Lua 脚本作为独立路由处理器执行。 // LuaRouteHandler 实现了 fasthttp.RequestHandler 接口,可以直接注册到路由。 // // 作者:xfy package lua import ( "fmt" "strings" "time" "github.com/valyala/fasthttp" ) // LuaRouteHandler Lua 路由处理器。 // // 将 Lua 脚本作为独立的 HTTP 路由处理器执行,支持: // - 独立的脚本路径和超时配置 // - ngx.say/print 输出缓冲 // - ngx.exit/ngx.redirect 特殊处理 // // 该处理器直接注册到路由系统,不经过中间件链。 type LuaRouteHandler struct { // engine 所属 Lua 引擎 engine *LuaEngine // scriptPath Lua 脚本路径 scriptPath string // timeout 执行超时时间 timeout time.Duration } // NewLuaRouteHandler 创建 Lua 路由处理器。 // // 参数: // - engine: Lua 引擎实例 // - scriptPath: Lua 脚本文件路径 // - timeout: 执行超时时间(0 表示无限制) // // 返回值: // - *LuaRouteHandler: 路由处理器实例 func NewLuaRouteHandler(engine *LuaEngine, scriptPath string, timeout time.Duration) *LuaRouteHandler { return &LuaRouteHandler{ engine: engine, scriptPath: scriptPath, timeout: timeout, } } // ServeHTTP 处理 HTTP 请求。 // // 执行流程: // 1. 创建请求级 LuaContext // 2. 设置 Phase 为 PhaseContent // 3. 初始化协程 // 4. 执行 Lua 脚本 // 5. 处理 ngx.exit/ngx.redirect 特殊退出 // 6. 刷新输出缓冲 // 7. 释放资源 // // 错误处理: // - 协程初始化失败:返回 500 Internal Server Error // - 脚本执行失败(非 ngx.exit):返回 500 Internal Server Error // - ngx.exit/ngx.redirect:正常退出,不视为错误 func (h *LuaRouteHandler) ServeHTTP(ctx *fasthttp.RequestCtx) { luaCtx := NewContext(h.engine, ctx) luaCtx.SetPhase(PhaseContent) if err := luaCtx.InitCoroutine(); err != nil { ctx.Error(fmt.Sprintf("lua coroutine init failed: %v", err), fasthttp.StatusInternalServerError) luaCtx.Release() return } err := luaCtx.ExecuteFile(h.scriptPath) // 检查是否为 ngx.exit 或 ngx.redirect 导致的"错误" // 这些实际上是正常的退出方式,不应视为错误 isNgxExit := err != nil && (strings.Contains(err.Error(), "ngx.exit") || strings.Contains(err.Error(), "ngx.redirect")) if isNgxExit { luaCtx.Exited = true } // 只有真正的错误才返回 500 if err != nil && !isNgxExit && !luaCtx.Exited { ctx.Error(fmt.Sprintf("lua execution failed: %v", err), fasthttp.StatusInternalServerError) } luaCtx.FlushOutput() luaCtx.Release() }