Roll src/third_party/WebKit 3529d49:06e8485 (svn 202554:202555)
[chromium-blink-merge.git] / remoting / webapp / crd / js / it2me_host_facade.js
blobc9167c84905941f460c73c757468cea0ec2b06db
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 {?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   /** @private {?function():void} */
44   this.onInitialized_ = function() {};
46   /**
47    * Called if Native Messaging host has failed to start.
48    * @private
49    * */
50   this.onInitializationFailed_ = function() {};
52   /**
53    * Called if the It2Me Native Messaging host sends a malformed message:
54    * missing required attributes, attributes with incorrect types, etc.
55    * @private {?function(!remoting.Error):void}
56    */
57   this.onError_ = function(error) {};
59   /** @private {?function(remoting.HostSession.State):void} */
60   this.onStateChanged_ = function() {};
62   /** @private {?function(boolean):void} */
63   this.onNatPolicyChanged_ = function() {};
65   /** @private */
66   this.debugMessageHandler_ =
67       new remoting.NativeMessageHostDebugMessageHandler();
71 remoting.It2MeHostFacade.prototype.dispose = function() {
72   base.dispose(this.eventHooks_);
73   this.eventHooks_ = null;
74   if (this.port_) {
75     this.port_.disconnect();
76     this.port_ = null;
77   }
80 /**
81  * Sets up connection to the Native Messaging host process and exchanges
82  * 'hello' messages. If Native Messaging is not supported or if the it2me
83  * native messaging host is not installed, onInitializationFailed is invoked.
84  * Otherwise, onInitialized is invoked.
85  *
86  * @param {function(*=):void} onInitialized Called after successful
87  *     initialization.
88  * @param {function(*=):void} onInitializationFailed Called if cannot connect to
89  *     the native messaging host.
90  * @return {void}
91  */
92 remoting.It2MeHostFacade.prototype.initialize =
93     function(onInitialized, onInitializationFailed) {
94   this.onInitialized_ = onInitialized;
95   this.onInitializationFailed_ = onInitializationFailed;
97   try {
98     this.port_ = chrome.runtime.connectNative(
99         'com.google.chrome.remote_assistance');
100     this.eventHooks_ = new base.Disposables(
101         new base.ChromeEventHook(this.port_.onMessage,
102                                  this.onIncomingMessage_.bind(this)),
103         new base.ChromeEventHook(this.port_.onDisconnect,
104                                  this.onHostDisconnect_.bind(this)));
105     this.port_.postMessage({type: 'hello'});
106   } catch (/** @type {*} */ err) {
107     console.log('Native Messaging initialization failed: ', err);
108     onInitializationFailed();
109     return;
110   }
114  * @param {string} email The user's email address.
115  * @param {string} authServiceWithToken Concatenation of the auth service
116  *     (e.g. oauth2) and the access token.
117  * @param {function(remoting.HostSession.State):void} onStateChanged Callback to
118  *     invoke when the host state changes.
119  * @param {function(boolean):void} onNatPolicyChanged Callback to invoke when
120  *     the nat traversal policy changes.
121  * @param {function(string):void} logDebugInfo Callback allowing the plugin
122  *     to log messages to the debug log.
123  * @param {string} xmppServerAddress XMPP server host name (or IP address) and
124  *     port.
125  * @param {boolean} xmppServerUseTls Whether to use TLS on connections to the
126  *     XMPP server
127  * @param {string} directoryBotJid XMPP JID for the remoting directory server
128  *     bot.
129  * @param {function(!remoting.Error):void} onError Callback to invoke in case of
130  *     an error.
131  * @return {void}
132  */
133 remoting.It2MeHostFacade.prototype.connect =
134     function(email, authServiceWithToken, onStateChanged, onNatPolicyChanged,
135              logDebugInfo, xmppServerAddress, xmppServerUseTls, directoryBotJid,
136              onError) {
137   if (!this.port_) {
138     console.error(
139         'remoting.It2MeHostFacade.connect() without initialization.');
140     onError(remoting.Error.unexpected());
141     return;
142   }
144   this.onStateChanged_ = onStateChanged;
145   this.onNatPolicyChanged_ = onNatPolicyChanged;
146   this.onError_ = onError;
147   this.port_.postMessage({
148     type: 'connect',
149     userName: email,
150     authServiceWithToken: authServiceWithToken,
151     xmppServerAddress: xmppServerAddress,
152     xmppServerUseTls: xmppServerUseTls,
153     directoryBotJid: directoryBotJid
154   });
158  * Unhooks the |onStateChanged|, |onError|, |onNatPolicyChanged| and
159  * |onInitalized| callbacks.  This is called when the client shuts down so that
160  * the callbacks will not be invoked on a disposed client.
162  * @return {void}
163  */
164 remoting.It2MeHostFacade.prototype.unhookCallbacks = function() {
165   this.onStateChanged_ = null;
166   this.onNatPolicyChanged_ = null;
167   this.onError_ = null;
168   this.onInitialized_ = null;
172  * @return {void}
173  */
174 remoting.It2MeHostFacade.prototype.disconnect = function() {
175   if (this.port_)
176     this.port_.postMessage({type: 'disconnect'});
180  * @return {boolean}
181  */
182 remoting.It2MeHostFacade.prototype.initialized = function() {
183   return this.initialized_;
187  * @return {string}
188  */
189 remoting.It2MeHostFacade.prototype.getAccessCode = function() {
190   return this.accessCode_;
194  * @return {number}
195  */
196 remoting.It2MeHostFacade.prototype.getAccessCodeLifetime = function() {
197   return this.accessCodeLifetime_;
201  * @return {string}
202  */
203 remoting.It2MeHostFacade.prototype.getClient = function() {
204   return this.clientId_;
208  * Handler for incoming messages.
210  * @param {Object} message The received message.
211  * @return {void}
212  * @private
213  */
214 remoting.It2MeHostFacade.prototype.onIncomingMessage_ =
215     function(message) {
216   if (this.debugMessageHandler_.handleMessage(message)) {
217     return;
218   }
220   var type = base.getStringAttr(message, 'type');
222   switch (type) {
223     case 'helloResponse':
224       var version = base.getStringAttr(message, 'version');
225       console.log('Host version: ', version);
226       this.initialized_ = true;
227       // A "hello" request is sent immediately after the native messaging host
228       // is started. We can proceed to the next task once we receive the
229       // "helloReponse".
230       if (this.onInitialized_) {
231         this.onInitialized_();
232       }
233       break;
235     case 'connectResponse':
236       console.log('connectResponse received');
237       // Response to the "connect" request. No action is needed until we
238       // receive the corresponding "hostStateChanged" message.
239       break;
241     case 'disconnectResponse':
242       console.log('disconnectResponse received');
243       // Response to the "disconnect" request. No action is needed until we
244       // receive the corresponding "hostStateChanged" message.
245       break;
247     case 'hostStateChanged':
248       var stateString = base.getStringAttr(message, 'state');
249       var errorMessage = base.getStringAttr(message, 'error_message', '');
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 = base.getStringAttr(message, 'accessCode');
256           var accessCodeLifetime =
257               base.getNumberAttr(message, 'accessCodeLifetime');
258           this.onReceivedAccessCode_(accessCode, accessCodeLifetime);
259           break;
261         case remoting.HostSession.State.CONNECTED:
262           var client = base.getStringAttr(message, 'client');
263           this.onConnected_(client);
264           break;
265       }
266       if (this.onStateChanged_) {
267         this.onStateChanged_(state);
268       }
269       break;
271     case 'natPolicyChanged':
272       if (this.onNatPolicyChanged_) {
273         var natTraversalEnabled =
274             base.getBooleanAttr(message, 'natTraversalEnabled');
275         this.onNatPolicyChanged_(natTraversalEnabled);
276       }
277       break;
279     case 'error':
280       console.error(base.getStringAttr(message, 'description'));
281       if (this.onError_) {
282         this.onError_(remoting.Error.unexpected());
283       }
284       break;
286     default:
287       throw 'Unexpected native message: ' + message;
288   }
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;
304  * @param {string} clientId
305  * @return {void}
306  * @private
307  */
308 remoting.It2MeHostFacade.prototype.onConnected_ = function(clientId) {
309   this.clientId_ = clientId;
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   }
334 })();