120e32dfa5ef96947edd02b100e180af96a1b3d1
[profile/ivi/SettingsApp.git] / js / websocket.js
1 /*
2  * Copyright (c) 2013, Intel Corporation.
3  *
4  * This program is licensed under the terms and conditions of the
5  * Apache License, version 2.0.  The full text of the Apache License is at
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  */
9
10 /* Dummy backend for faking websocket daemon */
11 var dummyBackend = false;
12
13 var WS_REQUEST_TYPE = {
14     WIFI: "wifi",
15     BLUETOOTH: "bluetooth",
16     DISPLAY: "display",
17     SOUND: "sound",
18     DATETIME: "clock",
19     LOCALE: "locale"
20 };
21
22 var WS_EVENT_TYPE = {
23     WIFI: "wifi",
24     BLUETOOTH: "bluetooth",
25     DISPLAY: "display",
26     SOUND: "sound",
27     DATETIME: "clock",
28     LOCALE: "locale"
29 };
30
31 /* web socket module to connect to the settings daemon */
32 var wsAPI = (function() {
33     /* number of connection retries to attempt if the socket closes */
34     var self = this;
35     this.connected = false;
36     this.event_callbacks = $.Callbacks();
37
38     /* default values for WebSocket */
39     this.socketUrl = 'ws://localhost:16000/';
40     this.socketProtocol = 'http-only';
41
42     this.methodIdx = 0;
43     this.methodCalls = [];
44     for (var i = 0; i < 100; i++) {
45         this.methodCalls[i] = null;
46     }
47
48     this.MethodCall = function(id, name, success_cb, error_cb) {
49         var me = this;
50         this.successCB = success_cb;
51         this.errorCB = error_cb;
52         this.transactionid = id;
53         this.name = name;
54         this.done = false;
55         this.start = function() {
56             me.timeout = setTimeout(function() {
57                 if (me.errorCB !== undefined) {
58                     me.errorCB('\"' + me.name + '\" method timed out after ' + self.timeouttime + 'ms');
59                 }
60                 me.finish();
61             }, self.timeouttime);
62         }
63         this.finish = function() {
64             if (me.timeout !== undefined) {
65                 clearTimeout(me.timeout);
66             }
67             me.done = true;
68         }
69     }
70
71     this.EventObject = function(type, name, value) {
72         var me = this;
73         this.type = type;
74         this.name = name;
75         this.value = value;
76     }
77
78     function connect(url, protocol, sucess_cb, error_cb) {
79         self.socketUrl = typeof url !== 'undefined' ? url : self.socketUrl;
80         self.socketProtocol = typeof protocol !== 'undefined' ? protocol : self.socketProtocol;
81         self.successCB = sucess_cb;
82         self.errorCB = error_cb;
83
84         if ('WebSocket' in window) {
85             if (self.socketProtocol.length > 0) {
86                 self.socket = new WebSocket(self.socketUrl, self.socketProtocol);
87             } else {
88                 self.socket = new WebSocket(self);
89             }
90             console.log('Connecting to websocket: ' + self.socketUrl);
91
92             self.socket.onopen = function() {
93                 self.connected = true;
94                 console.log('websocket opened');
95                 self.successCB();
96             };
97
98             self.socket.onclose = function() {
99                 self.connected = false;
100                 console.log('websocket closed');
101
102                 if (dummyBackend) {
103                     /* fake the connection for dummy backend */
104                     self.connected = true;
105                     self.successCB();
106                     return;
107                 }
108
109                 self.errorCB('Disconnected from settings daemon');
110             };
111
112             self.socket.onerror = function(e) {
113                 console.log('web socket error: ', e.data);
114
115                 if (dummyBackend) {
116                     /* ignore websocket error */
117                     return;
118                 }
119
120                 if (e.data) {
121                     self.errorCB('websocket error: ' + e.data);
122                 } else {
123                     self.errorCB('websocket error: unknown');
124                 }
125             };
126
127             self.socket.onmessage = function(e) {
128                 self.receive(e.data);
129             };
130         } else {
131             console.log('Websockets not supported');
132         }
133     }
134
135     function send(msg, success_cb, error_cb) {
136         if (!this.connected) {
137             if (errorCB !== undefined) {
138                 errorCB('Settings daemon is not connected');
139             }
140             return;
141         }
142         var i = this.methodIdx;
143         this.methodIdx = (this.methodIdx + 1) % 100;
144         this.methodCalls[i] = new this.MethodCall(msg.transactionid, msg.name, success_cb, error_cb);
145         this.methodCalls[i].start();
146
147         var jsonMsg = JSON.stringify(msg);
148         console.log('Sending json msg: ' + jsonMsg);
149         if (dummyBackend) {
150             /* fake with dummy data */
151             dummyBackendSend(msg);
152         } else {
153             this.socket.send(jsonMsg);
154         }
155     }
156
157     function fireEvent(type, name, value) {
158         var event = new this.EventObject(type, name, value);
159         console.log('Fire event: [' + type + ', ' + name + ', ' + value + ']');
160         event_callbacks.fire(event);
161     }
162
163     function receive(msg) {
164         var self = this;
165         var event;
166         try {
167             console.log("Received json msg: " + msg);
168             event = JSON.parse(msg);
169         } catch (e) {
170             self.iErrorCB('GARBAGE MESSAGE: ' + msg);
171             return;
172         }
173
174         if ((event === undefined) || (event.type === undefined) || (event.name === undefined)) {
175             self.iErrorCB('BADLY FORMED MESSAGE: ' + msg);
176             return;
177         } else {
178             if (event.type === 'methodReply') {
179                 var calls = this.methodCalls;
180                 for (var i = 0; i < calls.length; i++) {
181                     var call = calls[i];
182                     if (call && (!call.done) && (call.transactionid === event.transactionid)) {
183                         call.finish();
184                         if (event.error !== undefined) {
185                             call.errorCB(event.error);
186                         }
187                         if (event.data !== undefined && call.successCB !== undefined) {
188                             call.successCB(event.data);
189                         }
190                         return;
191                     }
192                 }
193             } else if (event.type === 'event') {
194                 self.fireSevent(event.name, event.data);
195             }
196         }
197     }
198
199     function generateTransactionId() {
200         var i, val = [];
201         for (i = 0; i < 8; i++) {
202             var num = Math.floor((Math.random() + 1) * 65536);
203             val[i] = num.toString(16).substring(1);
204         }
205         var uuid = val[0] + val[1] + '-' + val[2] + '-' + val[3] + '-' + val[4] + '-' + val[5] + val[6] + val[7];
206         return uuid;
207     }
208
209     function sendRequest(request_type, request_name, request_args, success_cb, error_cb) {
210         var msg = {
211             'type': request_type,
212             'name': request_name,
213             'transactionid': generateTransactionId(),
214             'data': request_args
215         };
216
217         send(msg, success_cb, error_cb);
218     }
219
220     function subscribeEvents(callback) {
221         event_callbacks.add(callback);
222     }
223
224     function unsubscribeEvents(callback) {
225         event_callbacks.remove(callback);
226     }
227
228     /* this is dummy data for testing purposes */
229     function dummyBackendSend(msg) {
230         if (dummyBackend) {
231             console.log('Sending to dummy server');
232
233             var calls = this.methodCalls;
234             var replyMsg = null;
235
236             for (var i = 0; i < calls.length; i++) {
237                 var call = calls[i];
238                 if (call && (!call.done) && (call.transactionid === msg.transactionid)) {
239                     call.finish();
240                     if (msg.error !== undefined) {
241                         call.errorCB(msg.error);
242                     }
243                     if (msg.data !== undefined && call.successCB && call.errorCB !== undefined) {
244                         var replyDelay = 0;
245
246                         switch (msg.type) {
247                         case WS_REQUEST_TYPE.WIFI:
248                             if (msg.name === 'isEnabled') {
249                                 /* default to enabled */
250                                 var results = {
251                                     'isEnabled': true
252                                 };
253                                 replyMsg = JSON.stringify(results);
254                             } else if (msg.name === 'enable') {
255                                 if (msg.data === true) {
256                                     fireEvent(WS_EVENT_TYPE.WIFI, 'enabled', true);
257                                 } else {
258                                     fireEvent(WS_EVENT_TYPE.WIFI, 'enabled', false);
259                                 }
260                             } else if (msg.name === 'scan') {
261                                 var results = {
262                                     "services" : [
263                                         [
264                                             "/net/connman/service/ethernet_0010f32f5a70_cable",
265                                             {
266                                             }
267                                         ],
268                                         [
269                                             "/net/connman/service/wifi_c8f733acdf96_3558364737_managed_psk",
270                                             {
271                                             }
272                                         ],
273                                         [
274                                             "/net/connman/service/wifi_c8f733acdf96_446f75636865626167_managed_psk",
275                                             {
276                                                 "Type" : "wifi",
277                                                 "Security" : [
278                                                     "psk"
279                                                 ],
280                                                 "State" : "idle",
281                                                 "Strength" : 50,
282                                                 "Favorite" : false,
283                                                 "Immutable" : false,
284                                                 "AutoConnect" : false,
285                                                 "Name" : "Foo",
286                                                 "BSSID" : "21:ef:30:b9:ad:86",
287                                                 "MaxRate" : 54000000,
288                                                 "Frequency" : 2417,
289                                                 "EncryptionMode" : "aes",
290                                                 "Ethernet" : {
291                                                     "Method" : "auto",
292                                                     "Interface" : "wlp1s0",
293                                                     "Address" : "E8:F2:33:AC:DF:96",
294                                                     "MTU" : 1500
295                                                 },
296                                                 "IPv4" : {
297                                                 },
298                                                 "IPv4.Configuration" : {
299                                                     "Method" : "dhcp"
300                                                 },
301                                                 "IPv6" : {
302                                                 },
303                                                 "IPv6.Configuration" : {
304                                                     "Method" : "auto",
305                                                     "Privacy" : "disabled"
306                                                 },
307                                                 "Nameservers" : [
308                                                 ],
309                                                 "Nameservers.Configuration" : [
310                                                 ],
311                                                 "Timeservers" : [
312                                                 ],
313                                                 "Timeservers.Configuration" : [
314                                                 ],
315                                                 "Domains" : [
316                                                 ],
317                                                 "Domains.Configuration" : [
318                                                 ],
319                                                 "Proxy" : {
320                                                 },
321                                                 "Proxy.Configuration" : {
322                                                 },
323                                                 "Provider" : {
324                                                 }
325                                             }
326                                         ],
327                                         [
328                                             "/net/connman/service/wifi_c8f733acdf96_536563757265446f75636865626167_managed_psk",
329                                             {
330                                             }
331                                         ]
332                                     ]
333                                 }
334
335                                 replyMsg = JSON.stringify(results);
336                                 /* simulate scan behavior */
337                                 replyDelay = 2000;
338                             } else if (msg.name === 'connect') {
339                                 replyMsg = msg.data;
340                                 fireEvent(WS_EVENT_TYPE.WIFI, 'connecting', replyMsg);
341                                 setTimeout(function() {
342                                     fireEvent(WS_EVENT_TYPE.WIFI, 'connected', replyMsg);
343                                 }, 1000);
344                             } else if (msg.name === 'disconnect') {
345                                 replyMsg = msg.data;
346                                 fireEvent(WS_EVENT_TYPE.WIFI, 'disconnecting', replyMsg);
347                                 setTimeout(function() {
348                                     fireEvent(WS_EVENT_TYPE.WIFI, 'disconnected', replyMsg);
349                                 }, 1000);
350                             } else {
351                                 call.errorCB('Unsupported request name: ' + msg.name);
352                                 return;
353                             }
354                             break;
355                         case WS_REQUEST_TYPE.BLUETOOTH:
356                             if (msg.name === 'enable') {
357                                 fireEvent(WS_EVENT_TYPE.BLUETOOTH, 'enabled', true);
358                             } else if (msg.name === 'disable') {
359                                 fireEvent(WS_EVENT_TYPE.BLUETOOTH, 'enabled', false);
360                             } else {
361                                 call.errorCB('Unsupported request name: ' + msg.name);
362                                 return;
363                             }
364                             break;
365                         case WS_REQUEST_TYPE.DATETIME:
366                             break;
367                         case WS_REQUEST_TYPE.DISPLAY:
368                         case WS_REQUEST_TYPE.SOUND:
369                         case WS_REQUEST_TYPE.LOCALE:
370                             call.errorCB('Request not implemented');
371                             return;
372                         default:
373                             call.errorCB('Invalid request type: ' + msg.type);
374                             return;
375                         }
376                         setTimeout(function() {
377                             call.successCB(replyMsg);
378                         }, replyDelay);
379                     }
380                     return;
381                 }
382             }
383         }
384     }
385
386     return {
387         connect: connect,
388         sendRequest: sendRequest,
389         subscribeEvents: subscribeEvents
390     }
391 })();