| Index: remoting/webapp/host_dispatcher.js
|
| ===================================================================
|
| --- remoting/webapp/host_dispatcher.js (revision 278256)
|
| +++ remoting/webapp/host_dispatcher.js (working copy)
|
| @@ -5,7 +5,15 @@
|
| /**
|
| * @fileoverview
|
| * This class provides an interface between the HostController and either the
|
| - * NativeMessaging Host.
|
| + * NativeMessaging Host or the Host NPAPI plugin, depending on whether or not
|
| + * NativeMessaging is supported. Since the test for NativeMessaging support is
|
| + * asynchronous, this class stores any requests on a queue, pending the result
|
| + * of the test.
|
| + * Once the test is complete, the pending requests are performed on either the
|
| + * NativeMessaging host, or the NPAPI plugin.
|
| + *
|
| + * If necessary, the HostController is instructed (via a callback) to
|
| + * instantiate the NPAPI plugin, and return a reference to it here.
|
| */
|
|
|
| 'use strict';
|
| @@ -15,17 +23,26 @@
|
|
|
| /**
|
| * @constructor
|
| + * @param {function():remoting.HostPlugin} createPluginCallback Callback to
|
| + * instantiate the NPAPI plugin when NativeMessaging is determined to be
|
| + * unsupported.
|
| */
|
| -remoting.HostDispatcher = function() {
|
| +remoting.HostDispatcher = function(createPluginCallback) {
|
| /** @type {remoting.HostNativeMessaging} @private */
|
| this.nativeMessagingHost_ = new remoting.HostNativeMessaging();
|
|
|
| + /** @type {remoting.HostPlugin} @private */
|
| + this.npapiHost_ = null;
|
| +
|
| /** @type {remoting.HostDispatcher.State} @private */
|
| this.state_ = remoting.HostDispatcher.State.UNKNOWN;
|
|
|
| /** @type {Array.<function()>} @private */
|
| this.pendingRequests_ = [];
|
|
|
| + /** @type {function():remoting.HostPlugin} @private */
|
| + this.createPluginCallback_ = createPluginCallback;
|
| +
|
| this.tryToInitialize_();
|
| }
|
|
|
| @@ -33,7 +50,8 @@
|
| remoting.HostDispatcher.State = {
|
| UNKNOWN: 0,
|
| NATIVE_MESSAGING: 1,
|
| - NOT_INSTALLED: 2
|
| + NPAPI: 2,
|
| + NOT_INSTALLED: 3
|
| };
|
|
|
| remoting.HostDispatcher.prototype.tryToInitialize_ = function() {
|
| @@ -57,7 +75,10 @@
|
| }
|
|
|
| function onNativeMessagingFailed(error) {
|
| - that.state_ = remoting.HostDispatcher.State.NOT_INSTALLED;
|
| + that.npapiHost_ = that.createPluginCallback_();
|
| +
|
| + that.state_ = that.npapiHost_ ? remoting.HostDispatcher.State.NPAPI
|
| + : remoting.HostDispatcher.State.NOT_INSTALLED;
|
| sendPendingRequests();
|
| }
|
|
|
| @@ -66,6 +87,13 @@
|
| };
|
|
|
| /**
|
| + * @return {remoting.HostPlugin}
|
| + */
|
| +remoting.HostDispatcher.prototype.getNpapiHost = function() {
|
| + return this.npapiHost_;
|
| +}
|
| +
|
| +/**
|
| * @param {remoting.HostController.Feature} feature The feature to test for.
|
| * @param {function(boolean):void} onDone
|
| * @return {void}
|
| @@ -80,6 +108,15 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| onDone(this.nativeMessagingHost_.hasFeature(feature));
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + // If this is an old NPAPI plugin that doesn't list supportedFeatures,
|
| + // assume it is an old plugin that doesn't support any new feature.
|
| + var supportedFeatures = [];
|
| + if (typeof(this.npapiHost_.supportedFeatures) == 'string') {
|
| + supportedFeatures = this.npapiHost_.supportedFeatures.split(' ');
|
| + }
|
| + onDone(supportedFeatures.indexOf(feature) >= 0);
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onDone(false);
|
| break;
|
| @@ -100,6 +137,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getHostName(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getHostName(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -123,6 +167,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getPinHash(hostId, pin, onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getPinHash(hostId, pin, onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -143,6 +194,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.generateKeyPair(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.generateKeyPair(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -165,6 +223,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.updateDaemonConfig(config, onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.updateDaemonConfig(JSON.stringify(config), onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -177,6 +242,21 @@
|
| * @return {void}
|
| */
|
| remoting.HostDispatcher.prototype.getDaemonConfig = function(onDone, onError) {
|
| + /**
|
| + * Converts the config string from the NPAPI plugin to an Object, to pass to
|
| + * |onDone|.
|
| + * @param {string} configStr
|
| + * @return {void}
|
| + */
|
| + function callbackForNpapi(configStr) {
|
| + var config = jsonParseSafe(configStr);
|
| + if (typeof(config) != 'object') {
|
| + onError(remoting.Error.UNEXPECTED);
|
| + } else {
|
| + onDone(/** @type {Object} */ (config));
|
| + }
|
| + }
|
| +
|
| switch (this.state_) {
|
| case remoting.HostDispatcher.State.UNKNOWN:
|
| this.pendingRequests_.push(
|
| @@ -185,6 +265,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getDaemonConfig(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getDaemonConfig(callbackForNpapi);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onDone({});
|
| break;
|
| @@ -205,6 +292,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| onDone(this.nativeMessagingHost_.getDaemonVersion());
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getDaemonVersion(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -226,6 +320,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getUsageStatsConsent(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getUsageStatsConsent(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -233,6 +334,36 @@
|
| };
|
|
|
| /**
|
| + * This function installs the host using the NPAPI plugin and should only be
|
| + * called on Windows.
|
| + *
|
| + * @param {function(remoting.HostController.AsyncResult):void} onDone
|
| + * @param {function(remoting.Error):void} onError
|
| + * @return {void}
|
| + */
|
| +remoting.HostDispatcher.prototype.installHost = function(onDone, onError) {
|
| + switch (this.state_) {
|
| + case remoting.HostDispatcher.State.UNKNOWN:
|
| + this.pendingRequests_.push(this.installHost.bind(this, onDone, onError));
|
| + break;
|
| + case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| + // Host already installed, no action needed.
|
| + onDone(remoting.HostController.AsyncResult.OK);
|
| + break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.installHost(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| + case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + break;
|
| + }
|
| +};
|
| +
|
| +/**
|
| * @param {Object} config
|
| * @param {boolean} consent
|
| * @param {function(remoting.HostController.AsyncResult):void} onDone
|
| @@ -249,6 +380,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.startDaemon(config, consent, onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.startDaemon(JSON.stringify(config), consent, onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -268,6 +406,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.stopDaemon(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.stopDaemon(onDone);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -305,6 +450,16 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getDaemonState(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + // Call the callback directly, since NPAPI exposes the state directly as
|
| + // a field member, rather than an asynchronous method.
|
| + var state = this.npapiHost_.daemonState;
|
| + if (state === undefined) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + } else {
|
| + onDone(state);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onDone(remoting.HostController.State.NOT_INSTALLED);
|
| break;
|
| @@ -317,6 +472,22 @@
|
| * @return {void}
|
| */
|
| remoting.HostDispatcher.prototype.getPairedClients = function(onDone, onError) {
|
| + /**
|
| + * Converts the JSON string from the NPAPI plugin to Array.<PairedClient>, to
|
| + * pass to |onDone|.
|
| + * @param {string} pairedClientsJson
|
| + * @return {void}
|
| + */
|
| + function callbackForNpapi(pairedClientsJson) {
|
| + var pairedClients = remoting.PairedClient.convertToPairedClientArray(
|
| + jsonParseSafe(pairedClientsJson));
|
| + if (pairedClients != null) {
|
| + onDone(pairedClients);
|
| + } else {
|
| + onError(remoting.Error.UNEXPECTED);
|
| + }
|
| + }
|
| +
|
| switch (this.state_) {
|
| case remoting.HostDispatcher.State.UNKNOWN:
|
| this.pendingRequests_.push(
|
| @@ -325,6 +496,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getPairedClients(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.getPairedClients(callbackForNpapi);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -366,6 +544,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.clearPairedClients(callback, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.clearPairedClients(callback);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -390,6 +575,13 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.deletePairedClient(client, callback, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + try {
|
| + this.npapiHost_.deletePairedClient(client, callback);
|
| + } catch (err) {
|
| + onError(remoting.Error.MISSING_PLUGIN);
|
| + }
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -411,6 +603,11 @@
|
| case remoting.HostDispatcher.State.NATIVE_MESSAGING:
|
| this.nativeMessagingHost_.getHostClientId(onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + // The NPAPI plugin is packaged with the webapp, not the host, so it
|
| + // doesn't have access to the API keys baked into the installed host.
|
| + onError(remoting.Error.UNEXPECTED);
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| @@ -435,8 +632,21 @@
|
| this.nativeMessagingHost_.getCredentialsFromAuthCode(
|
| authorizationCode, onDone, onError);
|
| break;
|
| + case remoting.HostDispatcher.State.NPAPI:
|
| + // The NPAPI plugin is packaged with the webapp, not the host, so it
|
| + // doesn't have access to the API keys baked into the installed host.
|
| + onError(remoting.Error.UNEXPECTED);
|
| + break;
|
| case remoting.HostDispatcher.State.NOT_INSTALLED:
|
| onError(remoting.Error.MISSING_PLUGIN);
|
| break;
|
| }
|
| };
|
| +
|
| +/**
|
| + * Returns true if the NPAPI plugin is being used.
|
| + * @return {boolean}
|
| + */
|
| +remoting.HostDispatcher.prototype.usingNpapiPlugin = function() {
|
| + return this.state_ == remoting.HostDispatcher.State.NPAPI;
|
| +}
|
|
|