diff options
-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); } }); |