monaca-lib
Version:
Monaca cloud API bindings for JavaScript
277 lines (248 loc) • 7.89 kB
JavaScript
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var WorkerRuntime = {};
/**
* @param {string} moduleName
* @param {string} workerName
* @return {!Promise.<!SharedWorker>}
*/
WorkerRuntime.startSharedWorker = function(moduleName, workerName)
{
if (Runtime.isReleaseMode()) {
try {
var worker = new SharedWorker(moduleName + "_module.js", workerName);
return Promise.resolve(worker);
} catch (e) {
return Promise.reject(e);
}
}
return loadResourcePromise(moduleName + "/module.json").then(start, start.bind(null, undefined));
/**
* @param {string=} content
* @return {!SharedWorker}
*/
function start(content)
{
if (!content)
throw new Error("Worker is not defined: " + moduleName + " " + new Error().stack);
var scripts = JSON.parse(content)["scripts"];
if (scripts.length !== 1)
throw new Error("WorkerRuntime.startSharedWorker supports modules with only one script!");
return new SharedWorker(moduleName + "/" + scripts[0], workerName);
}
}
/**
* @param {string} moduleName
* @return {!Promise.<!Worker>}
*/
WorkerRuntime.startWorker = function(moduleName)
{
if (Runtime.isReleaseMode())
return Promise.resolve(new Worker(moduleName + "_module.js"));
/**
* @suppress {checkTypes}
*/
var loader = function() {
self.onmessage = function(event) {
self.onmessage = null;
var scripts = event.data;
for (var i = 0; i < scripts.length; ++i) {
var source = scripts[i]["source"];
self.eval(source + "\n//# sourceURL=" + scripts[i]["url"]);
}
};
};
return loadResourcePromise(moduleName + "/module.json").then(start, start.bind(null, undefined));
/**
* @param {string=} content
*/
function start(content)
{
if (!content)
throw new Error("Worker is not defined: " + moduleName + " " + new Error().stack);
var message = [];
var scripts = JSON.parse(content)["scripts"];
var promise = Promise.resolve();
for (var i = 0; i < scripts.length; ++i) {
var url = self._importScriptPathPrefix + moduleName + "/" + scripts[i];
var parts = url.split("://");
url = parts.length === 1 ? url : parts[0] + "://" + normalizePath(parts[1]);
promise = promise.then(promiseGetter(loadResourcePromise(moduleName + "/" + scripts[i]))).then(pushSource.bind(null, url), pushSource.bind(null, null, null));
}
return promise.then(createWorker);
function promiseGetter(promise)
{
return function() {
return promise;
};
}
/**
* @param {?string} url
* @param {?string} source
*/
function pushSource(url, source)
{
if (!url) {
console.error("Failed to load " + url);
return;
}
message.push({ source: source, url: url });
}
/**
* @return {!Worker}
*/
function createWorker()
{
var blob = new Blob(["(" + loader.toString() + ")()\n//# sourceURL=" + moduleName], { type: "text/javascript" });
var workerURL = window.URL.createObjectURL(blob);
try {
var worker = new Worker(workerURL);
worker.postMessage(message);
return worker;
} finally {
window.URL.revokeObjectURL(workerURL);
}
}
}
}
/**
* @constructor
* @param {string} moduleName
* @param {string=} workerName
*/
WorkerRuntime.Worker = function(moduleName, workerName)
{
this._isSharedWorker = !!workerName;
this._workerPromise = workerName ? WorkerRuntime.startSharedWorker(moduleName, /** @type {string} */ (workerName)) : WorkerRuntime.startWorker(moduleName);
}
WorkerRuntime.Worker.prototype = {
/**
* @param {*} message
*/
postMessage: function(message)
{
this._workerPromise.then(postToWorker.bind(this));
/**
* @param {!Worker|!SharedWorker} worker
* @this {WorkerRuntime.Worker}
*/
function postToWorker(worker)
{
if (!this._disposed)
worker.postMessage(message);
}
},
dispose: function()
{
this._disposed = true;
this._workerPromise.then(terminate);
/**
* @param {!Worker|!SharedWorker} worker
*/
function terminate(worker)
{
worker.terminate();
}
},
terminate: function()
{
this.dispose();
},
/**
* @param {?function(!MessageEvent.<*>)} listener
*/
set onmessage(listener)
{
this._workerPromise.then(setOnMessage);
/**
* @param {!Worker|!SharedWorker} worker
*/
function setOnMessage(worker)
{
worker.onmessage = listener;
}
},
/**
* @param {?function(!Event)} listener
*/
set onerror(listener)
{
this._workerPromise.then(setOnError);
/**
* @param {!Worker|!SharedWorker} worker
*/
function setOnError(worker)
{
worker.onerror = listener;
}
},
get port()
{
return new WorkerRuntime.Worker.FuturePort(this);
}
}
/**
* @constructor
* @param {!WorkerRuntime.Worker} worker
*/
WorkerRuntime.Worker.FuturePort = function(worker)
{
this._worker = worker;
}
WorkerRuntime.Worker.FuturePort.prototype = {
/**
* @param {?function(!MessageEvent.<?>)} listener
*/
set onmessage(listener)
{
this._worker._workerPromise.then(setOnMessage);
/**
* @param {!SharedWorker} worker
*/
function setOnMessage(worker)
{
worker.port.onmessage = listener;
}
},
/**
* @param {?function(!Event)} listener
*/
set onerror(listener)
{
this._worker._workerPromise.then(setOnError);
/**
* @param {!SharedWorker} worker
*/
function setOnError(worker)
{
worker.port.onerror = listener;
}
}
}