UNPKG

monaca-lib

Version:

Monaca cloud API bindings for JavaScript

277 lines (248 loc) 7.89 kB
/* * 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; } } }