// Copyright 2013 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
* This class provides an interface between the HostController and either the
* NativeMessaging Host.
*/
'use strict';
/** @suppress {duplicate} */
var remoting = remoting || {};
/**
* @constructor
*/
remoting.HostDispatcher = function() {
/** @type {remoting.HostNativeMessaging} @private */
this.nativeMessagingHost_ = new remoting.HostNativeMessaging();
/** @type {remoting.HostDispatcher.State} @private */
this.state_ = remoting.HostDispatcher.State.UNKNOWN;
/** @type {Array.<function()>} @private */
this.pendingRequests_ = [];
this.tryToInitialize_();
}
/** @enum {number} */
remoting.HostDispatcher.State = {
UNKNOWN: 0,
NATIVE_MESSAGING: 1,
NOT_INSTALLED: 2
};
remoting.HostDispatcher.prototype.tryToInitialize_ = function() {
/** @type {remoting.HostDispatcher} */
var that = this;
if (this.state_ != remoting.HostDispatcher.State.UNKNOWN)
return;
function sendPendingRequests() {
var pendingRequests = that.pendingRequests_;
that.pendingRequests_ = [];
for (var i = 0; i < pendingRequests.length; i++) {
pendingRequests[i]();
}
}
function onNativeMessagingInit() {
that.state_ = remoting.HostDispatcher.State.NATIVE_MESSAGING;
sendPendingRequests();
}
function onNativeMessagingFailed(error) {
that.state_ = remoting.HostDispatcher.State.NOT_INSTALLED;
sendPendingRequests();
}
this.nativeMessagingHost_.initialize(onNativeMessagingInit,
onNativeMessagingFailed);
};
/**
* @param {remoting.HostController.Feature} feature The feature to test for.
* @param {function(boolean):void} onDone
* @return {void}
*/
remoting.HostDispatcher.prototype.hasFeature = function(
feature, onDone) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.hasFeature.bind(this, feature, onDone));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
onDone(this.nativeMessagingHost_.hasFeature(feature));
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onDone(false);
break;
}
};
/**
* @param {function(string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getHostName = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getHostName.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getHostName(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {string} hostId
* @param {string} pin
* @param {function(string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getPinHash =
function(hostId, pin, onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getPinHash.bind(this, hostId, pin, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getPinHash(hostId, pin, onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(string, string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.generateKeyPair = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.generateKeyPair.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.generateKeyPair(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {Object} config
* @param {function(remoting.HostController.AsyncResult):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.updateDaemonConfig =
function(config, onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.updateDaemonConfig.bind(this, config, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.updateDaemonConfig(config, onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(Object):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getDaemonConfig = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getDaemonConfig.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getDaemonConfig(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onDone({});
break;
}
};
/**
* @param {function(string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getDaemonVersion = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getDaemonVersion.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
onDone(this.nativeMessagingHost_.getDaemonVersion());
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(boolean, boolean, boolean):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getUsageStatsConsent =
function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getUsageStatsConsent.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getUsageStatsConsent(onDone, onError);
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
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.startDaemon =
function(config, consent, onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.startDaemon.bind(this, config, consent, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.startDaemon(config, consent, onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(remoting.HostController.AsyncResult):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.stopDaemon = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(this.stopDaemon.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.stopDaemon(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(remoting.HostController.State):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getDaemonState = function(onDone, onError) {
// If the host was in not-initialized state try initializing it again in case
// it was installed.
if (this.state_ == remoting.HostDispatcher.State.NOT_INSTALLED) {
this.state_ = remoting.HostDispatcher.State.UNKNOWN;
this.tryToInitialize_();
}
this.getDaemonStateInternal_(onDone, onError);
}
/**
* @param {function(remoting.HostController.State):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getDaemonStateInternal_ =
function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getDaemonStateInternal_.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getDaemonState(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onDone(remoting.HostController.State.NOT_INSTALLED);
break;
}
};
/**
* @param {function(Array.<remoting.PairedClient>):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getPairedClients = function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getPairedClients.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getPairedClients(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* The pairing API returns a boolean to indicate success or failure, but
* the JS API is defined in terms of onDone and onError callbacks. This
* function converts one to the other.
*
* @param {function():void} onDone Success callback.
* @param {function(remoting.Error):void} onError Error callback.
* @param {boolean} success True if the operation succeeded; false otherwise.
* @private
*/
remoting.HostDispatcher.runCallback_ = function(onDone, onError, success) {
if (success) {
onDone();
} else {
onError(remoting.Error.UNEXPECTED);
}
};
/**
* @param {function():void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.clearPairedClients =
function(onDone, onError) {
var callback =
remoting.HostDispatcher.runCallback_.bind(null, onDone, onError);
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.clearPairedClients.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.clearPairedClients(callback, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {string} client
* @param {function():void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.deletePairedClient =
function(client, onDone, onError) {
var callback =
remoting.HostDispatcher.runCallback_.bind(null, onDone, onError);
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.deletePairedClient.bind(this, client, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.deletePairedClient(client, callback, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {function(string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getHostClientId =
function(onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getHostClientId.bind(this, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getHostClientId(onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};
/**
* @param {string} authorizationCode
* @param {function(string, string):void} onDone
* @param {function(remoting.Error):void} onError
* @return {void}
*/
remoting.HostDispatcher.prototype.getCredentialsFromAuthCode =
function(authorizationCode, onDone, onError) {
switch (this.state_) {
case remoting.HostDispatcher.State.UNKNOWN:
this.pendingRequests_.push(
this.getCredentialsFromAuthCode.bind(
this, authorizationCode, onDone, onError));
break;
case remoting.HostDispatcher.State.NATIVE_MESSAGING:
this.nativeMessagingHost_.getCredentialsFromAuthCode(
authorizationCode, onDone, onError);
break;
case remoting.HostDispatcher.State.NOT_INSTALLED:
onError(remoting.Error.MISSING_PLUGIN);
break;
}
};