UNPKG

sku-pg

Version:

Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!

254 lines (216 loc) 7.77 kB
// Copyright 2007 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview This implementation of goog.gears.WorkerPool uses * a fake worker pool (FakeWorkerPool_) that is implemented as an iframe in the * current document. * */ goog.provide('goog.gears.FakeWorkerPool'); goog.require('goog.Uri'); goog.require('goog.gears'); goog.require('goog.gears.WorkerPool'); goog.require('goog.net.XmlHttp'); /** * This class implements a fake worker pool. It has the same interface as * the Gears WorkerPool object but uses an iframe and timers to emulate the * async nature of the message passing. * @constructor * @private */ goog.gears.FakeWorkerPool_ = function() { /** * Map from worker id to the frame element name * @private */ this.frameNames_ = {}; }; /** * Counter used to ensure that the frame get unique names * @type {number} * @private */ goog.gears.FakeWorkerPool_.idCounter_ = 1; /** * The id of the main worker * @type {number} * @private */ goog.gears.FakeWorkerPool_.mainWorkerId_ = 0; /** * Creates a new worker. * @param {string} url URL from which to get the code to execute inside the * worker. * @return {number} The ID of the worker that was created. */ goog.gears.FakeWorkerPool_.prototype.createWorkerFromUrl = function(url) { // TODO(user) make this async var xhr = new goog.net.XmlHttp(); xhr.open('GET', url, false); xhr.send(null); return this.createWorker(xhr.responseText); }; /** * Creates a worker and evals the code inside the worker. * @param {string} code The JavaScript code to evaluate in the worker. * @return {number} The ID of the worker that was created. */ goog.gears.FakeWorkerPool_.prototype.createWorker = function(code) { // HACK(user): Since this code is included in a worker thread we cannot // directly reference window var win = goog.getObjectByName('window'); // This will be dead code on a worker thread so we don't get here. It is // therefore OK to access win.document without square brackets. var doc = win.document; var iframeElement = doc.createElement('iframe'); var id = goog.gears.FakeWorkerPool_.idCounter_++; var name = iframeElement.name = iframeElement.id = 'fake-worker-' + id; doc.body.appendChild(iframeElement); var w = win.frames[name]; this.frameNames_[id] = name; var selfObj = this; var fakeGearsWorkerPool = { 'sendMessage': function(message, toId) { w.setTimeout(function() { selfObj.routeMessage_(message, id, toId); }, 1); }, 'allowCrossOrigin': function() { // Do nothing. } }; doc = w.document; doc.open(); w['google'] = { 'gears': { 'workerPool': fakeGearsWorkerPool, 'factory': goog.gears.getFactory() } }; // Make window, document and navigator undefined in the worker scope. // We cannot just set these to undefined because the properties are read // only. We therefore use a with statement to hide them to the scope. doc.write('<script>with ({window: undefined, document: undefined, ' + 'navigator: undefined}) {' + code + '}</script>'); doc.close(); return id; }; /** * Allows the worker who calls this to be used cross origin. This is not * currently supported. */ goog.gears.FakeWorkerPool_.prototype.allowCrossOrigin = function() { // Do nothing. This is not currently supported. }; /** * Sends a message to a worker * @param {string} message The message to send. * @param {number} workerId The id of the worker to send the message to. */ goog.gears.FakeWorkerPool_.prototype.sendMessage = function(message, workerId) { var w = this.getWindow_(workerId); var messageObject = this.createMessageObject_(message, workerId); // Use w.setTimeout instead of window.setTimeout because JSUnit overides that w.setTimeout(function() { w['google']['gears']['workerPool'].onmessage( String(message), goog.gears.FakeWorkerPool_.mainWorkerId_, messageObject); }, 1); }; /** * Callback for messages sent to this worker. Override to handle incoming * messages * @param {string} message The message sent to this worker. * @param {number} sender The id of the worker that sent this message. * @param {Object=} opt_messageObject An object containing all information about * the message. */ goog.gears.FakeWorkerPool_.prototype.onmessage = function(message, sender, opt_messageObject) { // Intentionally empty. The user should override this on the instance. }; /** * Routes the message to the right frame * @param {string} message The message sent to this worker. * @param {number} fromId The id of the worker that sent this message. * @param {number} toId The id of the worker to send the message to. * @private */ goog.gears.FakeWorkerPool_.prototype.routeMessage_ = function(message, fromId, toId) { var messageObject = this.createMessageObject_(message, fromId); if (toId == goog.gears.FakeWorkerPool_.mainWorkerId_) { this.onmessage(message, fromId, messageObject); } else { var w = this.getWindow_(toId); w['google']['gears']['workerPool'].onmessage( message, fromId, messageObject); } }; /** * Creates the message object. * @param {*} text The text of the message. * @param {number} sender The id of the sender. * @return {Object} The message object. * @private */ goog.gears.FakeWorkerPool_.prototype.createMessageObject_ = function( text, sender) { // Use the current window's location since this class currently does not // allow cross-domain creation of workers. var uri = new goog.Uri(goog.getObjectByName('window').location); // The origin is represented as SCHEME://DOMAIN[:PORT]. Standard ports 80 // and 443 are omitted. var port = uri.getPort(); var origin = uri.getScheme() + '://' + uri.getDomain() + (uri.hasPort() && port != 80 && port != 443 ? ':' + uri.getPort() : ''); return {'text': text, 'sender': sender, 'origin': origin, 'body': text}; }; /** * Returns the window/frame that is used to emulate the thread * @param {number} workerId The id of the worker. * @return {Window} The window/frame that is used to emulate the thread. * @private */ goog.gears.FakeWorkerPool_.prototype.getWindow_ = function(workerId) { var frameName = this.frameNames_[workerId]; if (frameName) { // HACK(user): Since this code is included in a worker thread we cannot // directly reference window var w = goog.getObjectByName('window.frames')[frameName]; if (w) return w; } throw Error('Could not access worker'); }; /** * The fake goog.gears.WorkerPool. Instead of wrapping the real Gears * WorkerPool it uses goog.gears.FakeWorkerPool_ * * @constructor * @extends {goog.gears.WorkerPool} */ goog.gears.FakeWorkerPool = function() { goog.gears.WorkerPool.call(this); }; goog.inherits(goog.gears.FakeWorkerPool, goog.gears.WorkerPool); /** * @return {Object} A fake Gears WorkerPool object. * @protected */ goog.gears.FakeWorkerPool.prototype.getGearsWorkerPool = function() { return new goog.gears.FakeWorkerPool_; };