luci2: split into submodules
[project/luci2/ui.git] / luci2 / htdocs / luci2 / rpc.js
1 Class.extend({
2         _id: 1,
3         _batch: undefined,
4         _requests: { },
5
6         _call: function(req, cb)
7         {
8                 var q = '';
9
10                 if ($.isArray(req))
11                         for (var i = 0; i < req.length; i++)
12                                 q += '%s%s.%s'.format(
13                                         q ? ';' : '/',
14                                         req[i].params[1],
15                                         req[i].params[2]
16                                 );
17                 else
18                         q += '/%s.%s'.format(req.params[1], req.params[2]);
19
20                 return $.ajax('/ubus' + q, {
21                         cache:       false,
22                         contentType: 'application/json',
23                         data:        JSON.stringify(req),
24                         dataType:    'json',
25                         type:        'POST',
26                         timeout:     L.globals.timeout,
27                         _rpc_req:   req
28                 }).then(cb, cb);
29         },
30
31         _list_cb: function(msg)
32         {
33                 var list = msg.result;
34
35                 /* verify message frame */
36                 if (typeof(msg) != 'object' || msg.jsonrpc != '2.0' || !msg.id || !$.isArray(list))
37                         list = [ ];
38
39                 return $.Deferred().resolveWith(this, [ list ]);
40         },
41
42         _call_cb: function(msg)
43         {
44                 var data = [ ];
45                 var type = Object.prototype.toString;
46                 var reqs = this._rpc_req;
47
48                 if (!$.isArray(reqs))
49                 {
50                         msg = [ msg ];
51                         reqs = [ reqs ];
52                 }
53
54                 for (var i = 0; i < msg.length; i++)
55                 {
56                         /* fetch related request info */
57                         var req = L.rpc._requests[reqs[i].id];
58                         if (typeof(req) != 'object')
59                                 throw 'No related request for JSON response';
60
61                         /* fetch response attribute and verify returned type */
62                         var ret = undefined;
63
64                         /* verify message frame */
65                         if (typeof(msg[i]) == 'object' && msg[i].jsonrpc == '2.0')
66                                 if ($.isArray(msg[i].result) && msg[i].result[0] == 0)
67                                         ret = (msg[i].result.length > 1) ? msg[i].result[1] : msg[i].result[0];
68
69                         if (req.expect)
70                         {
71                                 for (var key in req.expect)
72                                 {
73                                         if (typeof(ret) != 'undefined' && key != '')
74                                                 ret = ret[key];
75
76                                         if (typeof(ret) == 'undefined' || type.call(ret) != type.call(req.expect[key]))
77                                                 ret = req.expect[key];
78
79                                         break;
80                                 }
81                         }
82
83                         /* apply filter */
84                         if (typeof(req.filter) == 'function')
85                         {
86                                 req.priv[0] = ret;
87                                 req.priv[1] = req.params;
88                                 ret = req.filter.apply(L.rpc, req.priv);
89                         }
90
91                         /* store response data */
92                         if (typeof(req.index) == 'number')
93                                 data[req.index] = ret;
94                         else
95                                 data = ret;
96
97                         /* delete request object */
98                         delete L.rpc._requests[reqs[i].id];
99                 }
100
101                 return $.Deferred().resolveWith(this, [ data ]);
102         },
103
104         list: function()
105         {
106                 var params = [ ];
107                 for (var i = 0; i < arguments.length; i++)
108                         params[i] = arguments[i];
109
110                 var msg = {
111                         jsonrpc: '2.0',
112                         id:      this._id++,
113                         method:  'list',
114                         params:  (params.length > 0) ? params : undefined
115                 };
116
117                 return this._call(msg, this._list_cb);
118         },
119
120         batch: function()
121         {
122                 if (!$.isArray(this._batch))
123                         this._batch = [ ];
124         },
125
126         flush: function()
127         {
128                 if (!$.isArray(this._batch))
129                         return L.deferrable([ ]);
130
131                 var req = this._batch;
132                 delete this._batch;
133
134                 /* call rpc */
135                 return this._call(req, this._call_cb);
136         },
137
138         declare: function(options)
139         {
140                 var _rpc = this;
141
142                 return function() {
143                         /* build parameter object */
144                         var p_off = 0;
145                         var params = { };
146                         if ($.isArray(options.params))
147                                 for (p_off = 0; p_off < options.params.length; p_off++)
148                                         params[options.params[p_off]] = arguments[p_off];
149
150                         /* all remaining arguments are private args */
151                         var priv = [ undefined, undefined ];
152                         for (; p_off < arguments.length; p_off++)
153                                 priv.push(arguments[p_off]);
154
155                         /* store request info */
156                         var req = _rpc._requests[_rpc._id] = {
157                                 expect: options.expect,
158                                 filter: options.filter,
159                                 params: params,
160                                 priv:   priv
161                         };
162
163                         /* build message object */
164                         var msg = {
165                                 jsonrpc: '2.0',
166                                 id:      _rpc._id++,
167                                 method:  'call',
168                                 params:  [
169                                         L.globals.sid,
170                                         options.object,
171                                         options.method,
172                                         params
173                                 ]
174                         };
175
176                         /* when a batch is in progress then store index in request data
177                          * and push message object onto the stack */
178                         if ($.isArray(_rpc._batch))
179                         {
180                                 req.index = _rpc._batch.push(msg) - 1;
181                                 return L.deferrable(msg);
182                         }
183
184                         /* call rpc */
185                         return _rpc._call(msg, _rpc._call_cb);
186                 };
187         }
188 });