Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / remoting / webapp / it2me_host_facade.js
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6  * @fileoverview
7  * Class to communicate with the It2me Host component via Native Messaging.
8  */
9
10 'use strict';
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 /**
16  * @constructor
17  */
18 remoting.It2MeHostFacade = function() {
19   /**
20    * @type {number}
21    * @private
22    */
23   this.nextId_ = 0;
24
25   /**
26    * @type {?chrome.runtime.Port}
27    * @private
28    */
29   this.port_ = null;
30
31   /**
32    * @type {string}
33    * @private
34    */
35   this.accessCode_ = '';
36
37   /**
38    * @type {number}
39    * @private
40    */
41   this.accessCodeLifetime_ = 0;
42
43   /**
44    * @type {string}
45    * @private
46    */
47   this.clientId_ = '';
48
49   /**
50    * @type {boolean}
51    * @private
52    */
53   this.initialized_ = false;
54
55   /**
56    * @type {?function():void}
57  * @private
58    */
59   this.onInitialized_ = function() {};
60
61   /**
62    * Called if Native Messaging host has failed to start.
63    * @private
64    * */
65   this.onInitializationFailed_ = function() {};
66
67   /**
68    * Called if the It2Me Native Messaging host sends a malformed message:
69    * missing required attributes, attributes with incorrect types, etc.
70    * @param {remoting.Error} error
71    * @private
72    */
73   this.onError_ = function(error) {};
74
75   /**
76    * @type {?function(remoting.HostSession.State):void}
77    * @private
78    */
79   this.onStateChanged_ = function() {};
80
81   /**
82    * @type {?function(boolean):void}
83    * @private
84    */
85   this.onNatPolicyChanged_ = function() {};
86 };
87
88 /**
89  * Sets up connection to the Native Messaging host process and exchanges
90  * 'hello' messages. If Native Messaging is not supported or if the it2me
91  * native messaging host is not installed, onInitializationFailed is invoked.
92  * Otherwise, onInitialized is invoked.
93  *
94  * @param {function():void} onInitialized Called after successful
95  *     initialization.
96  * @param {function():void} onInitializationFailed Called if cannot connect to
97  *     the native messaging host.
98  * @return {void}
99  */
100 remoting.It2MeHostFacade.prototype.initialize =
101     function(onInitialized, onInitializationFailed) {
102   this.onInitialized_ = onInitialized;
103   this.onInitializationFailed_ = onInitializationFailed;
104
105   try {
106     this.port_ = chrome.runtime.connectNative(
107         'com.google.chrome.remote_assistance');
108     this.port_.onMessage.addListener(this.onIncomingMessage_.bind(this));
109     this.port_.onDisconnect.addListener(this.onHostDisconnect_.bind(this));
110     this.port_.postMessage({type: 'hello'});
111   } catch (err) {
112     console.log('Native Messaging initialization failed: ',
113                 /** @type {*} */ (err));
114     onInitializationFailed();
115     return;
116   }
117 };
118
119 /**
120  * @param {string} email The user's email address.
121  * @param {string} authServiceWithToken Concatenation of the auth service
122  *     (e.g. oauth2) and the access token.
123  * @param {function(remoting.HostSession.State):void} onStateChanged Callback to
124  *     invoke when the host state changes.
125  * @param {function(boolean):void} onNatPolicyChanged Callback to invoke when
126  *     the nat traversal policy changes.
127  * @param {function(string):void} logDebugInfo Callback allowing the plugin
128  *     to log messages to the debug log.
129  * @param {string} xmppServerAddress XMPP server host name (or IP address) and
130  *     port.
131  * @param {boolean} xmppServerUseTls Whether to use TLS on connections to the
132  *     XMPP server
133  * @param {string} directoryBotJid XMPP JID for the remoting directory server
134  *     bot.
135  * @param {function(remoting.Error):void} onError Callback to invoke in case of
136  *     an error.
137  * @return {void}
138  */
139 remoting.It2MeHostFacade.prototype.connect =
140     function(email, authServiceWithToken, onStateChanged, onNatPolicyChanged,
141              logDebugInfo, xmppServerAddress, xmppServerUseTls, directoryBotJid,
142              onError) {
143   if (!this.port_) {
144     console.error(
145         'remoting.It2MeHostFacade.connect() without initialization.');
146     onError(remoting.Error.UNEXPECTED);
147     return;
148   }
149
150   this.onStateChanged_ = onStateChanged;
151   this.onNatPolicyChanged_ = onNatPolicyChanged;
152   this.onError_ = onError;
153   this.port_.postMessage({
154     type: 'connect',
155     userName: email,
156     authServiceWithToken: authServiceWithToken,
157     xmppServerAddress: xmppServerAddress,
158     xmppServerUseTls: xmppServerUseTls,
159     directoryBotJid: directoryBotJid
160   });
161 };
162
163 /**
164  * Unhooks the |onStateChanged|, |onError|, |onNatPolicyChanged| and
165  * |onInitalized| callbacks.  This is called when the client shuts down so that
166  * the callbacks will not be invoked on a disposed client.
167  *
168  * @return {void}
169  */
170 remoting.It2MeHostFacade.prototype.unhookCallbacks = function() {
171   this.onStateChanged_ = null;
172   this.onNatPolicyChanged_ = null;
173   this.onError_ = null;
174   this.onInitialized_ = null;
175 };
176
177 /**
178  * @return {void}
179  */
180 remoting.It2MeHostFacade.prototype.disconnect = function() {
181   if (this.port_)
182     this.port_.postMessage({type: 'disconnect'});
183 };
184
185 /**
186  * @return {boolean}
187  */
188 remoting.It2MeHostFacade.prototype.initialized = function() {
189   return this.initialized_;
190 };
191
192 /**
193  * @return {string}
194  */
195 remoting.It2MeHostFacade.prototype.getAccessCode = function() {
196   return this.accessCode_;
197 };
198
199 /**
200  * @return {number}
201  */
202 remoting.It2MeHostFacade.prototype.getAccessCodeLifetime = function() {
203   return this.accessCodeLifetime_;
204 };
205
206 /**
207  * @return {string}
208  */
209 remoting.It2MeHostFacade.prototype.getClient = function() {
210   return this.clientId_;
211 };
212
213 /**
214  * Handler for incoming messages.
215  *
216  * @param {Object} message The received message.
217  * @return {void}
218  * @private
219  */
220 remoting.It2MeHostFacade.prototype.onIncomingMessage_ =
221     function(message) {
222   var type = getStringAttr(message, 'type');
223
224   switch (type) {
225     case 'helloResponse':
226       var version = getStringAttr(message, 'version');
227       console.log('Host version: ', version);
228       this.initialized_ = true;
229       // A "hello" request is sent immediately after the native messaging host
230       // is started. We can proceed to the next task once we receive the
231       // "helloReponse".
232       if (this.onInitialized_) {
233         this.onInitialized_();
234       }
235       break;
236
237     case 'connectResponse':
238       console.log('connectResponse received');
239       // Response to the "connect" request. No action is needed until we
240       // receive the corresponding "hostStateChanged" message.
241       break;
242
243     case 'disconnectResponse':
244       console.log('disconnectResponse received');
245       // Response to the "disconnect" request. No action is needed until we
246       // receive the corresponding "hostStateChanged" message.
247       break;
248
249     case 'hostStateChanged':
250       var stateString = getStringAttr(message, 'state');
251       console.log('hostStateChanged received: ', stateString);
252       var state = remoting.HostSession.State.fromString(stateString);
253
254       switch (state) {
255         case remoting.HostSession.State.RECEIVED_ACCESS_CODE:
256           var accessCode = getStringAttr(message, 'accessCode');
257           var accessCodeLifetime = getNumberAttr(message, 'accessCodeLifetime');
258           this.onReceivedAccessCode_(accessCode, accessCodeLifetime);
259           break;
260
261         case remoting.HostSession.State.CONNECTED:
262           var client = getStringAttr(message, 'client');
263           this.onConnected_(client);
264           break;
265       }
266       if (this.onStateChanged_) {
267         this.onStateChanged_(state);
268       }
269       break;
270
271     case 'natPolicyChanged':
272       if (this.onNatPolicyChanged_) {
273         var natTraversalEnabled =
274             getBooleanAttr(message, 'natTraversalEnabled');
275         this.onNatPolicyChanged_(natTraversalEnabled);
276       }
277       break;
278
279     case 'error':
280       console.error(getStringAttr(message, 'description'));
281       if (this.onError_) {
282         this.onError_(remoting.Error.UNEXPECTED);
283       }
284       break;
285
286     default:
287       throw 'Unexpected native message: ' + message;
288   }
289 };
290
291 /**
292  * @param {string} accessCode
293  * @param {number} accessCodeLifetime
294  * @return {void}
295  * @private
296  */
297 remoting.It2MeHostFacade.prototype.onReceivedAccessCode_ =
298     function(accessCode, accessCodeLifetime) {
299   this.accessCode_ = accessCode;
300   this.accessCodeLifetime_ = accessCodeLifetime;
301 };
302
303 /**
304  * @param {string} clientId
305  * @return {void}
306  * @private
307  */
308 remoting.It2MeHostFacade.prototype.onConnected_ = function(clientId) {
309   this.clientId_ = clientId;
310 };
311
312 /**
313  * @return {void}
314  * @private
315  */
316 remoting.It2MeHostFacade.prototype.onHostDisconnect_ = function() {
317   if (!this.initialized_) {
318     // If the host is disconnected before it is initialized, it probably means
319     // the host is not propertly installed (or not installed at all).
320     // E.g., if the host manifest is not present we get "Specified native
321     // messaging host not found" error. If the host manifest is present but
322     // the host binary cannot be found we get the "Native host has exited"
323     // error.
324     console.log('Native Messaging initialization failed: ' +
325                 chrome.runtime.lastError.message);
326     this.onInitializationFailed_();
327   } else {
328     console.error('Native Messaging port disconnected.');
329     this.port_ = null;
330     this.onError_(remoting.Error.UNEXPECTED);
331   }
332 }