{"id":36991153,"url":"https://github.com/kubeservice-stack/lua-resty-zookeeper","last_synced_at":"2026-01-13T23:41:42.810Z","repository":{"id":328789873,"uuid":"1116730480","full_name":"kubeservice-stack/lua-resty-zookeeper","owner":"kubeservice-stack","description":"lua-resty-zookeeper for openresty","archived":false,"fork":false,"pushed_at":"2025-12-25T12:01:44.000Z","size":110,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-26T15:56:34.215Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kubeservice-stack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-15T09:50:32.000Z","updated_at":"2025-12-25T03:46:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kubeservice-stack/lua-resty-zookeeper","commit_stats":null,"previous_names":["kubeservice-stack/lua-resty-zookeeper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/kubeservice-stack/lua-resty-zookeeper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubeservice-stack%2Flua-resty-zookeeper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubeservice-stack%2Flua-resty-zookeeper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubeservice-stack%2Flua-resty-zookeeper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubeservice-stack%2Flua-resty-zookeeper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kubeservice-stack","download_url":"https://codeload.github.com/kubeservice-stack/lua-resty-zookeeper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kubeservice-stack%2Flua-resty-zookeeper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28399512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-13T23:41:42.254Z","updated_at":"2026-01-13T23:41:42.805Z","avatar_url":"https://github.com/kubeservice-stack.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lua-resty-zookeeper\n\nA minimal, synchronous ZooKeeper client for OpenResty / plain Lua with robust CONNECT handshake parsing and basic operations.\n\nThis repository provides:\n\n- `lua/resty/zookeeper.lua` — core client implementation (handshake, signed error handling, create/get_children, exists, get_data, add_auth, close).\n- `test/test_zk.lua` — extended test script (connect, exists, get_data, create, get_children, delete, watch).\n\nNotable updates\n\n- Robust CONNECT handshake parsing with heuristics to handle different server response layouts.\n- Converts server 32-bit error codes to signed int32 for correct interpretation (e.g. ZNONODE = -101, ZNODEEXISTS = -110).\n- Added API:\n  - `client:create(path, data, mode, sequential)` — create nodes (supports persistent / ephemeral and sequential flags).\n  - `client:get_children(path)` — list children (returns a Lua table).\n  - `client:delete(path, version)` — delete a node (supports specifying version; default -1 means any version).\n  - `client:watch(path, kind)` — register a watcher and block until the next watcher event for this session (synchronous/blocking).\n\n## Quick start (plain Lua)\n\n1. Optional dependency for JSON support:\n\n   Using luarocks:\n\n   ```\n      luarocks install lua-cjson\n   ```\n\n2. Ensure the project `lua/` directory is on `package.path`.\n\n3. Run the test script:\n   - Linux / macOS (bash):\n\n     ```\n     export LUA_PATH=\"./lua/?.lua;./lua/?/init.lua;;\"\n     lua test/test_zk.lua 127.0.0.1:2181 /your_parent_path\n     ```\n\n   - Windows (PowerShell):\n\n     ```\n     $env:LUA_PATH = \".\\lua\\?.lua;.\\lua\\?\\init.lua;;\"\n     lua test\\test_zk.lua 127.0.0.1:2181 \\your_parent_path\n     ```\n\n## Quick start (OpenResty)\n\n1. Add the `lua/` directory to `lua_package_path` in `nginx.conf`:\n\n   ```nginx\n   lua_package_path \"/path/to/project/lua/?.lua;/path/to/project/lua/?/init.lua;;\";\n   ```\n\n2. Use in OpenResty Lua code:\n\n   ```lua\n   local zk = require(\"resty.zookeeper\")\n   local client, err = zk.new{\n     connect_string = \"127.0.0.1:2181\",\n     timeout = 3000,\n     session_timeout = 30000,\n     debug = false,\n   }\n   local ok, err = client:connect()\n   ```\n\n## API summary\n\n- Create client\n\n```lua\nlocal zk = require(\"zk_connection\") -- or require(\"resty.zookeeper\") or require(\"zookeeper\")\nlocal client, err = zk.new{\n  connect_string = \"127.0.0.1:2181\",\n  timeout = 5000,        -- ms for ngx, best-effort otherwise\n  session_timeout = 30000,\n  debug = true,          -- print handshake payload hex when true\n}\n```\n\n- Connect\n\n```lua\nlocal ok, err = client:connect()\nif not ok then error(err) end\n```\n\n- Basic operations\n\n```lua\n-- exists\nlocal exists, err = client:exists(\"/myapp\")\n\n-- get_data\nlocal data, err = client:get_data(\"/myapp\")\n\n-- add auth (instance method)\nlocal ok, err = client:add_auth(\"digest\", \"user:pass\")\n```\n\n- create\n\n```lua\n-- create(path, data, mode, sequential)\n-- mode: \"persistent\" (default) or \"ephemeral\"\n-- sequential: boolean; if true the server appends a monotonically increasing sequence number\nlocal created_path, err = client:create(\"/myapp/node\", \"payload\", \"persistent\", true)\n```\n\n- get_children\n\n```lua\nlocal children, err = client:get_children(\"/myapp\")\n-- returns a Lua table, e.g. { \"node0000000001\", \"node0000000002\", ... }\n```\n\n- delete\n\n```lua\n-- delete(path, version)\n-- version: signed int32; default -1 means match any version\nlocal ok, err = client:delete(\"/myapp/node\", -1)\nif not ok then\n  print(\"delete failed:\", err)\nend\n```\n\n- watch\n\n```lua\n-- watch(path, kind)\n-- kind: \"exists\" (default), \"get_data\", or \"get_children\"\n-- Blocks until a watcher event is delivered for this session.\nlocal evt, err = client:watch(\"/myapp\", \"get_children\")\nif not evt then\n  print(\"watch failed:\", err)\nelse\n  -- evt = { type = \u003cint\u003e, state = \u003cint\u003e, path = \"\u003cstring\u003e\" }\n  print(\"watch event:\", evt.type, evt.state, evt.path)\nend\n```\n\n## Error codes\n\n- Server error codes are 32-bit signed integers. This implementation converts received error codes to signed int32 values and interprets common constants:\n  - -101 (ZNONODE) : node does not exist\n  - -110 (ZNODEEXISTS) : node already exists\n  - -103 (ZBADVERSION) : version conflict on update/delete\n- Client methods return friendly errors for these conditions (for example, `exists` returns `false, nil` when the node does not exist).\n\n## Testing\n\n- The test script `test/test_zk.lua` demonstrates:\n  - connecting to a server\n  - checking for and creating a parent node if necessary\n  - creating a sequential child node\n  - listing children via `get_children`\n  - deleting a created node\n  - registering a watch and waiting for an event\n\n- Run the test with debug enabled to print handshake payload hex:\n\n  ```\n  export LUA_PATH=\"./lua/?.lua;./lua/?/init.lua;;\"\n  lua test/test_zk.lua 127.0.0.1:2181 /daaa\n  ```\n\n## Watcher testing notes\n\n- Watchers in ZooKeeper are session-scoped and the server sends watcher events to the session that registered them.\n- This library implements `watch` as a synchronous blocking call that waits for the next watcher event delivered to the session. Because it blocks, use a separate connection or coroutine for watchers if you need to perform other requests concurrently.\n- For reliable testing of watchers, use two clients/processes:\n  - Client A registers the watch (calls `client:watch(...)`).\n  - Client B performs an operation (create/delete/set) that triggers the watch.\n  - Client A should then receive the watcher event.\n\n## Implementation notes\n\n- `delete` encodes the provided version as a 32-bit integer. `version = -1` is encoded as `0xFFFFFFFF`, matching ZooKeeper's signed int32 representation for \"any version\".\n- `watch` sends the corresponding request (exists/get_data/get_children) with the watch flag set to 1, then reads packets until a watcher event (xid == -1, unsigned 4294967295) arrives. Non-watcher packets received while waiting are ignored.\n- This client is synchronous and designed for single-request-at-a-time usage per connection. If you require concurrent requests and watcher/event dispatching on a single connection, consider adding:\n  - an internal packet dispatcher that reads incoming packets continuously,\n  - routing responses by xid to waiting coroutines,\n  - delivering watcher events to registered callbacks.\n\n## Limitations and future work\n\n- Current limitations:\n  - synchronous (blocking) I/O model,\n  - single-request-per-connection assumption,\n  - simple watcher support (blocking wait for a single event),\n  - limited operation coverage and stat parsing,\n  - no automatic reconnection/session recovery logic,\n  - limited tests and no CI.\n\n- Potential enhancements:\n  - add an event-driven dispatcher and non-blocking watcher callbacks,\n  - implement reconnection and session recovery,\n  - expand the supported ZooKeeper protocol operations (ACLs, multi, get_acl, set_acl, stat parsing),\n  - add unit tests and CI workflow,\n  - publish as a LuaRock.\n\n## License\n\n- BSD\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkubeservice-stack%2Flua-resty-zookeeper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkubeservice-stack%2Flua-resty-zookeeper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkubeservice-stack%2Flua-resty-zookeeper/lists"}