diff options
author | Jo-Philipp Wich <jo@mein.io> | 2019-09-11 09:25:11 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2019-09-11 09:25:11 +0200 |
commit | f141433f5e38153e9dfbb8b320dfa70db1a47cf2 (patch) | |
tree | 3020f81be52e291f18921fae640c3d6c94afe1f1 | |
parent | 43d8e98a15072ff8f53d343a6a3fa1f59fcd175c (diff) |
luci-base: rpc.js: revamp error handling, add interceptor support
Add two new functions L.rpc.addInterceptor() and L.rpc.removeInterceptor()
which allow to register and remove interceptor functions which are invoked
before the rpc reply result promise is fulfilled.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/rpc.js | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/rpc.js b/modules/luci-base/htdocs/luci-static/resources/rpc.js index e6a1bb24dc..9a0f0164ae 100644 --- a/modules/luci-base/htdocs/luci-static/resources/rpc.js +++ b/modules/luci-base/htdocs/luci-static/resources/rpc.js @@ -2,7 +2,8 @@ var rpcRequestID = 1, rpcSessionID = L.env.sessionid || '00000000000000000000000000000000', - rpcBaseURL = L.url('admin/ubus'); + rpcBaseURL = L.url('admin/ubus'), + rpcInterceptorFns = []; return L.Class.extend({ call: function(req, cb) { @@ -39,29 +40,50 @@ return L.Class.extend({ req.resolve(list); }, - handleCallReply: function(req, res) { - var type = Object.prototype.toString, - msg = null; + parseCallReply: function(req, res) { + var msg = null; - if (!res.ok) - L.error('RPCError', 'RPC call to %s/%s failed with HTTP error %d: %s', - req.object, req.method, res.status, res.statusText || '?'); + try { + if (!res.ok) + L.raise('RPCError', 'RPC call to %s/%s failed with HTTP error %d: %s', + req.object, req.method, res.status, res.statusText || '?'); - msg = res.json(); + msg = res.json(); + } + catch (e) { + return req.reject(e); + } - /* fetch response attribute and verify returned type */ - var ret = undefined; + /* + * The interceptor args are intentionally swapped. + * Response is passed as first arg to align with Request class interceptors + */ + Promise.all(rpcInterceptorFns.map(function(fn) { return fn(msg, req) })) + .then(this.handleCallReply.bind(this, req, msg)) + .catch(req.reject); + }, - /* verify message frame */ - if (typeof(msg) == 'object' && msg.jsonrpc == '2.0') { - if (typeof(msg.error) == 'object' && msg.error.code && msg.error.message) - req.reject(new Error('RPC call to %s/%s failed with error %d: %s' - .format(req.object, req.method, msg.error.code, msg.error.message || '?'))); - else if (Array.isArray(msg.result)) - ret = (msg.result.length > 1) ? msg.result[1] : msg.result[0]; + handleCallReply: function(req, msg) { + var type = Object.prototype.toString, + ret = null; + + try { + /* verify message frame */ + if (!L.isObject(msg) || msg.jsonrpc != '2.0') + L.raise('RPCError', 'RPC call to %s/%s returned invalid message frame', + req.object, req.method); + + /* check error condition */ + if (L.isObject(msg.error) && msg.error.code && msg.error.message) + L.raise('RPCError', 'RPC call to %s/%s failed with error %d: %s', + req.object, req.method, msg.error.code, msg.error.message || '?'); } - else { - req.reject(new Error('Invalid message frame received')); + catch (e) { + return req.reject(e); + } + + if (Array.isArray(msg.result)) { + ret = (msg.result.length > 1) ? msg.result[1] : msg.result[0]; } if (req.expect) { @@ -139,7 +161,7 @@ return L.Class.extend({ }; /* call rpc */ - rpc.call(msg, rpc.handleCallReply.bind(rpc, req)); + rpc.call(msg, rpc.parseCallReply.bind(rpc, req)); }); }, this, this, options); }, @@ -175,5 +197,19 @@ return L.Class.extend({ case 10: return _('Connection lost'); default: return _('Unknown error code'); } + }, + + addInterceptor: function(interceptorFn) { + if (typeof(interceptorFn) == 'function') + rpcInterceptorFns.push(interceptorFn); + return interceptorFn; + }, + + removeInterceptor: function(interceptorFn) { + var oldlen = rpcInterceptorFns.length, i = oldlen; + while (i--) + if (rpcInterceptorFns[i] === interceptorFn) + rpcInterceptorFns.splice(i, 1); + return (rpcInterceptorFns.length < oldlen); } }); |