3 var rpcRequestRegistry
= {},
4 rpcRequestBatch
= null,
6 rpcSessionID
= L
.env
.sessionid
|| '00000000000000000000000000000000';
8 return L
.Class
.extend({
9 call: function(req
, cbFn
) {
10 var cb
= cbFn
.bind(this, req
),
13 if (Array
.isArray(req
)) {
15 return Promise
.resolve([]);
17 for (var i
= 0; i
< req
.length
; i
++)
18 q
+= '%s%s.%s'.format(
25 q
+= '/%s.%s'.format(req
.params
[1], req
.params
[2]);
28 return L
.Request
.post(L
.url('admin/ubus') + q
, req
, {
29 timeout
: (L
.env
.rpctimeout
|| 5) * 1000,
34 handleListReply: function(req
, msg
) {
35 var list
= msg
.result
;
37 /* verify message frame */
38 if (typeof(msg
) != 'object' || msg
.jsonrpc
!= '2.0' || !msg
.id
|| !Array
.isArray(list
))
44 handleCallReply: function(reqs
, res
) {
45 var type
= Object
.prototype.toString
,
50 L
.error('RPCError', 'RPC call failed with HTTP error %d: %s',
51 res
.status
, res
.statusText
|| '?');
55 if (!Array
.isArray(reqs
)) {
60 for (var i
= 0; i
< msg
.length
; i
++) {
61 /* fetch related request info */
62 var req
= rpcRequestRegistry
[reqs
[i
].id
];
63 if (typeof(req
) != 'object')
64 throw 'No related request for JSON response';
66 /* fetch response attribute and verify returned type */
69 /* verify message frame */
70 if (typeof(msg
[i
]) == 'object' && msg
[i
].jsonrpc
== '2.0') {
71 if (typeof(msg
[i
].error
) == 'object' && msg
[i
].error
.code
&& msg
[i
].error
.message
)
72 req
.reject(new Error('RPC call failed with error %d: %s'
73 .format(msg
[i
].error
.code
, msg
[i
].error
.message
|| '?')));
74 else if (Array
.isArray(msg
[i
].result
) && msg
[i
].result
[0] == 0)
75 ret
= (msg
[i
].result
.length
> 1) ? msg
[i
].result
[1] : msg
[i
].result
[0];
78 req
.reject(new Error('Invalid message frame received'));
82 for (var key
in req
.expect
) {
83 if (ret
!= null && key
!= '')
86 if (ret
== null || type
.call(ret
) != type
.call(req
.expect
[key
]))
87 ret
= req
.expect
[key
];
94 if (typeof(req
.filter
) == 'function') {
96 req
.priv
[1] = req
.params
;
97 ret
= req
.filter
.apply(this, req
.priv
);
102 /* store response data */
103 if (typeof(req
.index
) == 'number')
104 data
[req
.index
] = ret
;
108 /* delete request object */
109 delete rpcRequestRegistry
[reqs
[i
].id
];
112 return Promise
.resolve(data
);
120 params
: arguments
.length
? this.varargs(arguments
) : undefined
123 return this.call(msg
, this.handleListReply
);
127 if (!Array
.isArray(rpcRequestBatch
))
128 rpcRequestBatch
= [ ];
132 if (!Array
.isArray(rpcRequestBatch
))
133 return Promise
.resolve([]);
135 var req
= rpcRequestBatch
;
136 rpcRequestBatch
= null;
139 return this.call(req
, this.handleCallReply
);
142 declare: function(options
) {
143 return Function
.prototype.bind
.call(function(rpc
, options
) {
144 var args
= this.varargs(arguments
, 2);
145 return new Promise(function(resolveFn
, rejectFn
) {
146 /* build parameter object */
149 if (Array
.isArray(options
.params
))
150 for (p_off
= 0; p_off
< options
.params
.length
; p_off
++)
151 params
[options
.params
[p_off
]] = args
[p_off
];
153 /* all remaining arguments are private args */
154 var priv
= [ undefined, undefined ];
155 for (; p_off
< args
.length
; p_off
++)
156 priv
.push(args
[p_off
]);
158 /* store request info */
159 var req
= rpcRequestRegistry
[rpcRequestID
] = {
160 expect
: options
.expect
,
161 filter
: options
.filter
,
168 /* build message object */
181 /* when a batch is in progress then store index in request data
182 * and push message object onto the stack */
183 if (Array
.isArray(rpcRequestBatch
))
184 req
.index
= rpcRequestBatch
.push(msg
) - 1;
188 rpc
.call(msg
, rpc
.handleCallReply
);
190 }, this, this, options
);
193 setSessionID: function(sid
) {