From bdf0a4b520bdeb2c892f7eaadf3242c1b824bf11 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Sun, 14 Jun 2009 09:02:40 +0000 Subject: [PATCH] GSoC: Add RPC client --- libs/rpcc/Makefile | 2 + libs/rpcc/luasrc/rpcc.lua | 84 ++++++++++++++++++++++++++++++++++ libs/rpcc/luasrc/rpcc/ruci.lua | 63 +++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 libs/rpcc/Makefile create mode 100644 libs/rpcc/luasrc/rpcc.lua create mode 100644 libs/rpcc/luasrc/rpcc/ruci.lua diff --git a/libs/rpcc/Makefile b/libs/rpcc/Makefile new file mode 100644 index 000000000..81a96f6a8 --- /dev/null +++ b/libs/rpcc/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/libs/rpcc/luasrc/rpcc.lua b/libs/rpcc/luasrc/rpcc.lua new file mode 100644 index 000000000..ef94d3bbd --- /dev/null +++ b/libs/rpcc/luasrc/rpcc.lua @@ -0,0 +1,84 @@ +--[[ +LuCIRPCc +(c) 2009 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local util = require "luci.util" +local json = require "luci.json" +local ltn12 = require "luci.ltn12" +local nixio = require "nixio", require "nixio.util" + +local tostring, assert, setmetatable = tostring, assert, setmetatable +local error = error + +--- LuCI RPC Client. +-- @cstyle instance +module "luci.rpcc" + +RQLIMIT = 32 * nixio.const.buffersize + +--- Create a new JSON-RPC stream client. +-- @class function +-- @param fd File descriptor +-- @param v1 Use protocol version 1.0 +-- @return RPC Client +Client = util.class() + +function Client.__init__(self, fd, v1) + self.fd = fd + self.uniqueid = tostring(self):match("0x([a-f0-9]+)") + self.msgid = 1 + self.v1 = v1 +end + +--- Request an RP call and get the response. +-- @param method Remote method +-- @param params Parameters +-- @param notification Notification only? +-- @return response +function Client.request(self, method, params, notification) + local oldchunk = self.decoder and self.decoder.chunk + self.decoder = json.ActiveDecoder(self.fd:blocksource(nil, RQLIMIT)) + self.decoder.chunk = oldchunk + + local reqid = self.msgid .. self.uniqueid + local reqdata = json.Encoder({ + id = (not notification) and (self.msgid .. self.uniqueid) or nil, + jsonrpc = (not self.v1) and "2.0" or nil, + method = method, + params = params + }) + ltn12.pump.all(reqdata:source(), self.fd:sink()) + if not notification then + self.msgid = self.msgid + 1 + local response = self.decoder:get() + assert(response.id == reqid, "Invalid response id") + if response.error then + error(response.error.message or response.error) + end + return response.result + end +end + +--- Create a transparent RPC proxy. +-- @param prefix Method prefix +-- @return RPC Proxy object +function Client.proxy(self, prefix) + prefix = prefix or "" + return setmetatable({}, { + __call = function(proxy, ...) + return self:request(prefix, {...}) + end, + __index = function(proxy, name) + return self:proxy(prefix .. name .. ".") + end + }) +end \ No newline at end of file diff --git a/libs/rpcc/luasrc/rpcc/ruci.lua b/libs/rpcc/luasrc/rpcc/ruci.lua new file mode 100644 index 000000000..05cb72805 --- /dev/null +++ b/libs/rpcc/luasrc/rpcc/ruci.lua @@ -0,0 +1,63 @@ +--[[ +LuCIRPCc +(c) 2009 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local util = require "luci.util" +local rawget, setmetatable = rawget, setmetatable +local ipairs = ipairs + +--- Transparent UCI over RPC client. +-- @cstyle instance +module "luci.rpcc.ruci" + + +local Proxy = util.class() + +--- Create a new UCI over RPC proxy. +-- @param rpccl RPC client +-- @return Network transparent UCI module +function factory(rpccl) + return { + cursor = function(...) + return Proxy(rpccl, rpccl:request("ruci.cursor", {...})) + end, + cursor_state = function(...) + return Proxy(rpccl, rpccl:request("ruci.cursor_state", {...})) + end + } +end + +function Proxy.__init__(self, rpccl, objid) + self.__rpccl = rpccl + self.__objid = objid + + setmetatable(self, { + __index = function(self, key) + return rawget(self, key) or Proxy[key] or function(self, ...) + local argv = {self.__objid, ...} + return self.__rpccl:request("ruci."..key, argv) + end + end + }) +end + +function Proxy.foreach(self, config, section, callback) + local sections = self.__rpccl:request("ruci.foreach", {self.__objid, config, section}) + if sections then + for _, s in ipairs(sections) do + callback(s) + end + return true + else + return false + end +end -- 2.25.1