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>
This commit is contained in:
parent
43d8e98a15
commit
f141433f5e
1 changed files with 58 additions and 22 deletions
|
@ -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();
|
||||
|
||||
/* fetch response attribute and verify returned type */
|
||||
var ret = undefined;
|
||||
|
||||
/* 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];
|
||||
msg = res.json();
|
||||
}
|
||||
else {
|
||||
req.reject(new Error('Invalid message frame received'));
|
||||
catch (e) {
|
||||
return req.reject(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
},
|
||||
|
||||
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 || '?');
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue