Fix rare race condition with webworker tasks, fix minified web worker filename default

This commit is contained in:
Bart Butler 2016-10-26 16:56:21 -07:00
parent 778f1b1be2
commit 6abf7ffcc0
3 changed files with 39 additions and 20 deletions

View File

@ -79,11 +79,6 @@ module.exports = function(grunt) {
'dist/openpgp.worker.js': [ './src/worker/worker.js' ] 'dist/openpgp.worker.js': [ './src/worker/worker.js' ]
} }
}, },
worker_min: {
files: {
'dist/openpgp.worker.min.js': [ './src/worker/worker.js' ]
}
},
unittests: { unittests: {
files: { files: {
'test/lib/unittests-bundle.js': [ './test/unittests.js' ] 'test/lib/unittests-bundle.js': [ './test/unittests.js' ]
@ -110,12 +105,20 @@ module.exports = function(grunt) {
to: 'OpenPGP.js v<%= pkg.version %>' to: 'OpenPGP.js v<%= pkg.version %>'
}] }]
}, },
openpgp_min: {
src: ['dist/openpgp.min.js'],
dest: ['dist/openpgp.min.js'],
replacements: [{
from: "openpgp.worker.js",
to: "openpgp.worker.min.js"
}]
},
worker_min: { worker_min: {
src: ['dist/openpgp.worker.min.js'], src: ['dist/openpgp.worker.min.js'],
dest: ['dist/openpgp.worker.min.js'], dest: ['dist/openpgp.worker.min.js'],
replacements: [{ replacements: [{
from: "importScripts('openpgp.js')", from: "openpgp.js",
to: "importScripts('openpgp.min.js')" to: "openpgp.min.js"
}] }]
} }
}, },
@ -123,7 +126,7 @@ module.exports = function(grunt) {
openpgp: { openpgp: {
files: { files: {
'dist/openpgp.min.js' : [ 'dist/openpgp.js' ], 'dist/openpgp.min.js' : [ 'dist/openpgp.js' ],
'dist/openpgp.worker.min.js' : [ 'dist/openpgp.worker.min.js' ] 'dist/openpgp.worker.min.js' : [ 'dist/openpgp.worker.js' ]
} }
}, },
options: { options: {
@ -292,7 +295,9 @@ module.exports = function(grunt) {
} }
// Build tasks // Build tasks
grunt.registerTask('default', ['clean', 'copy:zlib', 'browserify', 'replace', 'uglify']); grunt.registerTask('version', ['replace:openpgp', 'replace:openpgp_debug']);
grunt.registerTask('replace_min', ['replace:openpgp_min', 'replace:worker_min']);
grunt.registerTask('default', ['clean', 'copy:zlib', 'browserify', 'version', 'uglify', 'replace_min']);
grunt.registerTask('documentation', ['jsdoc']); grunt.registerTask('documentation', ['jsdoc']);
// Test/Dev tasks // Test/Dev tasks
grunt.registerTask('test', ['jshint', 'jscs', 'mochaTest']); grunt.registerTask('test', ['jshint', 'jscs', 'mochaTest']);

View File

@ -39,13 +39,24 @@ export default function AsyncProxy({ path='openpgp.worker.js', worker, config }
throw new Error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')'); throw new Error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')');
}; };
this.seedRandom(INITIAL_RANDOM_SEED); this.seedRandom(INITIAL_RANDOM_SEED);
// FIFO
this.tasks = [];
if (config) { if (config) {
this.worker.postMessage({ event:'configure', config }); this.worker.postMessage({ event:'configure', config });
} }
// Cannot rely on task order being maintained, use object keyed by request ID to track tasks
this.tasks = {};
this.currentID = 0;
} }
/**
* Get new request ID
* @return {integer} New unique request ID
*/
AsyncProxy.prototype.getID = function() {
return this.currentID++;
};
/** /**
* Message handling * Message handling
*/ */
@ -55,11 +66,12 @@ AsyncProxy.prototype.onMessage = function(event) {
case 'method-return': case 'method-return':
if (msg.err) { if (msg.err) {
// fail // fail
this.tasks.shift().reject(new Error(msg.err)); this.tasks[msg.id].reject(new Error(msg.err));
} else { } else {
// success // success
this.tasks.shift().resolve(msg.data); this.tasks[msg.id].resolve(msg.data);
} }
delete this.tasks[msg.id];
break; break;
case 'request-seed': case 'request-seed':
this.seedRandom(RANDOM_SEED_REQUEST); this.seedRandom(RANDOM_SEED_REQUEST);
@ -106,11 +118,13 @@ AsyncProxy.prototype.terminate = function() {
* @return {Promise} see the corresponding public api functions for their return types * @return {Promise} see the corresponding public api functions for their return types
*/ */
AsyncProxy.prototype.delegate = function(method, options) { AsyncProxy.prototype.delegate = function(method, options) {
const id = this.getID();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// clone packets (for web worker structured cloning algorithm) // clone packets (for web worker structured cloning algorithm)
this.worker.postMessage({ event:method, options:packet.clone.clonePackets(options) }, util.getTransferables.call(util, options)); this.worker.postMessage({ id:id, event:method, options:packet.clone.clonePackets(options) }, util.getTransferables.call(util, options));
// remember to handle parsing cloned packets from worker // remember to handle parsing cloned packets from worker
this.tasks.push({ resolve: data => resolve(packet.clone.parseClonedPackets(data, method)), reject }); this.tasks[id] = { resolve: data => resolve(packet.clone.parseClonedPackets(data, method)), reject };
}); });
}; };

View File

@ -44,7 +44,7 @@ self.onmessage = function(event) {
break; break;
default: default:
delegate(msg.event, msg.options || {}); delegate(msg.id, msg.event, msg.options || {});
} }
}; };
@ -75,18 +75,18 @@ function seedRandom(buffer) {
* @param {String} method The public api function to be delegated to the worker thread * @param {String} method The public api function to be delegated to the worker thread
* @param {Object} options The api function's options * @param {Object} options The api function's options
*/ */
function delegate(method, options) { function delegate(id, method, options) {
if (typeof openpgp[method] !== 'function') { if (typeof openpgp[method] !== 'function') {
response({ event:'method-return', err:'Unknown Worker Event' }); response({ id:id, event:'method-return', err:'Unknown Worker Event' });
return; return;
} }
// parse cloned packets // parse cloned packets
options = openpgp.packet.clone.parseClonedPackets(options, method); options = openpgp.packet.clone.parseClonedPackets(options, method);
openpgp[method](options).then(function(data) { openpgp[method](options).then(function(data) {
// clone packets (for web worker structured cloning algorithm) // clone packets (for web worker structured cloning algorithm)
response({ event:'method-return', data:openpgp.packet.clone.clonePackets(data) }); response({ id:id, event:'method-return', data:openpgp.packet.clone.clonePackets(data) });
}).catch(function(e) { }).catch(function(e) {
response({ event:'method-return', err:e.message }); response({ id:id, event:'method-return', err:e.message });
}); });
} }