Added support for autoconnect for connman services
[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 ERROR_SETTINGSD_DISCONNECTED = 'Settings daemon is not connected';
14
15 var WS_REQUEST_TYPE = {
16     CONNMAN_MANAGER: "connman::manager",
17     CONNMAN_TECHNOLOGY: "connman::technology",
18     CONNMAN_SERVICE: "connman::service",
19     BLUETOOTH: "bluetooth",
20     DISPLAY: "display",
21     SOUND: "sound",
22     DATETIME: "clock",
23     LOCALE: "locale"
24 };
25
26 var WS_EVENT_TYPE = {
27     CONNMAN: "connman",
28     BLUETOOTH: "bluetooth",
29     DISPLAY: "display",
30     SOUND: "sound",
31     DATETIME: "clock",
32     LOCALE: "locale"
33 };
34
35 /* web socket module to connect to the settings daemon */
36 var wsAPI = (function() {
37     /* number of connection retries to attempt if the socket closes */
38     var self = this;
39     this.connected = false;
40     this.event_callbacks = $.Callbacks();
41
42     /* default values for WebSocket */
43     this.socketUrl = 'ws://localhost:16000/';
44     this.socketProtocol = 'http-only';
45
46     this.timeouttime = 15000;
47     this.methodIdx = 0;
48     this.methodCalls = [];
49     for (var i = 0; i < 100; i++) {
50         this.methodCalls[i] = null;
51     }
52
53     this.MethodCall = function(id, name, success_cb, error_cb) {
54         var me = this;
55         this.successCB = success_cb;
56         this.errorCB = error_cb;
57         this.transactionid = id;
58         this.name = name;
59         this.done = false;
60         this.start = function() {
61             me.timeout = setTimeout(function() {
62                 if (me.errorCB !== undefined) {
63                     me.errorCB('\"' + me.name + '\" method timed out after ' + self.timeouttime + ' ms');
64                 }
65                 me.finish();
66             }, self.timeouttime);
67         }
68         this.finish = function() {
69             if (me.timeout !== undefined) {
70                 clearTimeout(me.timeout);
71             }
72             me.done = true;
73         }
74     }
75
76     this.EventObject = function(type, id, name, value) {
77         var me = this;
78         this.type = type;
79         this.id = id;
80         this.name = name;
81         this.value = value;
82     }
83
84     function connect(url, protocol, sucess_cb, error_cb) {
85         self.socketUrl = typeof url !== 'undefined' ? url : self.socketUrl;
86         self.socketProtocol = typeof protocol !== 'undefined' ? protocol : self.socketProtocol;
87         self.successCB = sucess_cb;
88         self.errorCB = error_cb;
89
90         if ('WebSocket' in window) {
91             if (self.socketProtocol.length > 0) {
92                 self.socket = new WebSocket(self.socketUrl, self.socketProtocol);
93             } else {
94                 self.socket = new WebSocket(self);
95             }
96             console.log('Connecting to websocket: ' + self.socketUrl);
97
98             self.socket.onopen = function() {
99                 self.connected = true;
100                 console.log('websocket opened');
101                 self.successCB();
102             };
103
104             self.socket.onclose = function(code, reason, remote) {
105                 self.connected = false;
106                 console.log('websocket closed - ' + reason);
107
108                 if (dummyBackend) {
109                     /* fake the connection for dummy backend */
110                     self.connected = true;
111                     self.successCB();
112                     return;
113                 }
114
115                 self.errorCB(reason);
116             };
117
118             self.socket.onerror = function(e) {
119                 if (dummyBackend) {
120                     /* ignore websocket error */
121                     return;
122                 }
123
124                 if (e.data) {
125                     self.errorCB('websocket error: ' + e.data);
126                 } else {
127                     self.errorCB('websocket error: unknown');
128                 }
129             };
130
131             self.socket.onmessage = function(e) {
132                 receive(e.data);
133             };
134         } else {
135             console.log('Websockets not supported');
136         }
137     }
138
139     function reconnect() {
140         if (this.connected) return;
141
142         setTimeout(function() {
143             connect(self.socketUrl, self.socketProtocol, self.successCB, self.errorCB);
144         }, 1000);
145     }
146
147     function send(msg, success_cb, error_cb) {
148         if (!this.connected) {
149             if (error_cb !== undefined) {
150                 error_cb(ERROR_SETTINGSD_DISCONNECTED);
151             }
152             return;
153         }
154         var i = this.methodIdx;
155         this.methodIdx = (this.methodIdx + 1) % 100;
156         this.methodCalls[i] = new this.MethodCall(msg.transactionid, msg.name, success_cb, error_cb);
157         this.methodCalls[i].start();
158
159         var jsonMsg = JSON.stringify(msg);
160         console.log('Sending json msg: ' + jsonMsg);
161         if (dummyBackend) {
162             /* fake with dummy data */
163             dummyBackendSend(msg);
164         } else {
165             this.socket.send(jsonMsg);
166         }
167     }
168
169     function fireEvent(type, id, name, value) {
170         var event = new this.EventObject(type, id, name, value);
171         console.log('Firing ' + type + ' event id=' + id + ', name=' + name + ', value=' + value);
172         event_callbacks.fire(event);
173     }
174
175     function receive(msg) {
176         var self = this;
177         var response;
178         try {
179             console.log("Received json msg: " + msg);
180             response = JSON.parse(msg);
181         } catch (e) {
182             console.error('Garbage message: ' + msg);
183             return;
184         }
185
186         if ((response === undefined) || (response.type === undefined)) {
187             console.error('Badly formed message: ' + msg);
188         } else if (response.type === 'event' && response.value !== undefined) {
189             if (response.value.interface_name === 'net.connman.Manager' || response.value.interface_name === 'net.connman.Service' || response.value.interface_name === 'net.connman.Technology') {
190                 if (response.value.signal_name === undefined || response.value.parameters === undefined) {
191                     console.error('Badly formed event: ' + msg);
192                     return;
193                 }
194                 if (response.value.signal_name === 'ServiceChanged' && response.value.parameters.length !== 2) {
195                     console.error('Badly formed event parameters: ' + msg);
196                     return;
197                 }
198
199                 if (response.value.object_path === '/' || response.value.object_path.indexOf('/net/connman/technology/') >= 0) {
200                     fireEvent(WS_EVENT_TYPE.CONNMAN, response.value.object_path, response.value.signal_name, response.value.parameters);
201                 } else {
202                     console.error('Unrecognized event object_path, skipping');
203                 }
204             } else {
205                 console.error('Unrecognized event, skipping');
206             }
207         } else if (response.transactionid === undefined) {
208             console.error('Badly formed response: ' + msg);
209         } else {
210             var calls = this.methodCalls;
211             for (var i = 0; i < calls.length; i++) {
212                 var call = calls[i];
213                 if (call && (!call.done) && (call.transactionid === response.transactionid)) {
214                     call.finish();
215                     if (response.result !== 'succeeded' && response.reason !== undefined && call.errorCB !== undefined) {
216                         call.errorCB(response.reason);
217                     } else if (call.successCB !== undefined) {
218                         if (response.value !== undefined) {
219                             call.successCB(response.value);
220                         } else {
221                             call.successCB();
222                         }
223                     }
224                     return;
225                 }
226             }
227         }
228     }
229
230     function generateTransactionId() {
231         var i, val = [];
232         for (i = 0; i < 8; i++) {
233             var num = Math.floor((Math.random() + 1) * 65536);
234             val[i] = num.toString(16).substring(1);
235         }
236         var uuid = val[0] + val[1] + '-' + val[2] + '-' + val[3] + '-' + val[4] + '-' + val[5] + val[6] + val[7];
237         return uuid;
238     }
239
240     function sendRequest(request_type, request_name, request_args, success_cb, error_cb) {
241         var msg = {
242             'type': request_type,
243             'transactionid': generateTransactionId(),
244             'name': request_name,
245             'value': request_args
246         };
247
248         send(msg, success_cb, error_cb);
249     }
250
251     function subscribeEvents(callback) {
252         event_callbacks.add(callback);
253     }
254
255     function unsubscribeEvents(callback) {
256         event_callbacks.remove(callback);
257     }
258
259     /* this is dummy data for testing purposes */
260     function dummyBackendSend(msg) {
261         if (dummyBackend) {
262             console.log('Sending to dummy server');
263
264             var calls = this.methodCalls;
265             var replyMsg = null;
266
267             for (var i = 0; i < calls.length; i++) {
268                 var call = calls[i];
269                 if (call && (!call.done) && (call.transactionid === msg.transactionid)) {
270                     call.finish();
271                     if (msg.error !== undefined) {
272                         if (call.errorCB) {
273                             call.errorCB(msg.error);
274                         }
275                     }
276                     if (msg.value !== undefined && call.successCB !== undefined) {
277                         switch (msg.type) {
278                         case WS_REQUEST_TYPE.CONNMAN_MANAGER:
279                         case WS_REQUEST_TYPE.CONNMAN_TECHNOLOGY:
280                             if (msg.name === 'get_technologies') {
281                                 var results = [
282                                     [
283                                         ["/net/connman/technology/ethernet",
284                                         {
285                                             "Name": "Wired",
286                                             "Type": "ethernet",
287                                             "Powered": true,
288                                             "Connected": true,
289                                             "Tethering": false
290                                         }],
291                                         ["/net/connman/technology/wifi",
292                                         {
293                                             "Name": "WiFi",
294                                             "Type": "wifi",
295                                             "Powered": false,
296                                             "Connected": false,
297                                             "Tethering": false
298                                         }],
299                                         ["/net/connman/technology/bluetooth",
300                                         {
301                                             "Name": "Bluetooth",
302                                             "Type": "bluetooth",
303                                             "Powered": false,
304                                             "Connected": false,
305                                             "Tethering": false
306                                         }]
307                                     ]
308                                 ];
309
310                                 replyMsg = JSON.stringify(results);
311                                 call.successCB(results);
312                                 return;
313                             } else if (msg.name === 'enable' && msg.value[1] === true) {
314                                 call.successCB();
315                                 fireEvent(WS_EVENT_TYPE.CONNMAN, msg.value[0], 'PropertyChanged', ["Powered", true]);
316                                 return;
317                             } else if (msg.name === 'enable' && msg.value[1] === false) {
318                                 call.successCB();
319                                 fireEvent(WS_EVENT_TYPE.CONNMAN, msg.value[0], 'PropertyChanged', ["Powered", false]);
320                                 return;
321                             } else if (msg.name === 'get_services' || msg.name === 'scan') {
322                                 var results = [
323                                     [
324                                         ["/net/connman/service/ethernet_0010f32f5a70_cable",
325                                         {
326                                             "Type": "ethernet",
327                                             "Security": [],
328                                             "State": "ready",
329                                             "AutoConnect": true,
330                                             "Domains": ["ftrdhcpuser.net"],
331                                             "Domains.Configuration": [],
332                                             "Ethernet": {
333                                                 "Address": "10:20:F3:2F:5E:23",
334                                                 "Interface": "eno1",
335                                                 "MTU": 1500,
336                                                 "Method": "auto"
337                                             },
338                                             "Favorite": true,
339                                             "IPv4": {
340                                                 "Address": "192.168.1.20",
341                                                 "Gateway": "192.168.1.1",
342                                                 "Method": "dhcp",
343                                                 "Netmask": "255.255.255.0"
344                                             },
345                                             "IPv4.Configuration": {
346                                                 "Method": "dhcp"
347                                             },
348                                             "IPv6": {},
349                                             "IPv6.Configuration": {
350                                                 "Method": "auto",
351                                                 "Privacy": "disabled"
352                                             },
353                                             "Immutable": false,
354                                             "Name": "Wired",
355                                             "Nameservers": ["192.168.1.1", "184.11.12.13"],
356                                             "Nameservers.Configuration": [],
357                                             "Provider": {},
358                                             "Proxy": {
359                                                 "Method": "direct"
360                                             },
361                                             "Proxy.Configuration": {},
362                                             "Timeservers": ["192.168.1.1", "pool.ntp.org"],
363                                             "Timeservers.Configuration": []
364                                         }],
365                                         ["/net/connman/service/wifi_c8f733acdf96_3558364737_managed_psk",
366                                         {
367                                             "Type": "wifi",
368                                             "Security": ["psk"],
369                                             "State": "ready",
370                                             "Strength": 50,
371                                             "Favorite": false,
372                                             "Immutable": false,
373                                             "AutoConnect": false,
374                                             "Name": "Access Point 1",
375                                             "BSSID": "11:5d:49:88:3d:20",
376                                             "MaxRate": 54000000,
377                                             "Frequency": 2417,
378                                             "EncryptionMode": "none",
379                                             "Ethernet": {
380                                                 "Method": "auto",
381                                                 "Interface": "wlp1s0",
382                                                 "Address": "B2:D3:55:66:44:22",
383                                                 "MTU": 1500
384                                             },
385                                             "IPv4": {
386                                                 "Address": "192.168.1.20",
387                                                 "Gateway": "192.168.1.1",
388                                                 "Method": "dhcp",
389                                                 "Netmask": "255.255.255.0"
390                                             },
391                                             "IPv4.Configuration": {
392                                                 "Method": "dhcp"
393                                             },
394                                             "IPv6": {},
395                                             "IPv6.Configuration": {
396                                                 "Method": "auto",
397                                                 "Privacy": "disabled"
398                                             },
399                                             "Nameservers": [],
400                                             "Nameservers.Configuration": [],
401                                             "Timeservers": [],
402                                             "Timeservers.Configuration": [],
403                                             "Domains": [],
404                                             "Domains.Configuration": [],
405                                             "Proxy": {},
406                                             "Proxy.Configuration": {},
407                                             "Provider": {}
408                                         }],
409                                         ["/net/connman/service/wifi_c8f733acdf96_446f75636865626167_managed_psk",
410                                         {
411                                             "Type": "wifi",
412                                             "Security": ["psk"],
413                                             "State": "idle",
414                                             "Strength": 50,
415                                             "Favorite": false,
416                                             "Immutable": false,
417                                             "AutoConnect": false,
418                                             "Name": "Access Point 2",
419                                             "BSSID": "21:ef:30:b9:ad:86",
420                                             "MaxRate": 54000000,
421                                             "Frequency": 2417,
422                                             "EncryptionMode": "aes",
423                                             "Ethernet": {
424                                                 "Method": "auto",
425                                                 "Interface": "wlp1s0",
426                                                 "Address": "E8:F2:33:AC:DF:96",
427                                                 "MTU": 1500
428                                             },
429                                             "IPv4": {},
430                                             "IPv4.Configuration": {
431                                                 "Method": "dhcp"
432                                             },
433                                             "IPv6": {},
434                                             "IPv6.Configuration": {
435                                                 "Method": "auto",
436                                                 "Privacy": "disabled"
437                                             },
438                                             "Nameservers": [],
439                                             "Nameservers.Configuration": [],
440                                             "Timeservers": [],
441                                             "Timeservers.Configuration": [],
442                                             "Domains": [],
443                                             "Domains.Configuration": [],
444                                             "Proxy": {},
445                                             "Proxy.Configuration": {},
446                                             "Provider": {}
447                                         }],
448                                         ["/net/connman/service/wifi_c8f733acdf96_536563757265446f75636865626167_managed_psk",
449                                         {
450                                             "Type": "wifi",
451                                             "Security": ["psk"],
452                                             "State": "idle",
453                                             "Strength": 50,
454                                             "Favorite": false,
455                                             "Immutable": false,
456                                             "AutoConnect": false,
457                                             "Name": "Access Point 3",
458                                             "BSSID": "25:ad:44:b7:e3:66",
459                                             "MaxRate": 54000000,
460                                             "Frequency": 2417,
461                                             "EncryptionMode": "aes",
462                                             "Ethernet": {
463                                                 "Method": "auto",
464                                                 "Interface": "wlp1s0",
465                                                 "Address": "A9:28:44:AD:FF:26",
466                                                 "MTU": 1500
467                                             },
468                                             "IPv4": {},
469                                             "IPv4.Configuration": {
470                                                 "Method": "dhcp"
471                                             },
472                                             "IPv6": {},
473                                             "IPv6.Configuration": {
474                                                 "Method": "auto",
475                                                 "Privacy": "disabled"
476                                             },
477                                             "Nameservers": [],
478                                             "Nameservers.Configuration": [],
479                                             "Timeservers": [],
480                                             "Timeservers.Configuration": [],
481                                             "Domains": [],
482                                             "Domains.Configuration": [],
483                                             "Proxy": {},
484                                             "Proxy.Configuration": {},
485                                             "Provider": {}
486                                         }]
487                                     ]
488                                 ];
489
490                                 replyMsg = JSON.stringify(results);
491                                 /* simulate scan behavior */
492                                 setTimeout(function() {
493                                     call.successCB(results);
494                                 }, 2000);
495                                 return;
496                             }
497                         case WS_REQUEST_TYPE.CONNMAN_SERVICE:
498                             if (msg.name === 'connect') {
499                                 if (msg.value[0] === '/net/connman/service/wifi_c8f733acdf96_3558364737_managed_psk' && msg.value[1].Passphrase !== '123') {
500                                     call.errorCB('Invalid passphrase');
501                                 } else if (msg.value[0] === '/net/connman/service/wifi_c8f733acdf96_446f75636865626167_managed_psk' && msg.value[1].Passphrase !== '123') {
502                                     call.errorCB('Invalid passphrase');
503                                 } else {
504                                     call.successCB();
505                                     setTimeout(function() {
506                                         fireEvent(WS_EVENT_TYPE.CONNMAN, msg.value[0], 'PropertyChanged', ["Connected", true]);
507                                     }, 2000);
508                                 }
509                                 return;
510                             } else if (msg.name === 'disconnect') {
511                                 call.successCB();
512                                 setTimeout(function() {
513                                     fireEvent(WS_EVENT_TYPE.CONNMAN, msg.value[0], 'PropertyChanged', ["Connected", false]);
514                                 }, 2000);
515                                 return;
516                             } else if (msg.name === 'autoconnect') {
517                                 call.successCB();
518                                 return;
519                             } else {
520                                 if (call.errorCB) {
521                                     call.errorCB('Unsupported request: ' + msg.name + ', ' + msg.value);
522                                 }
523                                 return;
524                             }
525                             break;
526                         case WS_REQUEST_TYPE.DATETIME:
527                             if (msg.name === 'is_time_updates_auto' && msg.value !== undefined) {
528                                 /* default to manual */
529                                 call.successCB(false);
530                                 return;
531                             } else if (msg.name === 'is_timezone_updates_auto' && msg.value !== undefined) {
532                                 /* default to manual */
533                                 call.successCB(false);
534                                 return;
535                             } else if (msg.name === 'time' && msg.value !== undefined) {
536                                 call.successCB();
537                                 return;
538                             } else if (msg.name === 'timezone' && msg.value !== undefined) {
539                                 call.successCB();
540                                 return;
541                             } else if (msg.name === 'time_updates' && msg.value !== undefined) {
542                                 call.successCB();
543                                 return;
544                             } else if (msg.name === 'timezone_updates' && msg.value !== undefined) {
545                                 call.successCB();
546                                 return;
547                             } else {
548                                 if (call.errorCB) {
549                                     call.errorCB('Unsupported request: ' + msg.name + ', ' + msg.value);
550                                 }
551                                 return;
552                             }
553                             break;
554                         case WS_REQUEST_TYPE.DISPLAY:
555                         case WS_REQUEST_TYPE.SOUND:
556                         case WS_REQUEST_TYPE.LOCALE:
557                             if (call.errorCB) {
558                                 call.errorCB('Request not implemented');
559                             }
560                             return;
561                         default:
562                             if (call.errorCB) {
563                                 call.errorCB('Invalid request type: ' + msg.type);
564                             }
565                             return;
566                         }
567                     }
568                     return;
569                 }
570             }
571         }
572     }
573
574     return {
575         connect: connect,
576         reconnect: reconnect,
577         sendRequest: sendRequest,
578         subscribeEvents: subscribeEvents,
579         unsubscribeEvents: unsubscribeEvents
580     }
581 })();