mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-06-10 12:31:21 -04:00
Refuse to register second extension with same ID
If an extension attempts to register with the same ID as another extension which has already registered, the new registration is refused. If the extension is in a worker and no other extension is successfully registered by that worker, the watchdog system will terminate the "empty" worker.
This commit is contained in:
parent
e4381b4693
commit
670e51d335
2 changed files with 47 additions and 9 deletions
src
|
@ -55,6 +55,19 @@ class CentralDispatch extends SharedDispatch {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a service without regard to which object or worker might provide it.
|
||||
* @param {string} service - the globally unique string provided to `setService` when the service was registered.
|
||||
* @see {setService}
|
||||
*/
|
||||
clearService (service) {
|
||||
if (this.services.hasOwnProperty(service)) {
|
||||
delete this.services[service];
|
||||
} else {
|
||||
log.warn(`Central dispatch can't clear unknown service ${service}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a worker to the message dispatch system. The worker must implement a compatible message dispatch framework.
|
||||
* The dispatcher will immediately attempt to "handshake" with the worker.
|
||||
|
|
|
@ -70,6 +70,13 @@ class ExtensionManager {
|
|||
*/
|
||||
this.pendingWorkers = [];
|
||||
|
||||
/**
|
||||
* Set of loaded extension IDs. For built-in extensions the "URL" is the same as the ID; they differ in general.
|
||||
* @type {Set.<string>}
|
||||
* @private
|
||||
*/
|
||||
this._loadedExtensions = new Set();
|
||||
|
||||
/**
|
||||
* Set of workers currently being monitored by `_startWorkerWatchdog`.
|
||||
* @see {_startWorkerWatchdog}
|
||||
|
@ -90,6 +97,17 @@ class ExtensionManager {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an extension is registered or is in the process of loading. This is intended to control loading or
|
||||
* adding extensions so it may return `true` before the extension is ready to be used. Use the promise returned by
|
||||
* `loadExtensionURL` if you need to wait until the extension is truly ready.
|
||||
* @param {string} extensionID - the ID (not URL) of the extension.
|
||||
* @returns {boolean} - true if loaded, false otherwise.
|
||||
*/
|
||||
isExtensionLoaded (extensionID) {
|
||||
return this._loadedExtensions.has(extensionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an extension by URL or internal extension ID
|
||||
* @param {string} extensionURL - the URL for the extension to load OR the ID of an internal extension
|
||||
|
@ -170,15 +188,22 @@ class ExtensionManager {
|
|||
*/
|
||||
_registerExtensionInfo (serviceName, extensionInfo) {
|
||||
extensionInfo = this._prepareExtensionInfo(serviceName, extensionInfo);
|
||||
dispatch.call('runtime', '_registerExtensionPrimitives', extensionInfo).then(
|
||||
() => {
|
||||
if (dispatch.callingWorker) {
|
||||
this._stopWorkerWatchdog(dispatch.callingWorker);
|
||||
}
|
||||
},
|
||||
e => {
|
||||
log.error(`Failed to register primitives for extension "${extensionInfo.id}": ${e.message}`);
|
||||
});
|
||||
if (this.isExtensionLoaded(extensionInfo.id)) {
|
||||
const message = `Ignoring attempt to load a second extension with ID ${extensionInfo.id}`;
|
||||
log.warn(message);
|
||||
dispatch.clearService(serviceName);
|
||||
} else {
|
||||
dispatch.call('runtime', '_registerExtensionPrimitives', extensionInfo).then(
|
||||
() => {
|
||||
this._loadedExtensions.add(extensionInfo.id);
|
||||
if (dispatch.callingWorker) {
|
||||
this._stopWorkerWatchdog(dispatch.callingWorker);
|
||||
}
|
||||
},
|
||||
e => {
|
||||
log.error(`Failed to register primitives for extension "${extensionInfo.id}": ${e.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue