lua-polycall
v1.1.0
Published
Lua binding for the Polycall binding ABI v1 (libpolycall >= 1.1.0): C module for PUC Lua 5.3/5.4 -- config validation, RPC calls and peer nodes
Maintainers
Readme
lua-polycall
Lua binding for the Polycall core's
binding ABI v1 (polycall.h, libpolycall >= 1.1.0): configuration
validation, polycall_rpc calls and peer-to-peer nodes. LuaRocks rock
lua-polycall 1.1.0-1; npm source distribution lua-polycall.
1.1.0 replaces the earlier adapter, which simulated everything (protocol calls always errored,
connectreported success without connecting, "crypto" usedmath.random, and loading required a marker file). Every call now goes to the real core.
Design: a C module for PUC Lua
polycall.core (src/polycall_core.c) is a small C module (lua_CFunctions
over polycall.h) for PUC Lua 5.3 and 5.4, and require("polycall")
(polycall/init.lua) is the Lua API. A C module rather than LuaJIT FFI
because it works with the stock lua5.4/lua5.3 interpreters and LuaRocks'
builtin build, the compiler checks every call against the real header instead
of hand-copied ffi.cdef declarations, and it owns the caller-side buffers,
size_t/uint32_t conversions and error objects. (LuaJIT is not supported by
this build.)
Tested: Linux x86_64 (Debian 13, Lua 5.4.7 and 5.3.6, LuaRocks 3.8.0).
Windows: the module is written to build there (exported luaopen_polycall_core,
the core's polycall.dll / libpolycall.dll) but has not been built or tested
— there is no Lua toolchain on the QA host. macOS: not tested.
Build and install
Requirements: Lua 5.3/5.4 with headers (liblua5.4-dev), LuaRocks, a C
compiler, and the Polycall core >= 1.1.0 installed (<prefix>/include/polycall/polycall.h,
<prefix>/lib/libpolycall.so).
luarocks make lua-polycall-1.1.0-1.rockspec POLYCALL_DIR=/opt/polycall
lua -e 'print(require("polycall").version())'
# or a binary rock for another machine with the same Lua and core
luarocks make --pack-binary-rock lua-polycall-1.1.0-1.rockspec POLYCALL_DIR=/opt/polycall
luarocks install lua-polycall-1.1.0-1.linux-x86_64.rock POLYCALL_DIR=/opt/polycallLuaRocks links -lpolycall with an rpath to $(POLYCALL_LIBDIR). Lua loads C
modules with RTLD_NOW, so a missing core or an old 1.0 core without the ABI
v1 symbols fails require with a clear loader error, and polycall.core
refuses a core whose polycall_ffi_abi_version() is not 1.
API
local polycall = require("polycall")
polycall.abi_version() --> 1
polycall.version() --> "1.1.0"
polycall.run_config("lua-polycallrc") --> 0, or the raw status: polycall_ffi_run_config(path, 1)
polycall.run_config("lua-polycallrc", false) --> run=0: unknown keys are warnings
polycall.run_config_or_error("lua-polycallrc") --> raises polycall.Error
polycall.describe("lua-polycallrc") --> JSON
-- one polycall_rpc round trip to `polycall start` / `polycall daemon start`
polycall.call("127.0.0.1:8084", "inventory", "get", '{"item_id":"widget-a"}', 2000)
local alpha = polycall.open_peer("alpha", "127.0.0.1:0", os.getenv("POLYCALL_DEV_TOKEN"))
alpha:register("beta", "127.0.0.1:9002")
alpha:send("beta", "binary\0safe", "msg-1", 5000) -- exactly one attempt; retry with the same id
local m = alpha:recv(5000) -- {sender=, message_id=, payload=}; "forever" waits
alpha:ping("beta"); alpha:list(); alpha:health(); alpha:endpoint(); alpha:node_id()
alpha:unregister("beta"); alpha:cancel(); alpha:close()
alpha:handle() -- the int32 core handle
polycall.peer_from_handle(h) -- wrap a handle (another lua_State); never closed by GCpolycall.open_peer(id, false) opens a send-only node. Failures raise a
polycall.Error table (polycall.is_error(e)): status (polycall.status.E_*),
name/text (polycall_strerror), detail (polycall_last_error),
operation, plus output (remote error object of a failed call) or
needed (size a too-small recv capacity needed — the message stays queued).
Strings (paths, ids, endpoints, JSON) are passed to the core as the bytes Lua holds, which must be UTF-8 (BINDING_ABI.md); payloads are binary-safe.
PUC Lua itself has no OS threads (coroutines never run concurrently, and a
recv() blocks its whole lua_State). With a threads library such as
lua-llthreads2, each
thread is its own lua_State: require("polycall") there and wrap the same
node with polycall.peer_from_handle(peer:handle()); every core call is
thread-safe, and cancel() / close() from one thread wake a recv() blocked
in another (E_CANCELLED / E_CLOSED). Without one, use bounded timeouts.
The lua-polycall script (version, validate [CONFIG] [--lenient],
call ENDPOINT SERVICE OPERATION [JSON] [TIMEOUT_MS]) is installed by the rock.
Tests
tests/run-real-core.sh builds and installs the rock into a private tree
with LuaRocks and runs tests/real_core.lua from outside the checkout
against the real installed core (Lua 5.4 by default, LUA=lua5.3 for 5.3):
version/ABI, missing core / old core / ABI 2, run_config (valid, missing,
invalid, strict, TLS, non-ASCII path), call against a live polycall start
runtime and a polycall daemon, timeout boundaries, two nodes both
directions, payload matrix (empty, UTF-8, binary + NUL, 1 MiB, 1 MiB + 1),
registry ownership, de-duplication, auth, dead peers, timeouts, small buffers,
cancel and close waking a blocked recv() and 8 sender threads sharing /
owning handles (OS threads through lua-llthreads2), handle lifecycle,
concurrent senders from separate Lua processes, interop with a
polycall peer serve C node, and the CLI script. A missing Lua, LuaRocks or
core, or any skipped test (e.g. lua-llthreads2 not installed), is reported as
SKIP (exit 77), never as success.
tests/run-package.sh packs a binary rock (luarocks make
--pack-binary-rock), installs it into a clean tree and uses it from outside
the checkout against the real core.
luarocks install lua-llthreads2 # test-only dependency (threaded checks)
sh tests/run-real-core.sh # core in /opt/polycall, or POLYCALL_PREFIX / POLYCALL_LIBRARY
LUA=lua5.3 sh tests/run-real-core.sh
LUA_POLYCALL_TEST_WRAPPER="valgrind --error-exitcode=99 --leak-check=full" sh tests/run-real-core.sh
sh tests/run-package.shLicense
MIT, OBINexus Computing / Nnamdi Michael Okpala, see LICENSE.
