import { plugin, server } from "@ccms/api" import { inject, ContainerInstance, Container, provideSingletonNamed } from "@ccms/container" import { interfaces } from "../interfaces" import { getPluginStageMetadata, getPluginSources } from "../utils" const LOADER_TYPE_NAME = 'ioc' @provideSingletonNamed(plugin.PluginLoader, LOADER_TYPE_NAME) export class IocLoader implements plugin.PluginLoader { type: string = LOADER_TYPE_NAME @inject(ContainerInstance) private container: Container @inject(server.ServerChecker) private serverChecker: server.ServerChecker private pluginMetadataMap: Map constructor() { this.pluginMetadataMap = getPluginSources() } require(loadMetadata: plugin.PluginLoadMetadata) { let metadata = this.pluginMetadataMap.get(loadMetadata.file.toString()) if (metadata && metadata.type == this.type) { loadMetadata.metadata = metadata loadMetadata.loaded = true } return loadMetadata } build(metadata: plugin.PluginMetadata) { let pluginInstance: plugin.Plugin try { this.bindPlugin(metadata) pluginInstance = this.container.getNamed(plugin.Plugin, metadata.name) if (!(pluginInstance instanceof interfaces.Plugin)) { console.i18n('ms.plugin.manager.build.not.extends', { source: metadata.source }) return } } catch (ex) { console.i18n("ms.plugin.manager.initialize.error", { name: metadata.name, ex }) console.ex(ex) } return pluginInstance } load(plugin: plugin.Plugin): void { this.stage(plugin, 'load') } enable(plugin: plugin.Plugin): void { this.stage(plugin, 'enable') } disable(plugin: plugin.Plugin): void { this.stage(plugin, 'disable') } reload(plugin: plugin.Plugin): void { this.disable(plugin) //@ts-ignore require(plugin.description.source, { cache: false }) this.load(plugin) this.enable(plugin) } private bindPlugin(metadata: plugin.PluginMetadata) { try { let pluginInstance = this.container.getNamed(plugin.Plugin, metadata.name) if (pluginInstance.description.source + '' !== metadata.source + '') { console.i18n('ms.plugin.manager.build.duplicate', { exists: pluginInstance.description.source, source: metadata.source }) } this.container.rebind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name) } catch{ this.container.bind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name) } } private stage(pluginInstance: plugin.Plugin, stageName: string) { let stages = getPluginStageMetadata(pluginInstance, stageName) for (const stage of stages) { if (!this.serverChecker.check(stage.servers)) { continue } console.i18n("ms.plugin.manager.stage.exec", { plugin: pluginInstance.description.name, name: stage.executor, stage: stageName, servers: stage.servers }) try { pluginInstance[stage.executor].apply(pluginInstance) } catch (error) { console.i18n("ms.plugin.manager.stage.exec.error", { plugin: pluginInstance.description.name, executor: stage.executor, error }) console.ex(error) } } } }