Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / remoting / webapp / host_it2me_native_messaging.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.HostIt2MeNativeMessaging = function() {
19   /**
20    * @type {number}
21    * @private
22    */
23   this.nextId_ = 0;
24
25   /**
26    * @type {?chrome.extension.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.onHostStarted_ = function() {};
60
61   /**
62    * Called if Native Messaging host has failed to start.
63    * @param {remoting.Error} error
64    * @private
65    * */
66   this.onHostInitFailed_ = function(error) {};
67
68   /**
69    * Called if the It2Me Native Messaging host sends a malformed message:
70    * missing required attributes, attributes with incorrect types, etc.
71    * @param {remoting.Error} error
72    * @private
73    */
74   this.onError_ = function(error) {};
75
76   /**
77    * @type {function(remoting.HostSession.State):void}
78    * @private
79    */
80   this.onStateChanged_ = function() {};
81
82   /**
83    * @type {function(boolean):void}
84    * @private
85    */
86   this.onNatPolicyChanged_ = function() {};
87 };
88
89 /**
90  * Sets up connection to the Native Messaging host process and exchanges
91  * 'hello' messages. If Native Messaging is not supported or if the it2me
92  * native messaging host is not installed, onHostInitFailed is invoked.
93  * Otherwise, onHostStarted is invoked.
94  *
95  * @param {function():void} onHostStarted Called after successful
96  *     initialization.
97  * @param {function(remoting.Error):void} onHostInitFailed Called if cannot
98  *      connect to host.
99  * @param {function(remoting.Error):void} onError Called on host error after
100  *     successfully connecting to the host.
101  * @return {void}
102  */
103 remoting.HostIt2MeNativeMessaging.prototype.initialize =
104     function(onHostStarted, onHostInitFailed, onError) {
105   this.onHostStarted_ = onHostStarted;
106   this.onHostInitFailed_ = onHostInitFailed;
107   this.onError_ = onError;
108
109   try {
110     this.port_ = chrome.runtime.connectNative(
111         'com.google.chrome.remote_assistance');
112     this.port_.onMessage.addListener(this.onIncomingMessage_.bind(this));
113     this.port_.onDisconnect.addListener(this.onHostDisconnect_.bind(this));
114     this.postMessage_({type: 'hello'});
115   } catch (err) {
116     console.log('Native Messaging initialization failed: ',
117                 /** @type {*} */ (err));
118     onHostInitFailed(remoting.Error.UNEXPECTED);
119     return;
120   }
121 };
122
123 /**
124  * Attaches a new ID to the supplied message, and posts it to the Native
125  * Messaging port.
126  * |message| should have its 'type' field set, and any other fields set
127  * depending on the message type.
128  *
129  * @param {{type: string}} message The message to post.
130  * @return {void}
131  * @private
132  */
133 remoting.HostIt2MeNativeMessaging.prototype.postMessage_ =
134     function(message) {
135   var id = this.nextId_++;
136   message['id'] = id;
137   this.port_.postMessage(message);
138 };
139
140 /**
141  * Handler for incoming Native Messages.
142  *
143  * @param {Object} message The received message.
144  * @return {void}
145  * @private
146  */
147 remoting.HostIt2MeNativeMessaging.prototype.onIncomingMessage_ =
148     function(message) {
149   try {
150     this.handleIncomingMessage_(message);
151   } catch (e) {
152     console.error(/** @type {*} */ (e));
153     this.onError_(remoting.Error.UNEXPECTED);
154   }
155 }
156
157 /**
158  * Handler for incoming Native Messages.
159  *
160  * @param {Object} message The received message.
161  * @return {void}
162  * @private
163  */
164 remoting.HostIt2MeNativeMessaging.prototype.handleIncomingMessage_ =
165     function(message) {
166   var type = getStringAttr(message, 'type');
167
168   switch (type) {
169     case 'helloResponse':
170       var version = getStringAttr(message, 'version');
171       console.log('Host version: ', version);
172       this.initialized_ = true;
173       // A "hello" request is sent immediately after the native messaging host
174       // is started. We can proceed to the next task once we receive the
175       // "helloReponse".
176       this.onHostStarted_();
177       break;
178
179     case 'connectResponse':
180       console.log('connectResponse received');
181       // Response to the "connect" request. No action is needed until we
182       // receive the corresponding "hostStateChanged" message.
183       break;
184
185     case 'disconnectResponse':
186       console.log('disconnectResponse received');
187       // Response to the "disconnect" request. No action is needed until we
188       // receive the corresponding "hostStateChanged" message.
189       break;
190
191     case 'hostStateChanged':
192       var stateString = getStringAttr(message, 'state');
193       console.log('hostStateChanged received: ', stateString);
194       var state = remoting.HostSession.State.fromString(stateString);
195
196       switch (state) {
197         case remoting.HostSession.State.RECEIVED_ACCESS_CODE:
198           var accessCode = getStringAttr(message, 'accessCode');
199           var accessCodeLifetime = getNumberAttr(message, 'accessCodeLifetime');
200           this.onReceivedAccessCode_(accessCode, accessCodeLifetime);
201           break;
202
203         case remoting.HostSession.State.CONNECTED:
204           var client = getStringAttr(message, 'client');
205           this.onConnected_(client);
206           break;
207       }
208       this.onStateChanged_(state);
209       break;
210
211     case 'natPolicyChanged':
212       var natTraversalEnabled = getBooleanAttr(message, 'natTraversalEnabled');
213       this.onNatPolicyChanged_(natTraversalEnabled);
214       break;
215
216     case 'error':
217       console.error(getStringAttr(message, 'description'));
218       this.onError_(remoting.Error.UNEXPECTED);
219       break;
220
221     default:
222       throw 'Unexpected native message: ' + message;
223   }
224 };
225
226 /**
227  * @param {string} email The user's email address.
228  * @param {string} authServiceWithToken Concatenation of the auth service
229  *     (e.g. oauth2) and the access token.
230  * @param {function(remoting.HostSession.State):void} onStateChanged Callback to
231  *     invoke when the host state changes.
232  * @param {function(boolean):void} onNatPolicyChanged Callback to invoke when
233  *     the nat traversal policy changes.
234  * @param {string} xmppServerAddress XMPP server host name (or IP address) and
235  *     port.
236  * @param {boolean} xmppServerUseTls Whether to use TLS on connections to the
237  *     XMPP server
238  * @param {string} directoryBotJid XMPP JID for the remoting directory server
239  *     bot.
240  * @return {void}
241  */
242 remoting.HostIt2MeNativeMessaging.prototype.connect =
243     function(email, authServiceWithToken, onStateChanged, onNatPolicyChanged,
244              xmppServerAddress, xmppServerUseTls, directoryBotJid) {
245   this.onStateChanged_ = onStateChanged;
246   this.onNatPolicyChanged_ = onNatPolicyChanged;
247   this.postMessage_({
248       type: 'connect',
249       userName: email,
250       authServiceWithToken: authServiceWithToken,
251       xmppServerAddress: xmppServerAddress,
252       xmppServerUseTls: xmppServerUseTls,
253       directoryBotJid: directoryBotJid});
254 };
255
256 /**
257  * @return {void}
258  */
259 remoting.HostIt2MeNativeMessaging.prototype.disconnect =
260     function() {
261   this.postMessage_({
262       type: 'disconnect'});
263 };
264
265 /**
266  * @param {string} accessCode
267  * @param {number} accessCodeLifetime
268  * @return {void}
269  * @private
270  */
271 remoting.HostIt2MeNativeMessaging.prototype.onReceivedAccessCode_ =
272     function(accessCode, accessCodeLifetime) {
273   this.accessCode_ = accessCode;
274   this.accessCodeLifetime_ = accessCodeLifetime;
275 };
276
277 /**
278  * @param {string} clientId
279  * @return {void}
280  * @private
281  */
282 remoting.HostIt2MeNativeMessaging.prototype.onConnected_ =
283     function(clientId) {
284   this.clientId_ = clientId;
285 };
286
287 /**
288  * @return {void}
289  * @private
290  */
291 remoting.HostIt2MeNativeMessaging.prototype.onHostDisconnect_ = function() {
292   if (!this.initialized_) {
293     var error = (chrome.runtime.lastError.message ==
294                  remoting.NATIVE_MESSAGING_HOST_NOT_FOUND_ERROR)
295                     ? remoting.Error.MISSING_PLUGIN
296                     : remoting.Error.UNEXPECTED;
297     console.error('Native Messaging initialization failed.');
298     this.onHostInitFailed_(error);
299   } else {
300     console.error('Native Messaging port disconnected.');
301     this.onError_(remoting.Error.UNEXPECTED);
302   }
303 }
304
305 /**
306  * @return {string}
307  */
308 remoting.HostIt2MeNativeMessaging.prototype.getAccessCode = function() {
309   return this.accessCode_
310 };
311
312 /**
313  * @return {number}
314  */
315 remoting.HostIt2MeNativeMessaging.prototype.getAccessCodeLifetime = function() {
316   return this.accessCodeLifetime_
317 };
318
319 /**
320  * @return {string}
321  */
322 remoting.HostIt2MeNativeMessaging.prototype.getClient = function() {
323   return this.clientId_;
324 };