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.
7 * Class to communicate with the It2me Host component via Native Messaging.
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
18 remoting.HostIt2MeNativeMessaging = function() {
26 * @type {?chrome.extension.Port}
35 this.accessCode_ = '';
41 this.accessCodeLifetime_ = 0;
53 this.initialized_ = false;
56 * @type {function():void}
59 this.onHostStarted_ = function() {};
62 * Called if Native Messaging host has failed to start.
63 * @param {remoting.Error} error
66 this.onHostInitFailed_ = function(error) {};
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
74 this.onError_ = function(error) {};
77 * @type {function(remoting.HostSession.State):void}
80 this.onStateChanged_ = function() {};
83 * @type {function(boolean):void}
86 this.onNatPolicyChanged_ = function() {};
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.
95 * @param {function():void} onHostStarted Called after successful
97 * @param {function(remoting.Error):void} onHostInitFailed Called if cannot
99 * @param {function(remoting.Error):void} onError Called on host error after
100 * successfully connecting to the host.
103 remoting.HostIt2MeNativeMessaging.prototype.initialize =
104 function(onHostStarted, onHostInitFailed, onError) {
105 this.onHostStarted_ = onHostStarted;
106 this.onHostInitFailed_ = onHostInitFailed;
107 this.onError_ = onError;
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'});
116 console.log('Native Messaging initialization failed: ',
117 /** @type {*} */ (err));
118 onHostInitFailed(remoting.Error.UNEXPECTED);
124 * Attaches a new ID to the supplied message, and posts it to the Native
126 * |message| should have its 'type' field set, and any other fields set
127 * depending on the message type.
129 * @param {{type: string}} message The message to post.
133 remoting.HostIt2MeNativeMessaging.prototype.postMessage_ =
135 var id = this.nextId_++;
137 this.port_.postMessage(message);
141 * Handler for incoming Native Messages.
143 * @param {Object} message The received message.
147 remoting.HostIt2MeNativeMessaging.prototype.onIncomingMessage_ =
150 this.handleIncomingMessage_(message);
152 console.error(/** @type {*} */ (e));
153 this.onError_(remoting.Error.UNEXPECTED);
158 * Handler for incoming Native Messages.
160 * @param {Object} message The received message.
164 remoting.HostIt2MeNativeMessaging.prototype.handleIncomingMessage_ =
166 var type = getStringAttr(message, '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
176 this.onHostStarted_();
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.
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.
191 case 'hostStateChanged':
192 var stateString = getStringAttr(message, 'state');
193 console.log('hostStateChanged received: ', stateString);
194 var state = remoting.HostSession.State.fromString(stateString);
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);
203 case remoting.HostSession.State.CONNECTED:
204 var client = getStringAttr(message, 'client');
205 this.onConnected_(client);
208 this.onStateChanged_(state);
211 case 'natPolicyChanged':
212 var natTraversalEnabled = getBooleanAttr(message, 'natTraversalEnabled');
213 this.onNatPolicyChanged_(natTraversalEnabled);
217 console.error(getStringAttr(message, 'description'));
218 this.onError_(remoting.Error.UNEXPECTED);
222 throw 'Unexpected native message: ' + message;
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
236 * @param {boolean} xmppServerUseTls Whether to use TLS on connections to the
238 * @param {string} directoryBotJid XMPP JID for the remoting directory server
242 remoting.HostIt2MeNativeMessaging.prototype.connect =
243 function(email, authServiceWithToken, onStateChanged, onNatPolicyChanged,
244 xmppServerAddress, xmppServerUseTls, directoryBotJid) {
245 this.onStateChanged_ = onStateChanged;
246 this.onNatPolicyChanged_ = onNatPolicyChanged;
250 authServiceWithToken: authServiceWithToken,
251 xmppServerAddress: xmppServerAddress,
252 xmppServerUseTls: xmppServerUseTls,
253 directoryBotJid: directoryBotJid});
259 remoting.HostIt2MeNativeMessaging.prototype.disconnect =
262 type: 'disconnect'});
266 * @param {string} accessCode
267 * @param {number} accessCodeLifetime
271 remoting.HostIt2MeNativeMessaging.prototype.onReceivedAccessCode_ =
272 function(accessCode, accessCodeLifetime) {
273 this.accessCode_ = accessCode;
274 this.accessCodeLifetime_ = accessCodeLifetime;
278 * @param {string} clientId
282 remoting.HostIt2MeNativeMessaging.prototype.onConnected_ =
284 this.clientId_ = clientId;
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);
300 console.error('Native Messaging port disconnected.');
301 this.onError_(remoting.Error.UNEXPECTED);
308 remoting.HostIt2MeNativeMessaging.prototype.getAccessCode = function() {
309 return this.accessCode_
315 remoting.HostIt2MeNativeMessaging.prototype.getAccessCodeLifetime = function() {
316 return this.accessCodeLifetime_
322 remoting.HostIt2MeNativeMessaging.prototype.getClient = function() {
323 return this.clientId_;