diff options
author | garykac <garykac@chromium.org> | 2015-03-13 13:38:11 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-13 20:38:55 +0000 |
commit | cd415d0eb53fa448ca0affc8b7f544334948a66a (patch) | |
tree | c68a7e503be32d1cfb2ee0741636112bffcf2a16 /remoting | |
parent | 365d55c8324e82db0473834a09816953cb158501 (diff) | |
download | chromium_src-cd415d0eb53fa448ca0affc8b7f544334948a66a.zip chromium_src-cd415d0eb53fa448ca0affc8b7f544334948a66a.tar.gz chromium_src-cd415d0eb53fa448ca0affc8b7f544334948a66a.tar.bz2 |
[Chromoting] Create ProtocolExtension interface
This creates an Application.ProtocolExtension interface and updates our
extensions to make use of it. Extension-specific code in the clientsession
has been generalized and the Application.Delegate registers the extensions
that it wants (rather than having the clientsession automatically adding
extension based on the current application.
After this cl, clientsession no longer has special code to handle
the cast and gnubby extensions.
BUG=465878
Review URL: https://codereview.chromium.org/1001073002
Cr-Commit-Position: refs/heads/master@{#320565}
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/remoting_webapp_files.gypi | 1 | ||||
-rw-r--r-- | remoting/webapp/base/js/application.js | 18 | ||||
-rw-r--r-- | remoting/webapp/base/js/protocol_extension.js | 46 | ||||
-rw-r--r-- | remoting/webapp/crd/js/cast_extension_handler.js | 39 | ||||
-rw-r--r-- | remoting/webapp/crd/js/client_plugin.js | 26 | ||||
-rw-r--r-- | remoting/webapp/crd/js/client_plugin_impl.js | 49 | ||||
-rw-r--r-- | remoting/webapp/crd/js/client_session.js | 125 | ||||
-rw-r--r-- | remoting/webapp/crd/js/desktop_remoting.js | 11 | ||||
-rw-r--r-- | remoting/webapp/crd/js/gnubby_auth_handler.js | 38 | ||||
-rw-r--r-- | remoting/webapp/crd/js/session_connector.js | 17 | ||||
-rw-r--r-- | remoting/webapp/crd/js/session_connector_impl.js | 85 |
11 files changed, 232 insertions, 223 deletions
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi index 39566d6..741c062 100644 --- a/remoting/remoting_webapp_files.gypi +++ b/remoting/remoting_webapp_files.gypi @@ -157,6 +157,7 @@ 'webapp/base/js/base.js', 'webapp/base/js/ipc.js', 'webapp/base/js/platform.js', + 'webapp/base/js/protocol_extension.js', 'webapp/crd/js/apps_v2_migration.js', 'webapp/crd/js/error.js', 'webapp/crd/js/event_handlers.js', diff --git a/remoting/webapp/base/js/application.js b/remoting/webapp/base/js/application.js index 7de0272..74817f7 100644 --- a/remoting/webapp/base/js/application.js +++ b/remoting/webapp/base/js/application.js @@ -52,19 +52,11 @@ remoting.Application.prototype.getApplicationName = function() { }; /** - * @return {Array<string>} A list of |ClientSession.Capability|s required - * by this application. - */ -remoting.Application.prototype.getRequiredCapabilities_ = function() { - return this.appCapabilities_; -}; - -/** * @param {remoting.ClientSession.Capability} capability * @return {boolean} */ remoting.Application.prototype.hasCapability = function(capability) { - var capabilities = remoting.app.getRequiredCapabilities_(); + var capabilities = this.appCapabilities_; return capabilities.indexOf(capability) != -1; }; @@ -184,9 +176,10 @@ remoting.Application.prototype.onExtensionMessage = function(type, data) { return true; } - if (remoting.clientSession) { - return remoting.clientSession.handleExtensionMessage(type, message); + if (remoting.desktopConnectedView) { + return remoting.desktopConnectedView.handleExtensionMessage(type, message); } + return false; }; @@ -213,7 +206,7 @@ remoting.Application.prototype.getSessionConnector = function() { this.onError.bind(this), this.onExtensionMessage.bind(this), this.onConnectionFailed.bind(this), - this.getRequiredCapabilities_(), + this.appCapabilities_, this.delegate_.getDefaultRemapKeys()); } return this.sessionConnector_; @@ -262,6 +255,7 @@ remoting.Application.prototype.updateStatistics_ = function() { remoting.clientSession.logStatistics(perfstats); }; + /** * @interface */ diff --git a/remoting/webapp/base/js/protocol_extension.js b/remoting/webapp/base/js/protocol_extension.js new file mode 100644 index 0000000..d745172 --- /dev/null +++ b/remoting/webapp/base/js/protocol_extension.js @@ -0,0 +1,46 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Interface abstracting the protocol extension functionality. + * Instances of this class can be registered with the SessionConnector + * to enhance the communication protocol between the host and client. + * Note that corresponding support on the host side is required. + */ + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** + * @interface + */ +remoting.ProtocolExtension = function() {}; + +/** + * The string that identifies the type of the extension. + * All extension messages with this type will be sent to the extension. + * + * @return {string} + */ +remoting.ProtocolExtension.prototype.getType = function() {}; + +/** + * Called when the connection has been established to start the extension. + * + * @param {function(string,string)} sendMessageToHost Callback to send a message + * to the host. + */ +remoting.ProtocolExtension.prototype.start = + function(sendMessageToHost) {}; + +/** + * Called when an extension message of a matching type is received. + * + * @param {string} message + */ +remoting.ProtocolExtension.prototype.onMessage = + function(message) {}; diff --git a/remoting/webapp/crd/js/cast_extension_handler.js b/remoting/webapp/crd/js/cast_extension_handler.js index 5957a16..ab0bde2 100644 --- a/remoting/webapp/crd/js/cast_extension_handler.js +++ b/remoting/webapp/crd/js/cast_extension_handler.js @@ -22,13 +22,9 @@ var remoting = remoting || {}; /** * @constructor - * @param {!remoting.ClientSession} clientSession The client session to send - * cast extension messages to. + * @implements {remoting.ProtocolExtension} */ -remoting.CastExtensionHandler = function(clientSession) { - /** @private */ - this.clientSession_ = clientSession; - +remoting.CastExtensionHandler = function() { /** @private {chrome.cast.Session} */ this.session_ = null; @@ -41,21 +37,30 @@ remoting.CastExtensionHandler = function(clientSession) { /** @private {Array<Object>} */ this.messageQueue_ = []; - this.start_(); + /** @private {?function(string,string)} */ + this.sendMessageToHostCallback_ = null; +}; + +/** @return {string} */ +remoting.CastExtensionHandler.prototype.getType = function() { + return 'cast_message'; }; /** * The id of the script node. - * @type {string} - * @private + * @private {string} */ remoting.CastExtensionHandler.prototype.SCRIPT_NODE_ID_ = 'cast-script-node'; /** * Attempts to load the Google Cast Chrome Sender API libary. - * @private + * + * @param {function(string,string)} sendMessageToHost Callback to send a message + * to the host. */ -remoting.CastExtensionHandler.prototype.start_ = function() { +remoting.CastExtensionHandler.prototype.start = function(sendMessageToHost) { + this.sendMessageToHostCallback_ = sendMessageToHost; + var node = document.getElementById(this.SCRIPT_NODE_ID_); if (node) { console.error( @@ -81,7 +86,6 @@ remoting.CastExtensionHandler.prototype.start_ = function() { } node.addEventListener('load', onLoad, false); node.addEventListener('error', onLoadError, false); - }; /** @@ -101,14 +105,13 @@ remoting.CastExtensionHandler.prototype.onMessage = function(msgString) { }; /** - * Send cast-extension messages through the client session. - * @param {Object} response The JSON response to be sent to the host. The - * response object must contain the appropriate keys. + * Send cast-extension messages through the host via the plugin. + * @param {Object} data The JSON response to be sent to the host. The + * response object must contain the appropriate keys. * @private */ -remoting.CastExtensionHandler.prototype.sendMessageToHost_ = - function(response) { - this.clientSession_.sendCastExtensionMessage(response); +remoting.CastExtensionHandler.prototype.sendMessageToHost_ = function(data) { + this.sendMessageToHostCallback_(this.getType(), JSON.stringify(data)); }; /** diff --git a/remoting/webapp/crd/js/client_plugin.js b/remoting/webapp/crd/js/client_plugin.js index 04f94db..66b9fd3 100644 --- a/remoting/webapp/crd/js/client_plugin.js +++ b/remoting/webapp/crd/js/client_plugin.js @@ -131,20 +131,6 @@ remoting.ClientPlugin.prototype.setConnectionEventHandler = function(handler) {}; /** - * @param {function(string):void} handler Callback for processing security key - * (Gnubby) protocol messages. - */ -remoting.ClientPlugin.prototype.setGnubbyAuthHandler = - function(handler) {}; - -/** - * @param {function(string):void} handler Callback for processing Cast protocol - * messages. - */ -remoting.ClientPlugin.prototype.setCastExtensionHandler = - function(handler) {}; - -/** * @param {function(string, number, number):void} handler Callback for * processing large mouse cursor images. The first parameter is a data: * URL encoding the mouse cursor; the second and third parameters are @@ -228,6 +214,13 @@ remoting.ClientPlugin.ConnectionEventHandler.prototype.onConnectionReady = remoting.ClientPlugin.ConnectionEventHandler.prototype.onSetCapabilities = function(capabilities) {}; +/** + * @param {string} type + * @param {string} data + */ +remoting.ClientPlugin.ConnectionEventHandler.prototype.onExtensionMessage = + function(type, data) {}; + /** * @interface @@ -236,14 +229,11 @@ remoting.ClientPluginFactory = function() {}; /** * @param {Element} container The container for the embed element. - * @param {function(string, string):boolean} onExtensionMessage The handler for - * protocol extension messages. Returns true if a message is recognized; - * false otherwise. * @param {Array<string>} requiredCapabilities * @return {remoting.ClientPlugin} A new client plugin instance. */ remoting.ClientPluginFactory.prototype.createPlugin = - function(container, onExtensionMessage, requiredCapabilities) {}; + function(container, requiredCapabilities) {}; /** * Preload the plugin to make instantiation faster when the user tries diff --git a/remoting/webapp/crd/js/client_plugin_impl.js b/remoting/webapp/crd/js/client_plugin_impl.js index 35e5b08..59fb8bf 100644 --- a/remoting/webapp/crd/js/client_plugin_impl.js +++ b/remoting/webapp/crd/js/client_plugin_impl.js @@ -27,21 +27,17 @@ remoting.ClientPluginMessage = function() { /** * @param {Element} container The container for the embed element. - * @param {function(string, string):boolean} onExtensionMessage The handler for - * protocol extension messages. Returns true if a message is recognized; - * false otherwise. * @param {Array<string>} requiredCapabilities The set of capabilties that the * session must support for this application. * @constructor * @implements {remoting.ClientPlugin} */ -remoting.ClientPluginImpl = function(container, onExtensionMessage, +remoting.ClientPluginImpl = function(container, requiredCapabilities) { this.plugin_ = remoting.ClientPluginImpl.createPluginElement_(); this.plugin_.id = 'session-client-plugin'; container.appendChild(this.plugin_); - this.onExtensionMessage_ = onExtensionMessage; /** @private {Array<string>} */ this.requiredCapabilities_ = requiredCapabilities; @@ -157,21 +153,6 @@ remoting.ClientPluginImpl.prototype.setConnectionEventHandler = }; /** - * @param {function(string):void} handler - */ -remoting.ClientPluginImpl.prototype.setGnubbyAuthHandler = function(handler) { - this.onGnubbyAuthHandler_ = handler; -}; - -/** - * @param {function(string):void} handler - */ -remoting.ClientPluginImpl.prototype.setCastExtensionHandler = - function(handler) { - this.onCastExtensionHandler_ = handler; -}; - -/** * @param {function(string, number, number):void} handler */ remoting.ClientPluginImpl.prototype.setMouseCursorHandler = function(handler) { @@ -256,6 +237,11 @@ remoting.ClientPluginImpl.prototype.handleMessageMethod_ = function(message) { /** @type {!Array<string>} */ var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); handler.onSetCapabilities(capabilities); + + } else if (message.method == 'extensionMessage') { + var extMsgType = getStringAttr(message.data, 'type'); + var extMsgData = getStringAttr(message.data, 'data'); + handler.onExtensionMessage(extMsgType, extMsgData); } } @@ -345,24 +331,6 @@ remoting.ClientPluginImpl.prototype.handleMessageMethod_ = function(message) { var sharedSecret = getStringAttr(message.data, 'sharedSecret'); this.onPairingComplete_(clientId, sharedSecret); - } else if (message.method == 'extensionMessage') { - var extMsgType = getStringAttr(message.data, 'type'); - var extMsgData = getStringAttr(message.data, 'data'); - switch (extMsgType) { - case 'gnubby-auth': - this.onGnubbyAuthHandler_(extMsgData); - break; - case 'test-echo-reply': - console.log('Got echo reply: ' + extMsgData); - break; - case 'cast_message': - this.onCastExtensionHandler_(extMsgData); - break; - default: - this.onExtensionMessage_(extMsgType, extMsgData); - break; - } - } else if (message.method == 'unsetCursorShape') { this.updateMouseCursorImage_('', 0, 0); @@ -804,13 +772,12 @@ remoting.DefaultClientPluginFactory = function() {}; /** * @param {Element} container - * @param {function(string, string):boolean} onExtensionMessage * @param {Array<string>} requiredCapabilities * @return {remoting.ClientPlugin} */ remoting.DefaultClientPluginFactory.prototype.createPlugin = - function(container, onExtensionMessage, requiredCapabilities) { - return new remoting.ClientPluginImpl(container, onExtensionMessage, + function(container, requiredCapabilities) { + return new remoting.ClientPluginImpl(container, requiredCapabilities); }; diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js index 6ac117c..3d58d15 100644 --- a/remoting/webapp/crd/js/client_session.js +++ b/remoting/webapp/crd/js/client_session.js @@ -36,12 +36,17 @@ remoting.ACCESS_TOKEN_RESEND_INTERVAL_MS = 15 * 60 * 1000; * @param {remoting.Host} host The host to connect to. * @param {remoting.SignalStrategy} signalStrategy Signal strategy. * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. + * @param {function(string, string):boolean} onExtensionMessage The handler for + * protocol extension messages. Returns true if a message is recognized; + * false otherwise. + * * @constructor * @extends {base.EventSourceImpl} * @implements {base.Disposable} * @implements {remoting.ClientPlugin.ConnectionEventHandler} */ -remoting.ClientSession = function(plugin, host, signalStrategy, mode) { +remoting.ClientSession = function(plugin, host, signalStrategy, mode, + onExtensionMessage) { /** @private */ this.state_ = remoting.ClientSession.State.CREATED; @@ -74,19 +79,12 @@ remoting.ClientSession = function(plugin, host, signalStrategy, mode) { */ this.logHostOfflineErrors_ = true; - /** @private {remoting.GnubbyAuthHandler} */ - this.gnubbyAuthHandler_ = null; - - /** @private {remoting.CastExtensionHandler} */ - this.castExtensionHandler_ = null; + /** @private {function(string, string):boolean} */ + this.onExtensionMessageHandler_ = onExtensionMessage; /** @private {remoting.ClientPlugin} */ this.plugin_ = plugin; plugin.setConnectionEventHandler(this); - plugin.setGnubbyAuthHandler( - this.processGnubbyAuthMessage_.bind(this)); - plugin.setCastExtensionHandler( - this.processCastExtensionMessage_.bind(this)); this.defineEvents(Object.keys(remoting.ClientSession.Events)); }; @@ -479,6 +477,14 @@ remoting.ClientSession.prototype.onSetCapabilities = function(capabilities) { }; /** + * @param {string} type + * @param {string} data + */ +remoting.ClientSession.prototype.onExtensionMessage = function(type, data) { + this.onExtensionMessageHandler_(type, data); +}; + +/** * @param {remoting.ClientSession.State} newState The new state for the session. * @return {void} Nothing. * @private @@ -503,10 +509,6 @@ remoting.ClientSession.prototype.setState_ = function(newState) { state = remoting.ClientSession.State.CONNECTION_DROPPED; } this.logToServer.logClientSessionStateChange(state, this.error_); - if (this.state_ == remoting.ClientSession.State.CONNECTED) { - this.createGnubbyAuthHandler_(); - this.createCastExtensionHandler_(); - } this.raiseEvent(remoting.ClientSession.Events.stateChanged, new remoting.ClientSession.StateEvent(newState, oldState) @@ -581,47 +583,6 @@ remoting.ClientSession.prototype.sendClientMessage = function(type, message) { }; /** - * Send a gnubby-auth extension message to the host. - * @param {Object} data The gnubby-auth message data. - */ -remoting.ClientSession.prototype.sendGnubbyAuthMessage = function(data) { - if (!this.plugin_) - return; - this.plugin_.sendClientMessage('gnubby-auth', JSON.stringify(data)); -}; - -/** - * Process a remote gnubby auth request. - * @param {string} data Remote gnubby request data. - * @private - */ -remoting.ClientSession.prototype.processGnubbyAuthMessage_ = function(data) { - if (this.gnubbyAuthHandler_) { - try { - this.gnubbyAuthHandler_.onMessage(data); - } catch (/** @type {*} */ err) { - console.error('Failed to process gnubby message: ', err); - } - } else { - console.error('Received unexpected gnubby message'); - } -}; - -/** - * Create a gnubby auth handler and inform the host that gnubby auth is - * supported. - * @private - */ -remoting.ClientSession.prototype.createGnubbyAuthHandler_ = function() { - if (remoting.desktopConnectedView.getMode() == - remoting.DesktopConnectedView.Mode.ME2ME) { - this.gnubbyAuthHandler_ = new remoting.GnubbyAuthHandler(this); - // TODO(psj): Move to more generic capabilities mechanism. - this.sendGnubbyAuthMessage({'type': 'control', 'option': 'auth-v1'}); - } -}; - -/** * Timer callback to send the access token to the host. * @private */ @@ -648,60 +609,6 @@ remoting.ClientSession.prototype.sendGoogleDriveAccessToken_ = function() { }; /** - * Send a Cast extension message to the host. - * @param {Object} data The cast message data. - */ -remoting.ClientSession.prototype.sendCastExtensionMessage = function(data) { - if (!this.plugin_) - return; - this.plugin_.sendClientMessage('cast_message', JSON.stringify(data)); -}; - -/** - * Process a remote Cast extension message from the host. - * @param {string} data Remote cast extension data message. - * @private - */ -remoting.ClientSession.prototype.processCastExtensionMessage_ = function(data) { - if (this.castExtensionHandler_) { - try { - this.castExtensionHandler_.onMessage(data); - } catch (/** @type {*} */ err) { - console.error('Failed to process cast message: ', err); - } - } else { - console.error('Received unexpected cast message'); - } -}; - -/** - * Create a CastExtensionHandler and inform the host that cast extension - * is supported. - * @private - */ -remoting.ClientSession.prototype.createCastExtensionHandler_ = function() { - if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST) && - remoting.desktopConnectedView.getMode() == - remoting.DesktopConnectedView.Mode.ME2ME) { - this.castExtensionHandler_ = new remoting.CastExtensionHandler(this); - } -}; - -/** - * Handles protocol extension messages. - * @param {string} type Type of extension message. - * @param {Object} message The parsed extension message data. - * @return {boolean} True if the message was recognized, false otherwise. - */ -remoting.ClientSession.prototype.handleExtensionMessage = - function(type, message) { - if (remoting.desktopConnectedView.handleExtensionMessage(type, message)) { - return true; - } - return false; -}; - -/** * Enables or disables rendering of dirty regions for debugging. * @param {boolean} enable True to enable rendering. */ diff --git a/remoting/webapp/crd/js/desktop_remoting.js b/remoting/webapp/crd/js/desktop_remoting.js index 186c5b6..10e35c5 100644 --- a/remoting/webapp/crd/js/desktop_remoting.js +++ b/remoting/webapp/crd/js/desktop_remoting.js @@ -192,6 +192,17 @@ remoting.DesktopRemoting.prototype.handleConnected = function(clientSession) { remoting.toolbar.preview(); } + if (remoting.desktopConnectedView.getMode() == + remoting.DesktopConnectedView.Mode.ME2ME) { + var sessionConnector = remoting.app.getSessionConnector(); + if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST)) { + sessionConnector.registerProtocolExtension( + new remoting.CastExtensionHandler()); + } + sessionConnector.registerProtocolExtension( + new remoting.GnubbyAuthHandler()); + } + if (remoting.pairingRequested) { /** * @param {string} clientId diff --git a/remoting/webapp/crd/js/gnubby_auth_handler.js b/remoting/webapp/crd/js/gnubby_auth_handler.js index baba1a305..4d414da 100644 --- a/remoting/webapp/crd/js/gnubby_auth_handler.js +++ b/remoting/webapp/crd/js/gnubby_auth_handler.js @@ -15,13 +15,39 @@ var remoting = remoting || {}; /** * @constructor - * @param {!remoting.ClientSession} clientSession The client session to send - * gnubby-auth response messages to. + * @implements {remoting.ProtocolExtension} */ -remoting.GnubbyAuthHandler = function(clientSession) { - this.clientSession_ = clientSession; +remoting.GnubbyAuthHandler = function() { + /** @private {?function(string,string)} */ + this.sendMessageToHostCallback_ = null; }; +/** @return {string} */ +remoting.GnubbyAuthHandler.prototype.getType = function() { + return 'gnubby-auth'; +}; + +/** + * @param {function(string,string)} sendMessageToHost Callback to send a message + * to the host. + */ +remoting.GnubbyAuthHandler.prototype.start = function(sendMessageToHost) { + this.sendMessageToHostCallback_ = sendMessageToHost; + + this.sendMessageToHost_({ + 'type': 'control', + 'option': 'auth-v1' + }); +}; + +/** + * @param {Object} data The data to send. + * @private + */ +remoting.GnubbyAuthHandler.prototype.sendMessageToHost_ = function(data) { + this.sendMessageToHostCallback_(this.getType(), JSON.stringify(data)); +} + /** * Processes gnubby-auth messages. * @param {string} data The gnubby-auth message data. @@ -48,14 +74,14 @@ remoting.GnubbyAuthHandler.prototype.onMessage = function(data) { remoting.GnubbyAuthHandler.prototype.callback_ = function(connectionId, response) { try { - this.clientSession_.sendGnubbyAuthMessage({ + this.sendMessageToHost_({ 'type': 'data', 'connectionId': connectionId, 'data': getArrayAttr(response, 'data') }); } catch (/** @type {*} */ err) { console.error('gnubby callback failed: ', err); - this.clientSession_.sendGnubbyAuthMessage({ + this.sendMessageToHost_({ 'type': 'error', 'connectionId': connectionId }); diff --git a/remoting/webapp/crd/js/session_connector.js b/remoting/webapp/crd/js/session_connector.js index a1a15bb..029e44f 100644 --- a/remoting/webapp/crd/js/session_connector.js +++ b/remoting/webapp/crd/js/session_connector.js @@ -104,6 +104,12 @@ remoting.SessionConnector.prototype.getConnectionMode = function() {}; */ remoting.SessionConnector.prototype.getHostId = function() {}; +/** + * @param {remoting.ProtocolExtension} extension + */ +remoting.SessionConnector.prototype.registerProtocolExtension = + function(extension) {}; + /** * @interface @@ -115,9 +121,9 @@ remoting.SessionConnectorFactory = function() {}; * @param {function(remoting.ClientSession):void} onConnected Callback on * success. * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(string, string):boolean} onExtensionMessage The handler for - * protocol extension messages. Returns true if a message is recognized; - * false otherwise. + * @param {function(string, string):boolean} appProtocolExtensionHandler The + * handler for the application's protocol extension messages. Returns true + * if a message is recognized; false otherwise. * @param {function(!remoting.Error):void} onConnectionFailed Callback for when * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities @@ -127,10 +133,7 @@ remoting.SessionConnectorFactory = function() {}; * @return {remoting.SessionConnector} */ remoting.SessionConnectorFactory.prototype.createConnector = - // TODO(garykac): Can onExtensionMessage be removed from here? It's only - // needed to pass to the ClientSession. Investigate why ClientSession - // needs this. - function(clientContainer, onConnected, onError, onExtensionMessage, + function(clientContainer, onConnected, onError, appProtocolExtensionHandler, onConnectionFailed, requiredCapabilities, defaultRemapKeys) {}; /** diff --git a/remoting/webapp/crd/js/session_connector_impl.js b/remoting/webapp/crd/js/session_connector_impl.js index 8c43b9b..b415a47 100644 --- a/remoting/webapp/crd/js/session_connector_impl.js +++ b/remoting/webapp/crd/js/session_connector_impl.js @@ -31,9 +31,9 @@ remoting.desktopConnectedView = null; * @param {function(remoting.ClientSession):void} onConnected Callback on * success. * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(string, string):boolean} onExtensionMessage The handler for - * protocol extension messages. Returns true if a message is recognized; - * false otherwise. + * @param {function(string, string):boolean} appProtocolExtensionHandler The + * handler for the application's protocol extension messages. Returns true + * if a message is recognized; false otherwise. * @param {function(!remoting.Error):void} onConnectionFailed Callback for when * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities @@ -44,7 +44,7 @@ remoting.desktopConnectedView = null; * @implements {remoting.SessionConnector} */ remoting.SessionConnectorImpl = function(clientContainer, onConnected, onError, - onExtensionMessage, + appProtocolExtensionHandler, onConnectionFailed, requiredCapabilities, defaultRemapKeys) { @@ -58,7 +58,7 @@ remoting.SessionConnectorImpl = function(clientContainer, onConnected, onError, this.onError_ = onError; /** @private {function(string, string):boolean} */ - this.onExtensionMessage_ = onExtensionMessage; + this.appProtocolExtensionHandler_ = appProtocolExtensionHandler; /** @private {function(!remoting.Error):void} */ this.onConnectionFailed_ = onConnectionFailed; @@ -115,6 +115,9 @@ remoting.SessionConnectorImpl.prototype.resetConnection_ = function() { /** @private {remoting.CredentialsProvider} */ this.credentialsProvider_ = null; + + /** @private {Object<string,remoting.ProtocolExtension>} */ + this.protocolExtensions_ = {}; }; /** @@ -325,7 +328,7 @@ remoting.SessionConnectorImpl.prototype.createSession_ = function() { '.client-plugin-container'); this.plugin_ = remoting.ClientPlugin.factory.createPlugin( - pluginContainer, this.onExtensionMessage_, this.requiredCapabilities_); + pluginContainer, this.requiredCapabilities_); var that = this; this.host_.options.load().then(function(){ @@ -352,7 +355,8 @@ remoting.SessionConnectorImpl.prototype.onPluginInitialized_ = function( } this.clientSession_ = new remoting.ClientSession( - this.plugin_, this.host_, this.signalStrategy_, this.connectionMode_); + this.plugin_, this.host_, this.signalStrategy_, this.connectionMode_, + this.onProtocolExtensionMessage_.bind(this)); remoting.clientSession = this.clientSession_; this.connectedView_ = new remoting.DesktopConnectedView( @@ -396,6 +400,59 @@ remoting.SessionConnectorImpl.prototype.removePlugin_ = function() { }; /** + * @param {remoting.ProtocolExtension} extension + */ +remoting.SessionConnectorImpl.prototype.registerProtocolExtension = + function(extension) { + var type = extension.getType(); + if (type in this.protocolExtensions_) { + console.error( + 'Attempt to register multiple extensions with the same type: ', type); + return; + } + this.protocolExtensions_[type] = extension; +}; + +/** @private */ +remoting.SessionConnectorImpl.prototype.initProtocolExtensions_ = function() { + for (var type in this.protocolExtensions_) { + /** @type {remoting.ProtocolExtension} */ + var extension = this.protocolExtensions_[type]; + extension.start(this.plugin_.sendClientMessage.bind(this.plugin_)); + } +}; + +/** + * Called when an extension message needs to be handled. + * + * @param {string} type The type of the extension message. + * @param {string} data The payload of the extension message. + * @return {boolean} Return true if the extension message was recognized. + * @private + */ +remoting.SessionConnectorImpl.prototype.onProtocolExtensionMessage_ = + function(type, data) { + if (type == 'test-echo-reply') { + console.log('Got echo reply: ' + data); + return true; + } + for (var type in this.protocolExtensions_) { + /** @type {remoting.ProtocolExtension} */ + var extension = this.protocolExtensions_[type]; + if (type == extension.getType()) { + try { + extension.onMessage(data); + } catch (/** @type {*} */ err) { + console.error('Failed to process protocol extension ', type, + ' message: ', err); + } + return true; + } + } + return this.appProtocolExtensionHandler_(type, data); +}; + +/** * Handle a change in the state of the client session prior to successful * connection (after connection, this class no longer handles state change * events). Errors that occur while connecting either trigger a reconnect @@ -422,6 +479,8 @@ remoting.SessionConnectorImpl.prototype.onStateChange_ = function(event) { new remoting.SmartReconnector(this, this.clientSession_); } this.onConnected_(this.clientSession_); + // Initialize any protocol extensions that may have been added by the app. + this.initProtocolExtensions_(); break; case remoting.ClientSession.State.CREATED: @@ -478,9 +537,9 @@ remoting.DefaultSessionConnectorFactory = function() {}; * @param {function(remoting.ClientSession):void} onConnected Callback on * success. * @param {function(!remoting.Error):void} onError Callback on error. - * @param {function(string, string):boolean} onExtensionMessage The handler for - * protocol extension messages. Returns true if a message is recognized; - * false otherwise. + * @param {function(string, string):boolean} appProtocolExtensionHandler The + * handler for the application's protocol extension messages. Returns true + * if a message is recognized; false otherwise. * @param {function(!remoting.Error):void} onConnectionFailed Callback for when * the connection fails. * @param {Array<string>} requiredCapabilities Connector capabilities @@ -490,10 +549,12 @@ remoting.DefaultSessionConnectorFactory = function() {}; * @return {remoting.SessionConnector} */ remoting.DefaultSessionConnectorFactory.prototype.createConnector = - function(clientContainer, onConnected, onError, onExtensionMessage, + function(clientContainer, onConnected, onError, + appProtocolExtensionHandler, onConnectionFailed, requiredCapabilities, defaultRemapKeys) { return new remoting.SessionConnectorImpl(clientContainer, onConnected, - onError, onExtensionMessage, + onError, + appProtocolExtensionHandler, onConnectionFailed, requiredCapabilities, defaultRemapKeys); |