Skip to content

Commit

Permalink
Allowed multiple plugins for one scheme
Browse files Browse the repository at this point in the history
This modified the networking engine to store every plugin it is given
for a scheme, and adds a priority system to pick which of the plugins
to use.

Issue #829

Change-Id: I21a8a534383f2be898160d609d77efecfc2b684b
  • Loading branch information
theodab committed Nov 3, 2017
1 parent 3cd9b6a commit fefe934
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 19 deletions.
6 changes: 4 additions & 2 deletions lib/net/http_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ shaka.net.HttpPlugin = function(uri, request) {
};


shaka.net.NetworkingEngine.registerScheme('http', shaka.net.HttpPlugin);
shaka.net.NetworkingEngine.registerScheme('https', shaka.net.HttpPlugin);
shaka.net.NetworkingEngine.registerScheme('http', shaka.net.HttpPlugin,
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);
shaka.net.NetworkingEngine.registerScheme('https', shaka.net.HttpPlugin,
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);

52 changes: 47 additions & 5 deletions lib/net/networking_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,66 @@ shaka.net.NetworkingEngine.RequestType = {
};


/**
* Priority level for network scheme plugins.
* If multiple plugins are provided for the same scheme, only the
* highest-priority one is used.
*
* @enum {number}
* @export
*/
shaka.net.NetworkingEngine.PluginPriority = {
FALLBACK: 1,
PREFERRED: 2,
APPLICATION: 3
};


/**
* @typedef {{
* plugin: shakaExtern.SchemePlugin,
* priority: number
* }}
* @property {shakaExtern.SchemePlugin} plugin
* The associated plugin.
* @property {number} priority
* The plugin's priority.
*/
shaka.net.NetworkingEngine.SchemeObject;


/**
* Contains the scheme plugins.
*
* @private {!Object.<string, ?shakaExtern.SchemePlugin>}
* @private {!Object.<string, shaka.net.NetworkingEngine.SchemeObject>}
*/
shaka.net.NetworkingEngine.schemes_ = {};


/**
* Registers a scheme plugin. This plugin will handle all requests with the
* given scheme. If a plugin with the same scheme already exists, it is
* replaced.
* replaced, unless the existing plugin is of higher priority.
* If no priority is provided, this defaults to the highest priority of
* APPLICATION.
*
* @param {string} scheme
* @param {shakaExtern.SchemePlugin} plugin
* @param {number=} opt_priority
* @export
*/
shaka.net.NetworkingEngine.registerScheme = function(scheme, plugin) {
shaka.net.NetworkingEngine.schemes_[scheme] = plugin;
shaka.net.NetworkingEngine.registerScheme =
function(scheme, plugin, opt_priority) {
goog.asserts.assert(opt_priority == undefined || opt_priority > 0,
'explicit priority must be > 0');
var priority =
opt_priority || shaka.net.NetworkingEngine.PluginPriority.APPLICATION;
var existing = shaka.net.NetworkingEngine.schemes_[scheme];
if (!existing || priority >= existing.priority)
shaka.net.NetworkingEngine.schemes_[scheme] = {
priority: priority,
plugin: plugin
};
};


Expand Down Expand Up @@ -354,7 +395,8 @@ shaka.net.NetworkingEngine.prototype.send_ = function(
request.uris[index] = uri.toString();
}

var plugin = shaka.net.NetworkingEngine.schemes_[scheme];
var object = shaka.net.NetworkingEngine.schemes_[scheme];
var plugin = object ? object.plugin : null;
if (!plugin) {
return Promise.reject(new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
Expand Down
87 changes: 75 additions & 12 deletions test/net/networking_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
};
});

function makeResolveScheme(spyName) {
return jasmine.createSpy(spyName).and.callFake(
function() {
return Promise.resolve({
uri: '', data: new ArrayBuffer(5), headers: {}
});
});
}

beforeEach(function() {
fakeProtocol = 'http:';
error = new shaka.util.Error(
Expand All @@ -51,18 +60,15 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
shaka.util.Error.Code.HTTP_ERROR);

networkingEngine = new shaka.net.NetworkingEngine();
resolveScheme = jasmine.createSpy('resolve scheme').and.callFake(
function() {
return Promise.resolve({
uri: '', data: new ArrayBuffer(5), headers: {}
});
});
resolveScheme = makeResolveScheme('resolve scheme');
rejectScheme = jasmine.createSpy('reject scheme')
.and.callFake(function() { return Promise.reject(error); });
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(resolveScheme));
'resolve', Util.spyFunc(resolveScheme),
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);
shaka.net.NetworkingEngine.registerScheme(
'reject', Util.spyFunc(rejectScheme));
'reject', Util.spyFunc(rejectScheme),
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);
});

afterEach(function() {
Expand Down Expand Up @@ -263,13 +269,54 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
});

describe('request', function() {
it('uses registered schemes', function(done) {
networkingEngine.request(requestType, createRequest('resolve://foo'))
function testResolve(schemeSpy) {
return networkingEngine.request(
requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function() {
expect(resolveScheme).toHaveBeenCalled();
done();
expect(schemeSpy).toHaveBeenCalled();
});
}

it('uses registered schemes', function(done) {
testResolve(resolveScheme).then(done);
});

it('uses registered scheme plugins in order of priority', function(done) {
var applicationResolveScheme =
makeResolveScheme('application resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(applicationResolveScheme),
shaka.net.NetworkingEngine.PluginPriority.APPLICATION);
var preferredResolveScheme =
makeResolveScheme('preferred resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(preferredResolveScheme),
shaka.net.NetworkingEngine.PluginPriority.PREFERRED);

testResolve(applicationResolveScheme).then(done);
});

it('uses newest scheme plugin in case of tie in priority', function(done) {
var secondResolveScheme = makeResolveScheme('second resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(secondResolveScheme),
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);

testResolve(secondResolveScheme).then(done);
});

it('defaults new scheme plugins to application priority', function(done) {
var secondResolveScheme = makeResolveScheme('second resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(secondResolveScheme));
var preferredResolveScheme =
makeResolveScheme('preferred resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(preferredResolveScheme),
shaka.net.NetworkingEngine.PluginPriority.PREFERRED);

testResolve(secondResolveScheme).then(done);
});

it('can unregister scheme', function(done) {
Expand All @@ -280,6 +327,22 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
.then(done);
});

it('unregister removes all plugins for scheme at once', function(done) {
var preferredResolveScheme =
makeResolveScheme('preferred resolve scheme');
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(preferredResolveScheme),
shaka.net.NetworkingEngine.PluginPriority.PREFERRED);

shaka.net.NetworkingEngine.unregisterScheme('resolve');
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(fail)
.catch(function() {
expect(resolveScheme).not.toHaveBeenCalled();
expect(preferredResolveScheme).not.toHaveBeenCalled();
}).then(done);
});

it('rejects if scheme does not exist', function(done) {
networkingEngine.request(requestType, createRequest('foo://foo'))
.then(fail)
Expand Down

0 comments on commit fefe934

Please sign in to comment.