import * as Collections from '../utils/collections';
import Util from '../util';
import Strategy from './strategy';
/** Launches all substrategies and emits prioritized connected transports.
*
* @param {Array} strategies
*/
export default class BestConnectedEverStrategy implements Strategy {
strategies: Strategy[];
constructor(strategies: Strategy[]) {
this.strategies = strategies;
}
isSupported(): boolean {
return Collections.any(this.strategies, Util.method('isSupported'));
}
connect(minPriority: number, callback: Function) {
return connect(this.strategies, minPriority, function(i, runners) {
return function(error, handshake) {
runners[i].error = error;
if (error) {
if (allRunnersFailed(runners)) {
callback(true);
}
return;
}
Collections.apply(runners, function(runner) {
runner.forceMinPriority(handshake.transport.priority);
});
callback(null, handshake);
};
});
}
}
/** Connects to all strategies in parallel.
*
* Callback builder should be a function that takes two arguments: index
* and a list of runners. It should return another function that will be
* passed to the substrategy with given index. Runners can be aborted using
* abortRunner(s) functions from this class.
*
* @param {Array} strategies
* @param {Function} callbackBuilder
* @return {Object} strategy runner
*/
function connect(
strategies: Strategy[],
minPriority: number,
callbackBuilder: Function
) {
var runners = Collections.map(strategies, function(strategy, i, _, rs) {
return strategy.connect(minPriority, callbackBuilder(i, rs));
});
return {
abort: function() {
Collections.apply(runners, abortRunner);
},
forceMinPriority: function(p) {
Collections.apply(runners, function(runner) {
runner.forceMinPriority(p);
});
}
};
}
function allRunnersFailed(runners): boolean {
return Collections.all(runners, function(runner) {
return Boolean(runner.error);
});
}
function abortRunner(runner) {
if (!runner.error && !runner.aborted) {
runner.abort();
runner.aborted = true;
}
}
|