Skip to content

Commit df027a5

Browse files
committed
fix: prevent infinite loop during plugin activation and improve activation logic
1 parent 885c49f commit df027a5

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

adminforth/index.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -212,25 +212,44 @@ class AdminForth implements IAdminForth {
212212
}
213213
}
214214
process.env.HEAVY_DEBUG && console.log(`🔌 Total plugins to activate: ${allPluginInstances.length}`);
215-
allPluginInstances.sort(({pi: a}, {pi: b}) => a.activationOrder - b.activationOrder);
216215

217-
allPluginInstances.forEach(
218-
({pi: pluginInstance, resource}, index) => {
219-
process.env.HEAVY_DEBUG && console.log(`🔌 Activating plugin ${index + 1}/${allPluginInstances.length}: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
220-
pluginInstance.modifyResourceConfig(this, resource);
221-
process.env.HEAVY_DEBUG && console.log(`🔌 Plugin ${pluginInstance.constructor.name} modifyResourceConfig completed`);
222-
223-
const plugin = this.activatedPlugins.find((p) => p.pluginInstanceId === pluginInstance.pluginInstanceId);
224-
if (plugin) {
225-
process.env.HEAVY_DEBUG && console.log(`Current plugin pluginInstance.pluginInstanceId ${pluginInstance.pluginInstanceId}`);
216+
let activationLoopCounter = 0;
217+
while (true) {
218+
activationLoopCounter++;
219+
if (activationLoopCounter > 1000) {
220+
throw new Error('Plugin activation loop exceeded 1000 iterations, possible infinite loop (some plugin tries to activate himself in a loop)');
221+
}
222+
const allPluginsAreActivated = allPluginInstances.length === this.activatePlugins.length;
223+
if (allPluginsAreActivated) {
224+
break;
225+
}
226+
227+
const unactivatedPlugins = allPluginInstances.filter(({pi: pluginInstance}) =>
228+
!this.activatedPlugins.find((p) => p.pluginInstanceId === pluginInstance.pluginInstanceId)
229+
);
230+
231+
process.env.HEAVY_DEBUG && console.log(`🔌 Unactivated plugins count: ${unactivatedPlugins.length}`);
232+
233+
unactivatedPlugins.sort(({pi: a}, {pi: b}) => a.activationOrder - b.activationOrder);
234+
235+
unactivatedPlugins.forEach(
236+
({pi: pluginInstance, resource}, index) => {
237+
process.env.HEAVY_DEBUG && console.log(`🔌 Activating plugin ${index + 1}/${allPluginInstances.length}: ${pluginInstance.constructor.name} for resource ${resource.resourceId}`);
238+
pluginInstance.modifyResourceConfig(this, resource, allPluginInstances);
239+
process.env.HEAVY_DEBUG && console.log(`🔌 Plugin ${pluginInstance.constructor.name} modifyResourceConfig completed`);
226240

227-
throw new Error(`Attempt to activate Plugin ${pluginInstance.constructor.name} second time for same resource, but plugin does not support it.
228-
To support multiple plugin instance pre one resource, plugin should return unique string values for each installation from instanceUniqueRepresentation`);
241+
const plugin = this.activatedPlugins.find((p) => p.pluginInstanceId === pluginInstance.pluginInstanceId);
242+
if (plugin) {
243+
process.env.HEAVY_DEBUG && console.log(`Current plugin pluginInstance.pluginInstanceId ${pluginInstance.pluginInstanceId}`);
244+
245+
throw new Error(`Attempt to activate Plugin ${pluginInstance.constructor.name} second time for same resource, but plugin does not support it.
246+
To support multiple plugin instance pre one resource, plugin should return unique string values for each installation from instanceUniqueRepresentation`);
247+
}
248+
this.activatedPlugins.push(pluginInstance);
249+
process.env.HEAVY_DEBUG && console.log(`🔌 Plugin ${pluginInstance.constructor.name} activated successfully`);
229250
}
230-
this.activatedPlugins.push(pluginInstance);
231-
process.env.HEAVY_DEBUG && console.log(`🔌 Plugin ${pluginInstance.constructor.name} activated successfully`);
232-
}
233-
);
251+
);
252+
}
234253
process.env.HEAVY_DEBUG && console.log('🔌 All plugins activation completed');
235254
}
236255

0 commit comments

Comments
 (0)