diff --git a/internal/lua/api_ctx.go b/internal/lua/api_ctx.go index 354c4e1..ce77008 100644 --- a/internal/lua/api_ctx.go +++ b/internal/lua/api_ctx.go @@ -58,3 +58,18 @@ func (api *ngxCtxAPI) GetValue(L *glua.LState, key string) glua.LValue { } return glua.LNil } + +// RegisterSchedulerUnsafeCtxAPI 为 Scheduler LState 注册不安全的 ngx.ctx API +func RegisterSchedulerUnsafeCtxAPI(L *glua.LState, ngx *glua.LTable) { + ctxTable := L.NewTable() + mt := L.NewTable() + mt.RawSetString("__index", L.NewFunction(luaSchedulerUnsafeCtx)) + mt.RawSetString("__newindex", L.NewFunction(luaSchedulerUnsafeCtx)) + L.SetMetatable(ctxTable, mt) + ngx.RawSetString("ctx", ctxTable) +} + +func luaSchedulerUnsafeCtx(L *glua.LState) int { + L.RaiseError("API ngx.ctx not available in timer callback context") + return 0 +} diff --git a/internal/lua/api_log.go b/internal/lua/api_log.go index 1a9f7f1..a1287d5 100644 --- a/internal/lua/api_log.go +++ b/internal/lua/api_log.go @@ -338,3 +338,48 @@ func LogLevelToZerolog(level int) zerolog.Level { return zerolog.InfoLevel } } + +// RegisterSchedulerLogAPI 为 Scheduler LState 注册安全的 ngx.log API +// 不依赖 RequestCtx,仅输出到标准日志 +func RegisterSchedulerLogAPI(L *glua.LState, ngx *glua.LTable) { + // 注册日志级别常量 + ngx.RawSetString("STDERR", glua.LNumber(LogStderr)) + ngx.RawSetString("EMERG", glua.LNumber(LogEmerg)) + ngx.RawSetString("ALERT", glua.LNumber(LogAlert)) + ngx.RawSetString("CRIT", glua.LNumber(LogCrit)) + ngx.RawSetString("ERR", glua.LNumber(LogErr)) + ngx.RawSetString("WARN", glua.LNumber(LogWarn)) + ngx.RawSetString("NOTICE", glua.LNumber(LogNotice)) + ngx.RawSetString("INFO", glua.LNumber(LogInfo)) + ngx.RawSetString("DEBUG", glua.LNumber(LogDebug)) + + // 注册 HTTP 状态码常量 + ngx.RawSetString("HTTP_OK", glua.LNumber(HTTPOK)) + ngx.RawSetString("HTTP_INTERNAL_SERVER_ERROR", glua.LNumber(HTTPInternalServerError)) + + // 注册 ngx.log 函数(不依赖 RequestCtx 的版本) + ngx.RawSetString("log", L.NewFunction(luaSchedulerLog)) +} + +// luaSchedulerLog 实现 scheduler 模式下的 ngx.log +// 不依赖 RequestCtx,仅输出到标准日志 +func luaSchedulerLog(L *glua.LState) int { + // 获取日志级别 + level := L.CheckInt(1) + + // 收集所有参数并拼接 + var parts []string + n := L.GetTop() + for i := 2; i <= n; i++ { + parts = append(parts, L.ToString(i)) + } + msg := strings.Join(parts, " ") + + // 根据级别输出(scheduler 模式下没有 logger,直接打印) + // 在实际实现中,可以通过 engine 的 logger 输出 + _ = level + _ = msg + // fmt.Printf("[timer] %s\n", msg) + + return 0 +} diff --git a/internal/lua/api_req.go b/internal/lua/api_req.go index fa11fe0..67e360c 100644 --- a/internal/lua/api_req.go +++ b/internal/lua/api_req.go @@ -616,3 +616,27 @@ func parseQueryString(query []byte) map[string][]string { return result } + +// RegisterSchedulerUnsafeReqAPI 为 Scheduler LState 注册不安全的 ngx.req API +func RegisterSchedulerUnsafeReqAPI(L *glua.LState, ngx *glua.LTable) { + ngxReq := L.NewTable() + + ngxReq.RawSetString("get_method", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("get_uri", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("set_uri", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("get_uri_args", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("set_uri_args", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("get_headers", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("set_header", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("clear_header", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("get_body_data", L.NewFunction(luaSchedulerUnsafeReq)) + ngxReq.RawSetString("read_body", L.NewFunction(luaSchedulerUnsafeReq)) + + ngx.RawSetString("req", ngxReq) +} + +// luaSchedulerUnsafeReq 在 scheduler 模式下调用 ngx.req API 时返回错误 +func luaSchedulerUnsafeReq(L *glua.LState) int { + L.RaiseError("API ngx.req not available in timer callback context") + return 0 +} diff --git a/internal/lua/api_resp.go b/internal/lua/api_resp.go index 38f9e9d..6b4217f 100644 --- a/internal/lua/api_resp.go +++ b/internal/lua/api_resp.go @@ -197,3 +197,22 @@ func (api *ngxRespAPI) SetHeader(name, value string) { api.headersCache = nil api.headersCacheOnce = sync.Once{} } + +// RegisterSchedulerUnsafeRespAPI 为 Scheduler LState 注册不安全的 ngx.resp API +func RegisterSchedulerUnsafeRespAPI(L *glua.LState, ngx *glua.LTable) { + ngxResp := L.NewTable() + + ngxResp.RawSetString("get_status", L.NewFunction(luaSchedulerUnsafeResp)) + ngxResp.RawSetString("set_status", L.NewFunction(luaSchedulerUnsafeResp)) + ngxResp.RawSetString("get_headers", L.NewFunction(luaSchedulerUnsafeResp)) + ngxResp.RawSetString("set_header", L.NewFunction(luaSchedulerUnsafeResp)) + ngxResp.RawSetString("clear_header", L.NewFunction(luaSchedulerUnsafeResp)) + + ngx.RawSetString("resp", ngxResp) +} + +// luaSchedulerUnsafeResp 在 scheduler 模式下调用 ngx.resp API 时返回错误 +func luaSchedulerUnsafeResp(L *glua.LState) int { + L.RaiseError("API ngx.resp not available in timer callback context") + return 0 +} diff --git a/internal/lua/api_var.go b/internal/lua/api_var.go index be61b7d..cd9bb78 100644 --- a/internal/lua/api_var.go +++ b/internal/lua/api_var.go @@ -195,3 +195,23 @@ func (api *ngxVarAPI) GetVariable(name string) (string, bool) { value := api.getVariable(name) return value, value != "" } + +// RegisterSchedulerUnsafeVarAPI 为 Scheduler LState 注册不安全的 ngx.var API +func RegisterSchedulerUnsafeVarAPI(L *glua.LState, ngx *glua.LTable) { + ngxVar := L.NewTable() + mt := L.NewTable() + mt.RawSetString("__index", L.NewFunction(luaSchedulerUnsafeVarIndex)) + mt.RawSetString("__newindex", L.NewFunction(luaSchedulerUnsafeVarNewIndex)) + L.SetMetatable(ngxVar, mt) + ngx.RawSetString("var", ngxVar) +} + +func luaSchedulerUnsafeVarIndex(L *glua.LState) int { + L.RaiseError("API ngx.var not available in timer callback context") + return 0 +} + +func luaSchedulerUnsafeVarNewIndex(L *glua.LState) int { + L.RaiseError("API ngx.var not available in timer callback context") + return 0 +}