summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2019-09-11 09:25:11 +0200
committerJo-Philipp Wich <jo@mein.io>2019-09-11 09:25:11 +0200
commitf141433f5e38153e9dfbb8b320dfa70db1a47cf2 (patch)
tree3020f81be52e291f18921fae640c3d6c94afe1f1
parent43d8e98a15072ff8f53d343a6a3fa1f59fcd175c (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.js76
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);
}
});