From a761611ad0895eac2ea537b6f90a0ac4d7ac3d3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 06:17:14 +0000 Subject: [PATCH 1/4] Initial plan From 4c36af011424999add1718696e309970e89991f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 06:22:14 +0000 Subject: [PATCH 2/4] Add debug/administration website with Lua terminal and log viewer - web/nginx.conf: OpenResty config with API endpoints for Lua code execution, log retrieval, log clearing, and server info - web/index.html: Single-page debug console UI with Lua terminal (code editor + output) and server log viewer with auto-refresh Co-authored-by: paintdream <7030141+paintdream@users.noreply.github.com> Agent-Logs-Url: https://github.com/paintdream/ngx_lua_cpp/sessions/f44b2ed1-ba42-480f-9e4a-7035bf3c50ab --- web/index.html | 674 +++++++++++++++++++++++++++++++++++++++++++++++++ web/nginx.conf | 249 ++++++++++++++++++ 2 files changed, 923 insertions(+) create mode 100644 web/index.html create mode 100644 web/nginx.conf diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..b01aecb --- /dev/null +++ b/web/index.html @@ -0,0 +1,674 @@ + + + + + +ngx_lua_cpp Debug Console + + + + + +
+
+ + ngx_lua_cpp Debug Console +
+
+ Connecting... + +
+
+ + +
+ +
+
+

▶ Lua Terminal

+
+ + +
+
+
+ +
+
+ Ctrl+Enter to run · Ctrl+L to clear output · Tab to indent +
+
+
+

Output

+ +
+
+ Output will appear here... +
+
+
+ + +
+
+

📜 Server Logs

+
+ + +
+
+
+ + + + +
+ + +
+
+
+
Loading logs...
+
+
+
+ + + + + diff --git a/web/nginx.conf b/web/nginx.conf new file mode 100644 index 0000000..f21a54d --- /dev/null +++ b/web/nginx.conf @@ -0,0 +1,249 @@ +# ngx_lua_cpp Debug/Administration Server +# OpenResty nginx configuration +# +# Usage: +# 1. Adjust the paths below to match your environment: +# - Replace [[ngx_lua_cpp source directory]] with the path to this repository +# - Replace [[ngx_lua_cpp binary directory]] with the path to the built library +# 2. Start OpenResty: +# openresty -p `pwd` -c nginx.conf +# 3. Open http://localhost:8080 in your browser + +worker_processes 1; +error_log logs/error.log info; +pid logs/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + access_log logs/access.log; + + sendfile on; + keepalive_timeout 65; + + # Shared dictionary for storing execution history + lua_shared_dict exec_history 1m; + + init_worker_by_lua_block { + -- Adjust these paths to your environment + -- package.path = package.path .. ";[[ngx_lua_cpp source directory]]/demo/?.lua" + -- package.cpath = package.cpath .. ";[[ngx_lua_cpp binary directory]]/?.dll;[[ngx_lua_cpp binary directory]]/lib?.so;" + -- require("init_ngx_lua_cpp") + } + + server { + listen 8080; + server_name localhost; + + # Serve static files (index.html, etc.) + location / { + root html; + index index.html; + } + + # API: Execute Lua code + location /api/exec { + default_type application/json; + + content_by_lua_block { + ngx.req.read_body() + local body = ngx.req.get_body_data() + if not body then + ngx.status = 400 + ngx.say('{"ok":false,"error":"Empty request body"}') + return + end + + local cjson = require("cjson.safe") + local data = cjson.decode(body) + if not data or not data.code then + ngx.status = 400 + ngx.say('{"ok":false,"error":"Invalid JSON or missing \\"code\\" field"}') + return + end + + local code = data.code + + -- Capture output by overriding ngx.say/ngx.print within the chunk + local output_parts = {} + local env = setmetatable({ + print = function(...) + local args = {...} + local parts = {} + for i = 1, select("#", ...) do + parts[#parts + 1] = tostring(args[i]) + end + output_parts[#output_parts + 1] = table.concat(parts, "\t") + end, + ngx = ngx, + require = require, + tostring = tostring, + tonumber = tonumber, + type = type, + pairs = pairs, + ipairs = ipairs, + pcall = pcall, + xpcall = xpcall, + error = error, + assert = assert, + select = select, + unpack = unpack, + table = table, + string = string, + math = math, + os = os, + io = io, + coroutine = coroutine, + collectgarbage = collectgarbage, + rawget = rawget, + rawset = rawset, + setmetatable = setmetatable, + getmetatable = getmetatable, + }, {__index = _G}) + + local fn, err = loadstring(code) + if not fn then + ngx.say(cjson.encode({ok = false, error = "Compile error: " .. err})) + return + end + + setfenv(fn, env) + + local ok, result = pcall(fn) + local output = table.concat(output_parts, "\n") + + if ok then + local res = {ok = true, output = output} + if result ~= nil then + res.result = tostring(result) + end + ngx.say(cjson.encode(res)) + else + ngx.say(cjson.encode({ok = false, error = tostring(result), output = output})) + end + } + } + + # API: Retrieve server logs + location /api/logs { + default_type application/json; + + content_by_lua_block { + local cjson = require("cjson.safe") + local args = ngx.req.get_uri_args() + local log_type = args.type or "error" + local lines = tonumber(args.lines) or 100 + + local log_file + if log_type == "access" then + log_file = ngx.config.prefix() .. "logs/access.log" + else + log_file = ngx.config.prefix() .. "logs/error.log" + end + + -- Read log file directly (no shell commands) + local f = io.open(log_file, "r") + if not f then + ngx.say(cjson.encode({ok = false, error = "Failed to open log file"})) + return + end + + -- Read all lines and keep only the last N + local all_lines = {} + for line in f:lines() do + all_lines[#all_lines + 1] = line + end + f:close() + + local start = math.max(1, #all_lines - math.min(lines, 10000) + 1) + local tail_lines = {} + for i = start, #all_lines do + tail_lines[#tail_lines + 1] = all_lines[i] + end + local content = table.concat(tail_lines, "\n") + + ngx.say(cjson.encode({ + ok = true, + log_type = log_type, + file = log_file, + content = content + })) + } + } + + # API: Clear logs + location /api/logs/clear { + default_type application/json; + + content_by_lua_block { + local cjson = require("cjson.safe") + local args = ngx.req.get_uri_args() + local log_type = args.type or "error" + + local log_file + if log_type == "access" then + log_file = ngx.config.prefix() .. "logs/access.log" + else + log_file = ngx.config.prefix() .. "logs/error.log" + end + + local ok, err = pcall(function() + local f = io.open(log_file, "w") + if f then + f:close() + end + -- Signal nginx to reopen log files + local pid_file = ngx.config.prefix() .. "logs/nginx.pid" + local pf = io.open(pid_file, "r") + if pf then + local pid = pf:read("*l") + pf:close() + if pid then + os.execute("kill -USR1 " .. tonumber(pid)) + end + end + end) + + if ok then + ngx.say(cjson.encode({ok = true, message = log_type .. " log cleared"})) + else + ngx.say(cjson.encode({ok = false, error = tostring(err)})) + end + } + } + + # API: Server info + location /api/info { + default_type application/json; + + content_by_lua_block { + local cjson = require("cjson.safe") + + local info = { + ok = true, + ngx_lua_version = ngx.config.ngx_lua_version, + nginx_version = ngx.config.nginx_version, + worker_pid = ngx.worker.pid(), + worker_count = ngx.worker.count(), + prefix = ngx.config.prefix(), + } + + -- Try to load ngx_lua_cpp info + local inst_ok, inst = pcall(require, "init_ngx_lua_cpp") + if inst_ok and inst then + info.ngx_lua_cpp = true + info.ngx_lua_cpp_running = inst:is_running() + else + info.ngx_lua_cpp = false + end + + ngx.say(cjson.encode(info)) + } + } + } +} From aecb33340240f607c65434fd36bd07c4090fa212 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 05:51:46 +0000 Subject: [PATCH 3/4] Initial plan From 90fba81ef68a102d9b1547b599d5522ca626268c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 05:58:07 +0000 Subject: [PATCH 4/4] Add doc/design.md: comprehensive design document for ngx_lua_cpp Co-authored-by: paintdream <7030141+paintdream@users.noreply.github.com> Agent-Logs-Url: https://github.com/paintdream/ngx_lua_cpp/sessions/60dd2890-9b07-4c4a-a307-1ed8baef7e37 --- doc/design.md | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 doc/design.md diff --git a/doc/design.md b/doc/design.md new file mode 100644 index 0000000..3ad4c57 --- /dev/null +++ b/doc/design.md @@ -0,0 +1,291 @@ +# ngx_lua_cpp Design Document + +## 1. Overview + +**ngx_lua_cpp** is a C++ extension framework for OpenResty/Nginx that lets developers write high-performance C++ logic — including C++20 coroutines — and expose it to Lua scripts running inside OpenResty's `ngx_lua` module. It is built on the [iris](https://github.com/paintdream/iris) header-only concurrency library and is distributed under the MIT License. + +### Goals + +- Enable C++ extensions for OpenResty without requiring any nginx or OpenResty header files at build time. +- Provide seamless Lua ↔ C++ type conversion and function binding via iris. +- Support C++20 coroutines that integrate transparently with OpenResty's Lua coroutine scheduler. +- Operate as a self-contained shared library (`.so` / `.dll`) loaded at runtime through LuaJIT's `require`. + +## 2. Repository Structure + +``` +ngx_lua_cpp/ +├── CMakeLists.txt # Build configuration (CMake, C++20) +├── LICENSE # MIT License +├── README.md # User-facing documentation +├── cmake/ +│ └── FindLuaJIT.cmake # CMake module to locate LuaJIT +├── demo/ +│ └── init_ngx_lua_cpp.lua # Lua bootstrap script for nginx workers +├── doc/ +│ └── design.md # This document +├── src/ +│ ├── ngx_lua_cpp.h # Public header — exported types and macros +│ ├── ngx_lua_cpp.cpp # Core implementation +│ └── iris/ # iris library (header-only, vendored) +│ ├── iris_common.h # Common utilities, allocators, helpers +│ ├── iris_common.inl # Inline implementations for iris_common.h +│ ├── iris_lua.h # Lua binding framework (iris_lua_t) +│ ├── iris_dispatcher.h # Thread pool and warp/strand abstractions +│ └── iris_coroutine.h # C++20 coroutine integration +└── web/ + ├── nginx.conf # Example nginx configuration with debug APIs + └── index.html # Browser-based debug console UI +``` + +## 3. Architecture + +The diagram below shows how the main components interact at runtime inside an OpenResty worker process: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ OpenResty Worker Process │ +│ │ +│ ┌──────────────┐ require("ngx_lua_cpp") ┌──────────────┐ │ +│ │ ngx_lua / │ ──────────────────────────► │ libngx_lua_ │ │ +│ │ LuaJIT VM │ ◄────────────────────────── │ cpp.so │ │ +│ │ │ Lua ↔ C++ calls │ │ │ +│ └──────┬───────┘ └──────┬───────┘ │ +│ │ │ │ +│ │ ngx.sleep / yield / resume │ │ +│ ▼ ▼ │ +│ ┌──────────────┐ hook process_events() ┌──────────────┐ │ +│ │ nginx event │ ◄─────────────────────────│ ngx_hooker_t │ │ +│ │ loop │ ─────────────────────────►│ (singleton) │ │ +│ └──────────────┘ notify() └──────┬───────┘ │ +│ │ │ +│ ┌───────▼──────┐ │ +│ │ ngx_lua_ │ │ +│ │ cpp_t │ │ +│ │ ┌──────────┐ │ │ +│ │ │async_ │ │ │ +│ │ │worker │ │ │ +│ │ │(thread │ │ │ +│ │ │pool) │ │ │ +│ │ └──────────┘ │ │ +│ │ ┌──────────┐ │ │ +│ │ │main_warp │ │ │ +│ │ │(strand) │ │ │ +│ │ └──────────┘ │ │ +│ └──────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Runtime Flow + +1. **Loading** — The nginx `init_worker_by_lua_block` directive executes `require("ngx_lua_cpp")`, which calls `luaopen_ngx_lua_cpp`. This registers the `ngx_lua_cpp_t` type with iris_lua and constructs the global `ngx_hooker_t` singleton. +2. **Initialization** — Lua code calls `lib.new()` to create an `ngx_lua_cpp_t` instance and `inst:start(N)` to spin up N worker threads. +3. **Request handling** — Inside `content_by_lua_block`, Lua calls C++ methods (e.g., `inst:sleep(40)`). If the method is a coroutine, the framework yields the current ngx_lua coroutine, dispatches work to the thread pool, and resumes the coroutine with the result once complete. +4. **Event loop integration** — `ngx_hooker_t` hooks `ngx_event_actions.process_events` so that every event-loop iteration drains completed async tasks back to the main thread via `main_warp->poll()`. + +## 4. Key Components + +### 4.1 `ngx_lua_cpp_t` (src/ngx_lua_cpp.h, src/ngx_lua_cpp.cpp) + +The primary class exposed to Lua. Each instance owns: + +| Member | Type | Purpose | +|---|---|---| +| `async_worker` | `shared_ptr>` | Thread pool for background work | +| `main_warp` | `unique_ptr` | Strand that serializes work back to the nginx main thread | +| `main_warp_guard` | `unique_ptr` | Keeps `main_warp` in the preempted (accepting tasks) state | +| `main_thread_index` | `size_t` | Index of the pseudo-thread representing the nginx main thread in the async worker | + +**Lua API** (registered in `lua_registar`): + +| Lua method | C++ method | Description | +|---|---|---| +| `lib.new()` | `place_new_object` | Creates a new `ngx_lua_cpp_t` instance | +| `inst:start(n)` | `start(size_t)` | Starts the thread pool with `n` worker threads | +| `inst:stop()` | `stop()` | Stops the thread pool and drains pending tasks | +| `inst:is_running()` | `is_running()` | Returns `true` if the thread pool is active | +| `inst:get_hardware_concurrency()` | `get_hardware_concurrency()` | Returns `std::thread::hardware_concurrency()` | +| `inst:sleep(ms)` | `sleep(size_t)` | Example coroutine: sleeps on a worker thread, returns the value | +| `inst:__async_worker__(ptr)` | `__async_worker__(void*)` | Introspection: get/set the internal async worker (for advanced use) | + +### 4.2 `ngx_hooker_t` (src/ngx_lua_cpp.cpp) + +A process-wide singleton (`get_instance()`) responsible for integrating with the nginx event loop. It is constructed on first access (typically when `luaopen_ngx_lua_cpp` is called). + +**Initialization steps:** + +1. Opens the host process handle (`dlopen(NULL)` / `GetModuleHandle(NULL)`). +2. Resolves nginx and ngx_lua symbols by name using `dlsym` / `GetProcAddress`: + - `ngx_event_actions` — the global event actions table + - `ngx_posted_delayed_events` — the delayed events queue + - `ngx_http_lua_module` / `ngx_stream_lua_module` — module descriptors + - `ngx_http_lua_get_co_ctx` / `ngx_stream_lua_get_co_ctx` — coroutine context accessors +3. Replaces `ngx_event_actions.process_events` with its own `proxy_ngx_process_events`, saving the original pointer. + +**Event loop hook** (`process_events`): + +On each nginx event loop iteration: +1. Removes any placeholder sleep events that were inserted by `ngx_lua_cpp_yield` (to trick ngx_lua into yielding). +2. Calls `process_events()` on every registered `ngx_lua_cpp_t` instance, which polls the main warp for completed tasks. +3. Calls the original `process_events` to perform normal nginx event processing. + +**Yield/Resume mechanism:** + +- **`ngx_lua_cpp_yield`** — Called when a C++ coroutine needs the Lua side to yield. It invokes `ngx.sleep(0)` internally to put the Lua coroutine into a sleeping state, making it compatible with ngx_lua's scheduler. +- **`ngx_lua_cpp_resume`** — Called when a C++ coroutine completes. It inserts the coroutine context into `ngx_posted_delayed_events` so nginx will wake and resume the Lua coroutine on the next event loop iteration. Return values are stored in the Lua registry keyed by the `lua_State*` pointer. + +**Auto-discovery of `co_ctx` event queue offset:** + +The offset of the `sleep.event_queue` field within `ngx_http_lua_co_ctx_t` (and the stream equivalent) is not known at compile time. The hooker discovers it at runtime by: +1. Calling `ngx.sleep(0)` once on the real yield function. +2. Observing which entry appears at the tail of `ngx_posted_delayed_events`. +3. Computing the byte offset from the `co_ctx` pointer to that queue entry. + +This approach avoids any dependency on nginx internal header files. + +### 4.3 `ngx_warp_t` (src/ngx_lua_cpp.h) + +A specialization of `iris_warp_t` configured for the nginx environment: + +```cpp +struct ngx_warp_t : iris_warp_t, false, ngx_warp_t> { ... }; +``` + +- The `strand = false` template parameter means it operates in warp (non-strand) mode — routines are dispatched but not strictly serialized. +- `flush_warp()` calls `ngx_hooker_t::notify()`, which triggers `ngx_event_actions.notify()` to wake the nginx event loop so it will process the newly queued tasks promptly. +- The enter/leave/suspend/resume warp hooks are no-ops because the nginx main thread context does not need additional locking. + +### 4.4 Coroutine Return Value Wrapping (src/ngx_lua_cpp.h) + +For C++ coroutines that return a value (i.e., `iris_coroutine_t` where `T` is non-void), the framework wraps the Lua-side coroutine function so that: + +1. When the C++ coroutine yields, the Lua coroutine also yields (via the ngx.sleep trick). +2. When the C++ coroutine completes with a return value, the value is stored in the Lua registry. +3. When the Lua coroutine is resumed, a wrapper function (`get_coroutine_returns`) retrieves the stored values from the registry and returns them as Lua return values. + +This is implemented through the `iris_lua_traits_t` specialization for coroutine function pointers and the `ngx_iris_wrap_coroutine_with_returns_key` registry entry. + +### 4.5 iris Library (src/iris/) + +The [iris](https://github.com/paintdream/iris) library is a header-only C++ concurrency framework providing: + +| Header | Purpose | +|---|---| +| `iris_common.h` / `.inl` | Utilities: block allocators, binary search helpers, atomic guards, debug macros | +| `iris_lua.h` | Full-featured Lua binding: automatic type marshalling, metatables, ref counting, coroutine integration, error handling | +| `iris_dispatcher.h` | `iris_async_worker_t` (thread pool) and `iris_warp_t` (strand/warp task serialization) | +| `iris_coroutine.h` | `iris_coroutine_t` — C++20 coroutine wrapper with `co_await` support for warp switching (`iris_switch`) | + +## 5. Nginx Integration Details + +### 5.1 No Header Dependency + +ngx_lua_cpp deliberately avoids including any nginx or OpenResty headers. Instead, `ngx_lua_cpp.cpp` contains minimal forward declarations of the nginx structures it needs: + +- `ngx_http_request_t` (first three fields only: `signature`, `connection`, `ctx`) +- `ngx_stream_session_t` (enough fields to reach `ctx`) +- `ngx_stream_lua_request_t` (first two fields: `connection`, `session`) +- `ngx_module_t` (first field: `ctx_index`) +- `ngx_event_actions_t` (full function pointer table) +- `ngx_queue_t` (doubly-linked list node) + +If a custom nginx build changes the layout of these structures, the forward declarations can be updated without pulling in the full nginx source tree. + +### 5.2 Symbol Resolution + +All nginx/ngx_lua symbols are resolved at runtime via `dlsym` (Linux) or `GetProcAddress` (Windows). This means: + +- The shared library has no link-time dependency on nginx. +- It works with any nginx binary that exports the required symbols. +- The library can detect HTTP vs. stream context at runtime by checking `ngx.config.subsystem`. + +### 5.3 HTTP and Stream Support + +The framework supports both `ngx_http_lua` and `ngx_stream_lua` subsystems. At registration time (`ngx_hooker_t::registar`), it queries `ngx.config.subsystem` and stores a boolean flag in the Lua registry. This flag is checked on every yield/resume to determine which set of context accessors and yield functions to use. + +## 6. Threading Model + +``` + ┌──────────────────────────┐ + │ nginx main thread │ + │ │ + │ ┌─────────────────────┐ │ + │ │ main_warp (strand) │ │ + │ │ polled each event │ │ + │ │ loop iteration │ │ + │ └─────────────────────┘ │ + └────────────┬───────────────┘ + │ + ┌────────────┼───────────────┐ + │ │ │ + ┌─────▼────┐ ┌────▼─────┐ ┌──────▼───┐ + │ worker 0 │ │ worker 1 │ │ worker N │ + │ (thread) │ │ (thread) │ │ (thread) │ + └───────────┘ └──────────┘ └──────────┘ +``` + +- **Main thread** — The nginx event loop thread. `main_warp` queues are polled here during `process_events`. All Lua interactions happen on this thread. +- **Worker threads** — Managed by `iris_async_worker_t`. C++ coroutines use `co_await iris_switch(nullptr)` to move execution off the main thread, perform blocking work, then `co_await iris_switch(current)` to return results to the main warp. +- **Priority tasks** — Tasks marked as priority are redirected to `main_warp` via the `set_priority_task_handler` callback, ensuring they execute on the main thread. + +## 7. Build System + +The project uses **CMake** (minimum version 3.12) with C++20 enabled: + +``` +cmake -B build . +cmake --build build +``` + +**Key build details:** + +- **Output**: Shared library (`libngx_lua_cpp.so` on Linux, `ngx_lua_cpp.dll` on Windows). +- **Lua dependency**: LuaJIT by default; can switch to Lua 5.1–5.4 via the `USE_LUA_VERSION` cache variable. +- **LuaJIT discovery**: Uses `cmake/FindLuaJIT.cmake`. Set the `LUA_DIR` environment variable if LuaJIT is not found automatically (typically points to OpenResty's installation directory). +- **Platform support**: Linux (GCC 11+, Clang 14+), Windows (Visual Studio 2019+). Non-MSVC builds add `-fPIC`. +- **Link dependencies** (non-MSVC): `m`, `dl`, `stdc++`, `pthread`, and the Lua library. + +## 8. Demo and Debug Console + +### 8.1 Lua Bootstrap (`demo/init_ngx_lua_cpp.lua`) + +A minimal Lua module loaded once per worker via `init_worker_by_lua_block`. It creates a singleton `ngx_lua_cpp_t` instance and starts 4 worker threads: + +```lua +local lib = require("ngx_lua_cpp") +local inst = lib.new() +inst:start(4) +return inst +``` + +Subsequent `require("init_ngx_lua_cpp")` calls in request handlers return the cached instance. + +### 8.2 Web Debug Console (`web/`) + +> **Security Warning:** The debug console exposes an endpoint that executes arbitrary Lua code on the server. It must **never** be deployed in production. Restrict access via firewall rules, bind to `localhost` only, and enable authentication if used in any shared environment. + +A self-contained debug interface consisting of: + +- **`nginx.conf`** — Configures an HTTP server on port 8080 with API endpoints: + - `POST /api/exec` — Execute arbitrary Lua code in a sandboxed environment + - `GET /api/logs` — Retrieve nginx error/access log tails + - `POST /api/logs/clear` — Truncate log files + - `GET /api/info` — Server status and ngx_lua_cpp state +- **`index.html`** — A single-page application providing a Lua terminal and log viewer with syntax highlighting and keyboard shortcuts. + +## 9. Extending ngx_lua_cpp + +To add a new C++ function accessible from Lua: + +1. **Declare** the method in `ngx_lua_cpp_t` (in `ngx_lua_cpp.h`). +2. **Implement** it in `ngx_lua_cpp.cpp`. For async operations, return `iris_coroutine_t` and use `co_await iris_switch` to move between warps. +3. **Register** it in `ngx_lua_cpp_t::lua_registar`: + ```cpp + lua.set_current<&ngx_lua_cpp_t::my_function>("my_function"); + ``` +4. **Call** from Lua: + ```lua + local result = inst:my_function(args) + ``` + +The iris_lua binding system handles automatic type marshalling between Lua and C++, including support for integers, floats, strings, booleans, tables, and userdata.