Initial commit of 001code-html Scratch frontend project.
Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
113
scratch-vm/src/dispatch/worker-dispatch.js
Normal file
113
scratch-vm/src/dispatch/worker-dispatch.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const SharedDispatch = require('./shared-dispatch');
|
||||
|
||||
const log = require('../util/log');
|
||||
const {centralDispatchService} = require('../extension-support/tw-extension-worker-context');
|
||||
|
||||
/**
|
||||
* This class provides a Worker with the means to participate in the message dispatch system managed by CentralDispatch.
|
||||
* From any context in the messaging system, the dispatcher's "call" method can call any method on any "service"
|
||||
* provided in any participating context. The dispatch system will forward function arguments and return values across
|
||||
* worker boundaries as needed.
|
||||
* @see {CentralDispatch}
|
||||
*/
|
||||
class WorkerDispatch extends SharedDispatch {
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
/**
|
||||
* This promise will be resolved when we have successfully connected to central dispatch.
|
||||
* @type {Promise}
|
||||
* @see {waitForConnection}
|
||||
* @private
|
||||
*/
|
||||
this._connectionPromise = new Promise(resolve => {
|
||||
this._onConnect = resolve;
|
||||
});
|
||||
|
||||
/**
|
||||
* Map of service name to local service provider.
|
||||
* If a service is not listed here, it is assumed to be provided by another context (another Worker or the main
|
||||
* thread).
|
||||
* @see {setService}
|
||||
* @type {object}
|
||||
*/
|
||||
this.services = {};
|
||||
|
||||
this._onMessage = this._onMessage.bind(this, centralDispatchService);
|
||||
if (typeof self !== 'undefined') {
|
||||
self.onmessage = this._onMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise} a promise which will resolve upon connection to central dispatch. If you need to make a call
|
||||
* immediately on "startup" you can attach a 'then' to this promise.
|
||||
* @example
|
||||
* dispatch.waitForConnection.then(() => {
|
||||
* dispatch.call('myService', 'hello');
|
||||
* })
|
||||
*/
|
||||
get waitForConnection () {
|
||||
return this._connectionPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a local object as the global provider of the specified service.
|
||||
* WARNING: Any method on the provider can be called from any worker within the dispatch system.
|
||||
* @param {string} service - a globally unique string identifying this service. Examples: 'vm', 'gui', 'extension9'.
|
||||
* @param {object} provider - a local object which provides this service.
|
||||
* @returns {Promise} - a promise which will resolve once the service is registered.
|
||||
*/
|
||||
setService (service, provider) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.services, service)) {
|
||||
log.warn(`Worker dispatch replacing existing service provider for ${service}`);
|
||||
}
|
||||
this.services[service] = provider;
|
||||
return this.waitForConnection.then(() => (
|
||||
this._remoteCall(centralDispatchService, 'dispatch', 'setService', service)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the service provider object for a particular service name.
|
||||
* @override
|
||||
* @param {string} service - the name of the service to look up
|
||||
* @returns {{provider:(object|Worker), isRemote:boolean}} - the means to contact the service, if found
|
||||
* @protected
|
||||
*/
|
||||
_getServiceProvider (service) {
|
||||
// if we don't have a local service by this name, contact central dispatch by calling `postMessage` on self
|
||||
const provider = this.services[service];
|
||||
return {
|
||||
provider: provider || centralDispatchService,
|
||||
isRemote: !provider
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a call message sent to the dispatch service itself
|
||||
* @override
|
||||
* @param {Worker} worker - the worker which sent the message.
|
||||
* @param {DispatchCallMessage} message - the message to be handled.
|
||||
* @returns {Promise|undefined} - a promise for the results of this operation, if appropriate
|
||||
* @protected
|
||||
*/
|
||||
_onDispatchMessage (worker, message) {
|
||||
let promise;
|
||||
switch (message.method) {
|
||||
case 'handshake':
|
||||
promise = this._onConnect();
|
||||
break;
|
||||
case 'terminate':
|
||||
// Don't close until next tick, after sending confirmation back
|
||||
setTimeout(() => self.close(), 0);
|
||||
promise = Promise.resolve();
|
||||
break;
|
||||
default:
|
||||
log.error(`Worker dispatch received message for unknown method: ${message.method}`);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new WorkerDispatch();
|
||||
Reference in New Issue
Block a user