4 rpcSessionID = L.env.sessionid || '00000000000000000000000000000000',
5 rpcBaseURL = L.url('admin/ubus'),
6 rpcInterceptorFns = [];
8 return L.Class.extend({
9 call: function(req, cb) {
12 if (Array.isArray(req)) {
14 return Promise.resolve([]);
16 for (var i = 0; i < req.length; i++)
18 q += '%s%s.%s'.format(
24 else if (req.params) {
25 q += '/%s.%s'.format(req.params[1], req.params[2]);
28 return L.Request.post(rpcBaseURL + q, req, {
29 timeout: (L.env.rpctimeout || 5) * 1000,
34 parseCallReply: function(req, res) {
37 if (res instanceof Error)
38 return req.reject(res);
42 L.raise('RPCError', 'RPC call to %s/%s failed with HTTP error %d: %s',
43 req.object, req.method, res.status, res.statusText || '?');
52 * The interceptor args are intentionally swapped.
53 * Response is passed as first arg to align with Request class interceptors
55 Promise.all(rpcInterceptorFns.map(function(fn) { return fn(msg, req) }))
56 .then(this.handleCallReply.bind(this, req, msg))
60 handleCallReply: function(req, msg) {
61 var type = Object.prototype.toString,
65 /* verify message frame */
66 if (!L.isObject(msg) || msg.jsonrpc != '2.0')
67 L.raise('RPCError', 'RPC call to %s/%s returned invalid message frame',
68 req.object, req.method);
70 /* check error condition */
71 if (L.isObject(msg.error) && msg.error.code && msg.error.message)
72 L.raise('RPCError', 'RPC call to %s/%s failed with error %d: %s',
73 req.object, req.method, msg.error.code, msg.error.message || '?');
79 if (!req.object && !req.method) {
82 else if (Array.isArray(msg.result)) {
83 ret = (msg.result.length > 1) ? msg.result[1] : msg.result[0];
87 for (var key in req.expect) {
88 if (ret != null && key != '')
91 if (ret == null || type.call(ret) != type.call(req.expect[key]))
92 ret = req.expect[key];
99 if (typeof(req.filter) == 'function') {
101 req.priv[1] = req.params;
102 ret = req.filter.apply(this, req.priv);
113 params: arguments.length ? this.varargs(arguments) : undefined
116 return new Promise(L.bind(function(resolveFn, rejectFn) {
117 /* store request info */
124 this.call(msg, this.parseCallReply.bind(this, req));
128 declare: function(options) {
129 return Function.prototype.bind.call(function(rpc, options) {
130 var args = this.varargs(arguments, 2);
131 return new Promise(function(resolveFn, rejectFn) {
132 /* build parameter object */
135 if (Array.isArray(options.params))
136 for (p_off = 0; p_off < options.params.length; p_off++)
137 params[options.params[p_off]] = args[p_off];
139 /* all remaining arguments are private args */
140 var priv = [ undefined, undefined ];
141 for (; p_off < args.length; p_off++)
142 priv.push(args[p_off]);
144 /* store request info */
146 expect: options.expect,
147 filter: options.filter,
152 object: options.object,
153 method: options.method
156 /* build message object */
170 rpc.call(msg, rpc.parseCallReply.bind(rpc, req));
172 }, this, this, options);
175 getSessionID: function() {
179 setSessionID: function(sid) {
183 getBaseURL: function() {
187 setBaseURL: function(url) {
191 getStatusText: function(statusCode) {
192 switch (statusCode) {
193 case 0: return _('Command OK');
194 case 1: return _('Invalid command');
195 case 2: return _('Invalid argument');
196 case 3: return _('Method not found');
197 case 4: return _('Resource not found');
198 case 5: return _('No data received');
199 case 6: return _('Permission denied');
200 case 7: return _('Request timeout');
201 case 8: return _('Not supported');
202 case 9: return _('Unspecified error');
203 case 10: return _('Connection lost');
204 default: return _('Unknown error code');
208 addInterceptor: function(interceptorFn) {
209 if (typeof(interceptorFn) == 'function')
210 rpcInterceptorFns.push(interceptorFn);
211 return interceptorFn;
214 removeInterceptor: function(interceptorFn) {
215 var oldlen = rpcInterceptorFns.length, i = oldlen;
217 if (rpcInterceptorFns[i] === interceptorFn)
218 rpcInterceptorFns.splice(i, 1);
219 return (rpcInterceptorFns.length < oldlen);