diff options
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources/rpc.js')
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/rpc.js | 257 |
1 files changed, 256 insertions, 1 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/rpc.js b/modules/luci-base/htdocs/luci-static/resources/rpc.js index 9c74bfdaf0..9b642444fa 100644 --- a/modules/luci-base/htdocs/luci-static/resources/rpc.js +++ b/modules/luci-base/htdocs/luci-static/resources/rpc.js @@ -5,7 +5,17 @@ var rpcRequestID = 1, rpcBaseURL = L.url('admin/ubus'), rpcInterceptorFns = []; -return L.Class.extend({ +/** + * @class rpc + * @memberof LuCI + * @hideconstructor + * @classdesc + * + * The `LuCI.rpc` class provides high level ubus JSON-RPC abstractions + * and means for listing and invoking remove RPC methods. + */ +return L.Class.extend(/** @lends LuCI.rpc.prototype */ { + /* privates */ call: function(req, cb, nobatch) { var q = ''; @@ -106,6 +116,27 @@ return L.Class.extend({ req.resolve(ret); }, + /** + * Lists available remote ubus objects or the method signatures of + * specific objects. + * + * This function has two signatures and is sensitive to the number of + * arguments passed to it: + * - `list()` - + * Returns an array containing the names of all remote `ubus` objects + * - `list("objname", ...)` + * Returns method signatures for each given `ubus` object name. + * + * @param {...string} [objectNames] + * If any object names are given, this function will return the method + * signatures of each given object. + * + * @returns {Promise<Array<string>|Object<string, Object<string, Object<string, string>>>>} + * When invoked without arguments, this function will return a promise + * resolving to an array of `ubus` object names. When invoked with one or + * more arguments, a promise resolving to an object describing the method + * signatures of each requested `ubus` object name will be returned. + */ list: function() { var msg = { jsonrpc: '2.0', @@ -126,6 +157,138 @@ return L.Class.extend({ }, this)); }, + /** + * @typedef {Object} DeclareOptions + * @memberof LuCI.rpc + * + * @property {string} object + * The name of the remote `ubus` object to invoke. + * + * @property {string} method + * The name of the remote `ubus` method to invoke. + * + * @property {string[]} [params] + * Lists the named parameters expected by the remote `ubus` RPC method. + * The arguments passed to the resulting generated method call function + * will be mapped to named parameters in the order they appear in this + * array. + * + * Extraneous parameters passed to the generated function will not be + * sent to the remote procedure but are passed to the + * {@link LuCI.rpc~filterFn filter function} if one is specified. + * + * Examples: + * - `params: [ "foo", "bar" ]` - + * When the resulting call function is invoked with `fn(true, false)`, + * the corresponding args object sent to the remote procedure will be + * `{ foo: true, bar: false }`. + * - `params: [ "test" ], filter: function(reply, args, extra) { ... }` - + * When the resultung generated function is invoked with + * `fn("foo", "bar", "baz")` then `{ "test": "foo" }` will be sent as + * argument to the remote procedure and the filter function will be + * invoked with `filterFn(reply, [ "foo" ], "bar", "baz")` + * + * @property {Object<string,*>} [expect] + * Describes the expected return data structure. The given object is + * supposed to contain a single key selecting the value to use from + * the returned `ubus` reply object. The value of the sole key within + * the `expect` object is used to infer the expected type of the received + * `ubus` reply data. + * + * If the received data does not contain `expect`'s key, or if the + * type of the data differs from the type of the value in the expect + * object, the expect object's value is returned as default instead. + * + * The key in the `expect` object may be an empty string (`''`) in which + * case the entire reply object is selected instead of one of its subkeys. + * + * If the `expect` option is omitted, the received reply will be returned + * as-is, regardless of its format or type. + * + * Examples: + * - `expect: { '': { error: 'Invalid response' } }` - + * This requires the entire `ubus` reply to be a plain JavaScript + * object. If the reply isn't an object but e.g. an array or a numeric + * error code instead, it will get replaced with + * `{ error: 'Invalid response' }` instead. + * - `expect: { results: [] }` - + * This requires the received `ubus` reply to be an object containing + * a key `results` with an array as value. If the received reply does + * not contain such a key, or if `reply.results` points to a non-array + * value, the empty array (`[]`) will be used instead. + * - `expect: { success: false }` - + * This requires the received `ubus` reply to be an object containing + * a key `success` with a boolean value. If the reply does not contain + * `success` or if `reply.success` is not a boolean value, `false` will + * be returned as default instead. + * + * @property {LuCI.rpc~filterFn} [filter] + * Specfies an optional filter function which is invoked to transform the + * received reply data before it is returned to the caller. + * + */ + + /** + * The filter function is invoked to transform a received `ubus` RPC call + * reply before returning it to the caller. + * + * @callback LuCI.rpc~filterFn + * + * @param {*} data + * The received `ubus` reply data or a subset of it as described in the + * `expect` option of the RPC call declaration. In case of remote call + * errors, `data` is numeric `ubus` error code instead. + * + * @param {Array<*>} args + * The arguments the RPC method has been invoked with. + * + * @param {...*} extraArgs + * All extraneous arguments passed to the RPC method exceeding the number + * of arguments describes in the RPC call declaration. + * + * @return {*} + * The return value of the filter function will be returned to the caller + * of the RPC method as-is. + */ + + /** + * The generated invocation function is returned by + * {@link LuCI.rpc#declare rpc.declare()} and encapsulates a single + * RPC method call. + * + * Calling this function will execute a remote `ubus` HTTP call request + * using the arguments passed to it as arguments and return a promise + * resolving to the received reply values. + * + * @callback LuCI.rpc~invokeFn + * + * @param {...*} params + * The parameters to pass to the remote procedure call. The given + * positional arguments will be named to named RPC parameters according + * to the names specified in the `params` array of the method declaration. + * + * Any additional parameters exceeding the amount of arguments in the + * `params` declaration are passed as private extra arguments to the + * declared filter function. + * + * @return {Promise<*>} + * Returns a promise resolving to the result data of the remote `ubus` + * RPC method invocation, optionally substituted and filtered according + * to the `expect` and `filter` declarations. + */ + + /** + * Describes a remote RPC call procedure and returns a function + * implementing it. + * + * @param {LuCI.rpc.DeclareOptions} options + * If any object names are given, this function will return the method + * signatures of each given object. + * + * @returns {LuCI.rpc~invokeFn} + * Returns a new function implementing the method call described in + * `options`. + */ declare: function(options) { return Function.prototype.bind.call(function(rpc, options) { var args = this.varargs(arguments, 2); @@ -173,22 +336,58 @@ return L.Class.extend({ }, this, this, options); }, + /** + * Returns the current RPC session id. + * + * @returns {string} + * Returns the 32 byte session ID string used for authenticating remote + * requests. + */ getSessionID: function() { return rpcSessionID; }, + /** + * Set the RPC session id to use. + * + * @param {string} sid + * Sets the 32 byte session ID string used for authenticating remote + * requests. + */ setSessionID: function(sid) { rpcSessionID = sid; }, + /** + * Returns the current RPC base URL. + * + * @returns {string} + * Returns the RPC URL endpoint to issue requests against. + */ getBaseURL: function() { return rpcBaseURL; }, + /** + * Set the RPC base URL to use. + * + * @param {string} sid + * Sets the RPC URL endpoint to issue requests against. + */ setBaseURL: function(url) { rpcBaseURL = url; }, + /** + * Translates a numeric `ubus` error code into a human readable + * description. + * + * @param {number} statusCode + * The numeric status code. + * + * @returns {string} + * Returns the textual description of the code. + */ getStatusText: function(statusCode) { switch (statusCode) { case 0: return _('Command OK'); @@ -206,12 +405,68 @@ return L.Class.extend({ } }, + /** + * Registered interceptor functions are invoked before the standard reply + * parsing and handling logic. + * + * By returning rejected promises, interceptor functions can cause the + * invocation function to fail, regardless of the received reply. + * + * Interceptors may also modify their message argument in-place to + * rewrite received replies before they're processed by the standard + * response handling code. + * + * A common use case for such functions is to detect failing RPC replies + * due to expired authentication in order to trigger a new login. + * + * @callback LuCI.rpc~interceptorFn + * + * @param {*} msg + * The unprocessed, JSON decoded remote RPC method call reply. + * + * Since interceptors run before the standard parsing logic, the reply + * data is not verified for correctness or filtered according to + * `expect` and `filter` specifications in the declarations. + * + * @param {Object} req + * The related request object which is an extended variant of the + * declaration object, allowing access to internals of the invocation + * function such as `filter`, `expect` or `params` values. + * + * @return {Promise<*>|*} + * Interceptor functions may return a promise to defer response + * processing until some delayed work completed. Any values the returned + * promise resolves to are ignored. + * + * When the returned promise rejects with an error, the invocation + * function will fail too, forwarding the error to the caller. + */ + + /** + * Registers a new interceptor function. + * + * @param {LuCI.rpc~interceptorFn} interceptorFn + * The inteceptor function to register. + * + * @returns {LuCI.rpc~interceptorFn} + * Returns the given function value. + */ addInterceptor: function(interceptorFn) { if (typeof(interceptorFn) == 'function') rpcInterceptorFns.push(interceptorFn); return interceptorFn; }, + /** + * Removes a registered interceptor function. + * + * @param {LuCI.rpc~interceptorFn} interceptorFn + * The inteceptor function to remove. + * + * @returns {boolean} + * Returns `true` if the given function has been removed or `false` + * if it has not been found. + */ removeInterceptor: function(interceptorFn) { var oldlen = rpcInterceptorFns.length, i = oldlen; while (i--) |