{"id":20842986,"url":"https://github.com/fffonion/lua-resty-shdict-server","last_synced_at":"2025-09-17T23:38:23.667Z","repository":{"id":150895117,"uuid":"118412237","full_name":"fffonion/lua-resty-shdict-server","owner":"fffonion","description":"Use ngx.shared as a Redis server","archived":false,"fork":false,"pushed_at":"2021-05-19T14:04:47.000Z","size":45,"stargazers_count":15,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-08T22:42:26.184Z","etag":null,"topics":["openresty","redis","redis-server","shdict"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fffonion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2018-01-22T05:47:48.000Z","updated_at":"2024-04-12T09:26:02.000Z","dependencies_parsed_at":"2023-07-09T12:31:51.408Z","dependency_job_id":null,"html_url":"https://github.com/fffonion/lua-resty-shdict-server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fffonion%2Flua-resty-shdict-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fffonion%2Flua-resty-shdict-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fffonion%2Flua-resty-shdict-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fffonion%2Flua-resty-shdict-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fffonion","download_url":"https://codeload.github.com/fffonion/lua-resty-shdict-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253160727,"owners_count":21863624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["openresty","redis","redis-server","shdict"],"created_at":"2024-11-18T01:26:18.309Z","updated_at":"2025-09-17T23:38:18.584Z","avatar_url":"https://github.com/fffonion.png","language":"Lua","funding_links":[],"categories":["Lua"],"sub_categories":[],"readme":"Name\n====\n\nlua-resty-shdict-server - A HTTP and Redis protocol compatible interface for debugging ngx.shared API\n\n![Build status](https://travis-ci.com/fffonion/lua-resty-shdict-server.svg?branch=master)\n\nTable of Contents\n=================\n\n- [Description](#description)\n- [Status](#status)\n- [Synopsis](#synopsis)\n- [API](#api)\n- [Commands](#commands)\n    * [Basic commands](#basic-commands)\n    * [AUTH](#auth)\n    * [SELECT](#select)\n    * [PING](#ping)\n    * [KEYS](#keys)\n\t* [EVAL](#eval)\n    * [DEL](#del)\n    * [GETFLAG](#getflag)\n- [Known Issues](#known-issues)\n- [TODO](#todo)\n- [Copyright and License](#copyright-and-license)\n- [See Also](#see-also)\n\n\nDescription\n===========\n\nThis is a library that provides a HTTP and a Redis protocol compatible interface to debug [ngx.shared.DICT](https://github.com/openresty/lua-nginx-module#ngxshareddict) API.\n\nIt can also be used as a mocking Redis server (WIP).\n\n[Back to TOC](#table-of-contents)\n\n\nStatus\n========\n\nProduction.\n\nSynopsis\n========\n\nShared dictionaries defined in `http` and `stream` subsystems are not shared to each other *currently*, thus we need two sets of configurations to debug with either subsystem. \n\nHowever there're [patches](patches) if you want to share shdict between `http` and `stream` subsystems. After apply the patch, you will need to use two `lua_shared_dict` directives to define shared dict twice with same name and same size. e.g.:\n\n```lua\nhttp {\n    lua_shared_dict dogs 10m;\n}\n\nstream {\n    lua_shared_dict dogs 10m;\n}\n```\n\nThis module provide a similar API to use in both subsystems.\n\nhttp\n----\n\n```lua\nlua_shared_dict dogs 10m;\n\nserver {\n    listen 80;\n    \n    location =/cli {\n        content_by_lua_block {\n            require \"resty.core\"\n            local srv = require(\"resty.shdict.server\")\n            local s = srv:new(\"foobar\", nil)\n            s:serve()\n        }\n    }\n}\n```\n\nThis sets up a simple HTTP server. Use any http client like `curl` to issue a http request to the location we configured. For example:\n\n```shell\n$ curl \"http://host/cli?dict=dogs\u0026cmd=set%20dog%20wow\u0026password=foobar\"\nOK\n\n$ curl \"http://host/cli?dict=dogs\u0026cmd=get%20dog\u0026password=foobar\"\n\"wow\"\n```\n\nstream\n----\n\n```lua\nlua_shared_dict dogs 10m;\n\nserver {\n    listen 127.0.0.1:18001;\n    content_by_lua_block {\n        require \"resty.core.shdict\"\n        require \"resty.shdict.redis-commands\"\n        local srv = require(\"resty.shdict.server\")\n        local s = srv:new(\"foobar\", nil)\n        s:serve()\n    }\n}\n```\n\nThis sets up a simple TCP server. Use telnet or equivalent tools to connect interactively. For example:\n\n```shell\n$ telnet 127.0.0.1 18001\nTrying 127.0.0.1...\nConnected to 127.0.0.1.\nEscape character is '^]'.\nSELECT dogs\n-ERR authentication required\nAUTH foobar\n+OK\nSELECT dogs\n+OK\nSET dog wow\n+OK\nGET dog\n+wow\n```\n\nAlso it supports [Redis RESP protocol](https://redis.io/topics/protocol).\n\n```shell\n$ redis-cli -h 127.0.0.1 -p 18001\n127.0.0.1:18001\u003e get dogs\n(error) ERR authentication required\n127.0.0.1:18001\u003e auth foobar\nOK\n127.0.0.1:18001\u003e set dog wow\n(error) ERR no shdict selected\n127.0.0.1:18001\u003e select dogs\nOK\n127.0.0.1:18001\u003e set dog wow\nOK\n127.0.0.1:18001\u003e get dog\nwow\n```\n\n\n[Back to TOC](#table-of-contents)\n\n\nAPI\n=======\n\nshdict.server:new(password, shdict)\n---------------------------------\n\nInitialize the server instance with *password* and pre-selected shared dictionary *shdict*.\n\nIf *password* is not set, the server is public. If *password* is set, client must call [auth](#auth) command to authenticate before running other commands. Please take proper security measurements if you're listening to non-local interfaces.\n\nIf *shdict* is not set, client must call [select](#select) command to select a shared dictionary.\n\nshdict.server:serve(mode)\n---------------------\n\nStart the server with handler named *mode`. To run handler `serve_stream_redis`, use:\n\n```Lua\nshdict.server:serve(\"stream_redis\")\n```\n\nIf *mode* is not defined, default handler for each subsystem is used. For `http` the default handler is `serve_http_plain`. For `stream` the default handler is `serve_stream_redis`.\n\nshdict.server:serve_http_plain()\n--------------------------------\n\nThis handler accept a single HTTP request from client and send the response back in plain text.\n\nshdict.server:serve_http_json()\n-------------------------------\n\nThis handler accept a single HTTP request from client and send the response back in json encoded text.\n\nshdict.server:serve_http(output_filter)\n---------------------------------------\n\nThis handler accept a single HTTP request from client and send the response formatted by `output_filter`.\n\nIf `output_filter` is not defined, **output_plain** is used and this handler is equivalent to `serve_http_plain`.\n\n`output_filter` is a function that takes a table as argument and returns a string. User can define their own filter and genereate desirable output.\n\nshdict.server:serve_stream_redis()\n----------------------------------\n\nThis handler accept TCP connection in inline or Redis protocol. A plain text TCP client like `telnet` or `nc` or a Redis-compatible client or library can be used to connect to the server.\n\n[Back to TOC](#table-of-contents)\n\n\nCommands\n=======\n\nBasic commands\n-------------\n\nMethods from `ngx.shared.DICT` API are supported.\n\n* [ngx.shared.DICT](https://github.com/openresty/lua-nginx-module#ngxshareddict)\n* [ngx.shared.DICT.get](https://github.com/openresty/lua-nginx-module#ngxshareddictget)\n* [ngx.shared.DICT.get_stale](https://github.com/openresty/lua-nginx-module#ngxshareddictget_stale)\n* [ngx.shared.DICT.set](https://github.com/openresty/lua-nginx-module#ngxshareddictset)\n* [ngx.shared.DICT.safe_set](https://github.com/openresty/lua-nginx-module#ngxshareddictsafe_set)\n* [ngx.shared.DICT.add](https://github.com/openresty/lua-nginx-module#ngxshareddictadd)\n* [ngx.shared.DICT.safe_add](https://github.com/openresty/lua-nginx-module#ngxshareddictsafe_add)\n* [ngx.shared.DICT.replace](https://github.com/openresty/lua-nginx-module#ngxshareddictreplace)\n* [ngx.shared.DICT.delete](https://github.com/openresty/lua-nginx-module#ngxshareddictdelete)\n* [ngx.shared.DICT.incr](https://github.com/openresty/lua-nginx-module#ngxshareddictincr)\n* [ngx.shared.DICT.lpush](https://github.com/openresty/lua-nginx-module#ngxshareddictlpush)\n* [ngx.shared.DICT.rpush](https://github.com/openresty/lua-nginx-module#ngxshareddictrpush)\n* [ngx.shared.DICT.lpop](https://github.com/openresty/lua-nginx-module#ngxshareddictlpop)\n* [ngx.shared.DICT.rpop](https://github.com/openresty/lua-nginx-module#ngxshareddictrpop)\n* [ngx.shared.DICT.llen](https://github.com/openresty/lua-nginx-module#ngxshareddictllen)\n* [ngx.shared.DICT.ttl](https://github.com/openresty/lua-nginx-module#ngxshareddictttl)\n* [ngx.shared.DICT.expire](https://github.com/openresty/lua-nginx-module#ngxshareddictexpire)\n* [ngx.shared.DICT.flush_all](https://github.com/openresty/lua-nginx-module#ngxshareddictflush_all)\n* [ngx.shared.DICT.flush_expired](https://github.com/openresty/lua-nginx-module#ngxshareddictflush_expired)\n* [ngx.shared.DICT.get_keys](https://github.com/openresty/lua-nginx-module#ngxshareddictget_keys)\n* [ngx.shared.DICT.capacity](https://github.com/openresty/lua-nginx-module#ngxshareddictcapacity)\n* [ngx.shared.DICT.free_space](https://github.com/openresty/lua-nginx-module#ngxshareddictfree_space)\n\nSome of the commands like `ttl` and `capacity` require the `resty.core` being installed. To use these commands, put `require('resty.core')` for http subsystem and `require('resty.core.shdict')` for stream subsystem.\n\nMethods names are **case-insensitive**. Arguments are seperated by spaces.\n\nFor example:\n\n- To set a value **wow** with key **dog**, use `SET dog wow` or `sEt dog wow`.\n- To set a value **wow !** with key **dog**, use `SET dog \"wow !\"`.\n- To set a value **\"wow\" !** with key **dog**, use `SET dog \"\\\"wow\\\" !\"`.\n\nSome commands are mapped to redis-flavoured commands if `resty.shdict.redis-commands` is included.\n\n- `setnx` as an alias of `add`\n- `setex` as an alias of `replace`\n- `flushall` as an alias of `flush_all`\n\nAUTH\n----\n\nAuthenticate to the server.\n\nReturns **OK** if *password* is valid.\n\n```\n\u003e AUTH password\n```\n\nSELECT\n------\n\nSelect a shared dictionary.\n\nReturns **OK** if *shdict* is found.\n\n```\n\u003e SELECT shdict\n```\n\nPING\n----\n\nTest connection to the server.\n\nReturns **PONG**.\n\n```\n\u003e PING\n```\n\nKEYS\n----\n\nThis command requires the `resty.shdict.redis-commands` module.\n\nReturn all keys matching *pattern* in a list. The *pattern* is a glob-style pattern.\n\nThe time complexity is **O(3n)**. This command is for debug only, please do not use in production code to search for keys.\n\n```\n\u003e KEYS pattern\n\u003e KEYS do?\n\u003e KEYS do*\n\u003e KEYS do[a-z]\n```\n\nEVAL\n----\n\nThis command requires the `resty.shdict.redis-commands` module.\n\nRun a Lua script on the server. The syntax is same as Redis [EVAL](https://redis.io/commands/eval). \n\n```\n\u003e EVAL script numkeys key [key ...] arg [arg ...]\n\u003e EVAL \"shdict.call('set', 'dog', 'wow') 0\n(nil)\n\u003e EVAL \"return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}\" 2 key1 key2 first second\n1) \"key1\"\n2) \"key2\"\n3) \"first\"\n4) \"second\"\n```\n\nFor security reasons, only the following APIs are available:\n\n- Functions: `assert`, `error`, `getmetatable`, `ipairs`, `next`, `pairs`, `pcall`, `select`, `setmetatable`, `tonumber`, `tostring`, `unpack`\n- Modules: `bit`, `math`, `string`, `table`\n- `ngx.shared` and `ngx.re`\n- `shdict.call` and `shdict.pcall` for invoking shdict APIs\n- `zone` as the current shdict instance\n\nAlso an alias from `redis.call` to `shdict.call` is created for convenience.\n\n\nGETFLAG\n-------\n\nThis command requires the `resty.shdict.redis-commands` module.\n\nGet the user flag for a key.\n\nReturn `nil` if the user flag is not set or key is not found.\n\n```\nGETFLAG key\n```\n\nDEL\n---\n\nThis command requires the `resty.shdict.redis-commands` module.\n\nDelete one or more keys from shdict.\n\nReturns **OK**.\n\n```\nDEL key [key ...]\nDELETE key [key ...]\n```\n\n\n[Back to TOC](#table-of-contents)\n\n\nKnown Issues\n====\n\n- The library will use `resty.core` if it's installed, the behaviour will be slightly different from the C implementation. For example, missing arguments will be filled by `nil` when using `resty.core`, issuing `SET a` is equivalent to `SET a nil` in this situation.\n- For performance issues, inline protocol (HTTP inline or Redis inline) only accept four arguments at most. `EVAL` may fail with **Invalid argument(s)** for this reason. To solve this, always use other protocols (like Redis RESP protocol) to call these commands.\n- `EVAL` command is **not atomic** when running multiple `shdict.call` altough the script is run on server.\n\n[Back to TOC](#table-of-contents)\n\n\nTODO\n====\n\n- Add more ngx.* API to EVAL command.\n- Add atomic SETFLAG command.\n- Return affected keys count for DEL command.\n- Add INFO command.\n\n[Back to TOC](#table-of-contents)\n\n\nCopyright and License\n=====================\n\nThis module is licensed under the BSD license.\n\nCopyright (C) 2018, by fffonion \u003cfffonion@gmail.com\u003e.\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n[Back to TOC](#table-of-contents)\n\n\nSee Also\n========\n* [openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module)\n\n[Back to TOC](#table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffffonion%2Flua-resty-shdict-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffffonion%2Flua-resty-shdict-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffffonion%2Flua-resty-shdict-server/lists"}