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