├── .gitignore ├── LICENSE ├── README.md ├── dist.ini └── lib └── resty ├── jsonrpc_demo.lua └── jsonrpc_server.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, rryqszq4 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-resty-jsonrpc-server 2 | ======================== 3 | 4 | lua-resty-jsonrpc-server -- JsonRPC 2.0 server for ngx_lua 5 | 6 | Table of Contents 7 | ================= 8 | 9 | * [Name](#lua-resty-jsonrpc-server) 10 | * [Description](#description) 11 | * [Synopsis](#synopsis) 12 | * [Curl test](#curl-test) 13 | * [Methods](#methods) 14 | * [new](#new) 15 | * [register](#register) 16 | * [bind](#bind) 17 | * [json_format](#json_format) 18 | * [rpc_format](#rpc_format) 19 | * [execute_procedure](#execute_procedure) 20 | * [execute_callback](#execute_callback) 21 | * [execute_method](#execute_method) 22 | * [get_response](#get_response) 23 | * [execute](#execute) 24 | * [rpc_error](#rpc_error) 25 | * [Jsonrpc 2.0 error](#jsonrpc-20-error) 26 | * [Author](#author) 27 | * [Copyright and License](#copyright-and-license) 28 | 29 | 30 | Description 31 | =========== 32 | 33 | This Lua library is a JsonRPC 2.0 server for the ngx_lua nginx module. 34 | 35 | 36 | Synopsis 37 | ======== 38 | 39 | ```lua 40 | lua_package_path "/path/to/lua-resty-jsonrpc-server/lib/?.lua;;"; 41 | 42 | server { 43 | location /lua-jsonrpc-server { 44 | default_type "application/json"; 45 | 46 | content_by_lua ' 47 | local jsonrpc_server = require "resty.jsonrpc_server" 48 | local jsonrpc_demo = require "resty.jsonrpc_demo" 49 | 50 | local server = jsonrpc_server:new() 51 | 52 | local add1 = function(a, b) 53 | return a + b 54 | end 55 | 56 | local register = server:register([[addition]], add1) 57 | 58 | local binder = server:bind([[addition1]], jsonrpc_demo, [[add1]]) 59 | 60 | local result = server:execute() 61 | 62 | ngx.say(result); 63 | 64 | '; 65 | } 66 | } 67 | 68 | ``` 69 | 70 | Curl test 71 | ========= 72 | 73 | input 74 | ```sh 75 | $ curl -d "{\"jsonrpc\":\"2.0\",\"method\":\"addition\", \"params\":[1,5]}" http://localhost/lua-jsonrpc-server 76 | ``` 77 | 78 | output 79 | ```sh 80 | $ {"result":6,"jsonrpc":"2.0","id":"null"} 81 | ``` 82 | 83 | Methods 84 | ======= 85 | 86 | new 87 | --- 88 | `syntax: server, err = jsonrpc_server:new()` 89 | 90 | register 91 | -------- 92 | `syntax: ok, err = jsonrpc_server:register(procedure, closure)` 93 | 94 | bind 95 | ---- 96 | `syntax: ok, err = jsonrpc_server:bind(procedure, classname, method)` 97 | 98 | json_format 99 | ----------- 100 | `syntax: ok, err = jsonrpc_server:json_format()` 101 | 102 | rpc_format 103 | ---------- 104 | `syntax: ok, err = jsonrpc_server:rpc_format()` 105 | 106 | execute_procedure 107 | ----------------- 108 | `syntax: ok, err = jsonrpc_server:execute_procedure(payload_method, payload_params)` 109 | 110 | execute_callback 111 | ---------------- 112 | `syntax: ok, err = jsonrpc_server:execute_callback(method, params)` 113 | 114 | execute_method 115 | -------------- 116 | `syntax: ok, err = jsonrpc_server:execute_method(method, params)` 117 | 118 | get_response 119 | ------------ 120 | `syntax: ok, err = jsonrpc_server:get_response(data)` 121 | 122 | execute 123 | ------- 124 | `syntax: ok, err = jsonrpc_server:execute()` 125 | 126 | rpc_error 127 | --------- 128 | `syntax: ok, err = jsonrpc_server:rpc_error(code, message)` 129 | 130 | Jsonrpc 2.0 error 131 | ================= 132 | 133 | ```javascript 134 | // Parse error 135 | {"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"Parse error"}} 136 | 137 | // Invalid Request 138 | {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid Request"}} 139 | 140 | // Method not found 141 | {"jsonrpc":"2.0","id":null,"error":{"code":-32601,"message":"Method not found"}} 142 | 143 | // Invalid params 144 | {"jsonrpc":"2.0","id":null,"error":{"code":-32602,"message":"Invalid params"}} 145 | ``` 146 | 147 | Author 148 | ====== 149 | 150 | rryqszq4 . 151 | 152 | Copyright and License 153 | ===================== 154 | 155 | Copyright (c) 2015, rryqszq4 156 | All rights reserved. 157 | 158 | Redistribution and use in source and binary forms, with or without 159 | modification, are permitted provided that the following conditions are met: 160 | 161 | * Redistributions of source code must retain the above copyright notice, this 162 | list of conditions and the following disclaimer. 163 | 164 | * Redistributions in binary form must reproduce the above copyright notice, 165 | this list of conditions and the following disclaimer in the documentation 166 | and/or other materials provided with the distribution. 167 | 168 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 169 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 171 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 172 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 173 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 174 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 175 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 176 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 177 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | name=lua-resty-jsonrpc-server 2 | abstract=JsonRPC 2.0 server for the ngx_lua/openresty 3 | author=Quan Zhao (rryqszq4) 4 | is_original=yes 5 | license=2bsd 6 | lib_dir=lib 7 | doc_dir=lib 8 | repo_link=https://github.com/rryqszq4/lua-resty-jsonrpc-server 9 | main_module=lib/resty/jsonrpc_server.lua 10 | requires = luajit >= 2.1.0, nginx >= 1.6.3 -------------------------------------------------------------------------------- /lib/resty/jsonrpc_demo.lua: -------------------------------------------------------------------------------- 1 | local _M = {} 2 | 3 | local mt = { __index = _M } 4 | 5 | function _M.new (self) 6 | return setmetatable({ }, mt) 7 | end 8 | 9 | function _M.add1(a, b) 10 | return a+b 11 | end 12 | 13 | return _M -------------------------------------------------------------------------------- /lib/resty/jsonrpc_server.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2015, rryqszq4 2 | -- All rights reserved. 3 | -- curl -d "{\"method\":\"addition\", \"params\":[1,3]}" http://localhost/lua-jsonrpc-server 4 | 5 | local cjson = require "cjson" 6 | 7 | local _M = { 8 | _VERSION = '0.0.1' 9 | } 10 | 11 | local mt = { __index = _M } 12 | 13 | function _M.new(self) 14 | local payload 15 | local callbacks 16 | local classes 17 | 18 | payload = nil 19 | callbacks = {} 20 | classes = {} 21 | 22 | return 23 | setmetatable({ 24 | payload = payload, 25 | callbacks = callbacks, 26 | classes = classes 27 | }, mt) 28 | end 29 | 30 | function _M.register(self, procedure, closure) 31 | 32 | self.callbacks[procedure] = closure 33 | 34 | end 35 | 36 | function _M.bind(self, procedure, classname, method) 37 | 38 | self.classes[procedure] = 39 | { 40 | classname = classname, 41 | method = method 42 | } 43 | 44 | end 45 | 46 | function _M.json_format(self) 47 | if self.payload == nil then 48 | ngx.req.read_body() 49 | self.payload = ngx.var.request_body 50 | end 51 | 52 | if type(self.payload) == "string" then 53 | self.payload = cjson.decode(self.payload) 54 | end 55 | 56 | if type(self.payload) == "table" then 57 | return true 58 | else 59 | return false 60 | end 61 | end 62 | 63 | function _M.rpc_format(self) 64 | if type(self.payload) ~= "table" then 65 | return { 66 | -32600, 67 | "Invalid Request" 68 | } 69 | end 70 | 71 | if self.payload["jsonrpc"] == nil or self.payload["jsonrpc"] ~= "2.0" then 72 | return { 73 | -32600, 74 | "Invalid Request" 75 | } 76 | end 77 | 78 | if self.payload["method"] == nil or type(self.payload["method"]) ~= "string" then 79 | return { 80 | -32601, 81 | "Method not found" 82 | } 83 | end 84 | 85 | if self.payload["params"] == nil or type(self.payload["params"]) ~= "table" then 86 | return { 87 | -32602, 88 | "Invalid params" 89 | } 90 | end 91 | 92 | return nil 93 | end 94 | 95 | function _M.execute_procedure(self, payload_method, payload_params) 96 | 97 | if type(self.callbacks[payload_method]) ~= "nil" then 98 | 99 | return self:execute_callback(payload_method, payload_params) 100 | 101 | elseif type(self.classes[payload_method]) ~= "nil" then 102 | 103 | return self:execute_method(payload_method, payload_params) 104 | 105 | else 106 | 107 | return self:rpc_error(-32601, "Method not found") 108 | 109 | end 110 | 111 | end 112 | 113 | function _M.execute_callback(self, method, params) 114 | local method = self.callbacks[method] 115 | local success, result = pcall(method, unpack(params)) 116 | return self:get_response(result) 117 | end 118 | 119 | function _M.execute_method(self, method, params) 120 | 121 | local classname = self.classes[method]["classname"] 122 | local method = self.classes[method]["method"] 123 | local success, result = pcall(classname[method], unpack(params)) 124 | 125 | return self:get_response(result) 126 | end 127 | 128 | function _M.get_response(self, data) 129 | return cjson.encode({ 130 | jsonrpc = "2.0", 131 | id = "null", 132 | result = data 133 | }) 134 | end 135 | 136 | function _M.execute(self) 137 | local result 138 | 139 | result = self:json_format() 140 | if result ~= true then 141 | return self:rpc_error(-32700, "Parse error") 142 | end 143 | 144 | result = self:rpc_format() 145 | if result ~= nil then 146 | return self:rpc_error(result[1], result[2]) 147 | end 148 | 149 | return self:execute_procedure(self.payload.method, self.payload.params) 150 | 151 | end 152 | 153 | function _M.rpc_error(self, code, message) 154 | return cjson.encode({ 155 | jsonrpc = "2.0", 156 | error = { 157 | code = code, 158 | message = message 159 | }, 160 | id = "null" 161 | }) 162 | end 163 | 164 | return _M 165 | 166 | --------------------------------------------------------------------------------