@lakutata/core
Version:
Lakutata Framework Core
529 lines (494 loc) • 17.5 kB
text/typescript
import {BaseObject} from '../BaseObject'
import {Container} from '../Container'
import {Component} from './Component'
import {IComponentsConfig} from '../../interfaces/IComponentsConfig'
import {IModulesConfig} from '../../interfaces/IModulesConfig'
import {TPluginsConfig} from '../../types/TPluginsConfig'
import {Plugin} from '../Plugin'
import EventEmitter from 'events'
import {IConstructor} from '../../interfaces/IConstructor'
import {TWorkflowsConfig} from '../../types/TWorkflowsConfig'
import {Workflow} from './Workflow'
import {Configurable} from '../../decorators/DependencyInjection'
import {ThreadManager} from '../thread/ThreadManager'
import {Thread} from '../thread/Thread'
import {IThreadConstructor} from '../../interfaces/IThreadConstructor'
import {ProcessManager} from '../process/ProcessManager'
import {Process} from '../process/Process'
import {IProcessConstructor} from '../../interfaces/IProcessConstructor'
import {TThreadsConfig} from '../../types/TThreadsConfig'
import {TProcessesConfig} from '../../types/TProcessesConfig'
import {ModuleNotFoundException} from '../../exceptions/ModuleNotFoundException'
import {ComponentNotFoundException} from '../../exceptions/ComponentNotFoundException'
export abstract class Module extends BaseObject {
/**
* 模块事件
* @type {EventEmitter}
* @private
*/
private readonly eventEmitter: EventEmitter = new EventEmitter()
/**
* 模块ID
* @type {string | IConstructor<Module>}
*/
public readonly id: string | IConstructor<Module>
/**
* 模块IoC容器
* @type {Container}
* @protected
*/
protected readonly container: Container = new Container()
/**
* 线程管理器
* @type {ThreadManager}
* @protected
*/
protected readonly threadManager: ThreadManager = new ThreadManager()
/**
* 进程管理器
* @type {ProcessManager}
* @protected
*/
protected readonly processManager: ProcessManager = new ProcessManager()
/**
* 组件加载完成回调函数
* @returns {any}
*/
protected readonly onComponentsLoaded: (module: ThisType<this>) => void | Promise<void> = () => void (0)
/**
* 模块加载完成回调函数
* @param {Module} module
* @returns {any}
*/
protected readonly onModulesLoaded: (module: ThisType<this>) => void | Promise<void> = () => void (0)
/**
* 模块初始化方法
* @returns {Promise<void> | void}
* @protected
*/
protected abstract initialize(): Promise<void> | void
constructor() {
super()
this.on('ready', async (module: this) => {
if (this.workflows) {
for (const workflow of this.workflows) {
const WorkflowConstructor: IConstructor<Workflow> = workflow as IConstructor<Workflow>
let workflowFunction: (((instance: this) => void) | ((instance: this) => Promise<void>)) | null = null
try {
const workflowInstance = new WorkflowConstructor(module)
if (workflowInstance.run) {
await workflowInstance.run()
}
} catch (e) {
workflowFunction = workflow as (((instance: this) => void) | ((instance: this) => Promise<void>))
}
if (workflowFunction) await workflowFunction(module)
}
}
})
this.container
.on('moduleLoaded', (moduleId, moduleConstructor, loadTime, subModuleId?) => {
const moduleStringId: string = typeof this.id === 'function' ? this.id.name : this.id
this.eventEmitter.emit('loaded', subModuleId ? `${moduleStringId}/${subModuleId}` : moduleStringId, moduleId, moduleConstructor, loadTime, 'module')
})
.on('componentLoaded', (componentId, componentConstructor, loadTime, subModuleId?) => {
const moduleStringId: string = typeof this.id === 'function' ? this.id.name : this.id
this.eventEmitter.emit('loaded', subModuleId ? `${moduleStringId}/${subModuleId}` : moduleStringId, componentId, componentConstructor, loadTime, 'component')
})
}
/**
* 工作流方法执行列表
* @type {TWorkflowsConfig[]}
* @protected
*/
protected readonly workflows: TWorkflowsConfig = []
/**
* 插件加载列表
* @type {TPluginsConfig}
*/
protected readonly plugins: TPluginsConfig = []
/**
* 组件加载列表
* @type {IComponentsConfig}
* @protected
*/
protected readonly components: IComponentsConfig = {}
/**
* 模块加载列表
* @type {IModulesConfig}
* @protected
*/
protected readonly modules: IModulesConfig = {}
/**
* 线程加载列表
* @type {TThreadsConfig}
* @protected
*/
protected readonly threads: TThreadsConfig = []
/**
* 进程加载列表
* @type {TProcessesConfig}
* @protected
*/
protected readonly processes: TProcessesConfig = []
/**
* 加载插件列表
* @protected
*/
protected bindPlugins(): void {
//todo 可能需要合并一下多个相同插件的配置
if (!this.plugins) return
const reversedPlugins = this.plugins.reverse()
const registeredPluginSet = new Set()
for (const pluginConstructorOrConfig of reversedPlugins) {
let pluginConstructor
let pluginConfig: object & { scope?: 'Transient' | 'Singleton' } = {}
if (typeof pluginConstructorOrConfig === 'object') {
pluginConstructor = pluginConstructorOrConfig.class
for (const configKey of Object.keys(pluginConstructorOrConfig)) {
const configValue = pluginConstructorOrConfig[configKey]
if (configValue !== pluginConstructor) {
pluginConfig[configKey] = configValue
}
}
} else {
pluginConstructor = pluginConstructorOrConfig
pluginConfig = {}
}
if (registeredPluginSet.has(pluginConstructor)) continue
this.container.bindPlugin(pluginConstructor, pluginConstructor.name, pluginConfig)
if (!this.hasProperty(pluginConstructor.name)) {
this.defineProperty(pluginConstructor.name, {
get() {
return this.container.getPlugin(pluginConstructor.name)
}
})
}
registeredPluginSet.add(pluginConstructor)
}
}
/**
* 加载组件列表
* @protected
*/
protected bindComponents(): void {
if (!this.components) return
for (const key of Object.keys(this.components)) {
const componentIdentifier: string = key
const componentConstructorOrConfig = this.components[key]
let componentConstructor
let componentConfig: object = {}
if (typeof componentConstructorOrConfig === 'object') {
componentConstructor = componentConstructorOrConfig.class
for (const configKey of Object.keys(componentConstructorOrConfig)) {
const configValue = componentConstructorOrConfig[configKey]
if (configValue !== componentConstructor) {
componentConfig[configKey] = configValue
}
}
} else {
componentConstructor = componentConstructorOrConfig
componentConfig = {}
}
this.container.bindComponent(componentConstructor, componentIdentifier, componentConfig)
}
}
/**
* 加载模块列表
* @protected
*/
protected bindModules(): void {
if (!this.modules) {
this.emit('modulesReady', this)
return
}
const moduleSize: number = Object.keys(this.modules).length
let loadedModuleCount: number = 0
if (moduleSize === loadedModuleCount) {
this.emit('modulesReady', this)
} else {
for (const key of Object.keys(this.modules)) {
const moduleIdentifier: string = key
const moduleConfig = this.modules[key]
const moduleConstructor = moduleConfig.class
let moduleConfigs: object = {}
for (const configKey of Object.keys(moduleConfig)) {
const configValue = moduleConfig[configKey]
if (moduleConstructor !== configValue) {
moduleConfigs[configKey] = configValue
}
}
this.container.bindModule(moduleConstructor, moduleConfigs, moduleIdentifier, () => {
loadedModuleCount += 1
if (loadedModuleCount === moduleSize) {
this.emit('modulesReady', this)
}
})
}
}
}
/**
* 加载线程列表
* @returns {Promise<void>}
* @protected
*/
protected async bindThreads(): Promise<void> {
if (this.threads) {
const threadBindPromises: Promise<boolean>[] = []
this.threads.forEach(threadConstructor => {
threadBindPromises.push(new Promise((resolve, reject) => {
this.threadManager.createThread(threadConstructor).then(resolve).catch(reject)
}))
})
await Promise.all(threadBindPromises)
}
}
/**
* 加载进程列表
* @returns {Promise<void>}
* @protected
*/
protected async bindProcesses(): Promise<void> {
if (this.processes) {
const processBindPromises: Promise<boolean>[] = []
this.processes.forEach(processConstructor => {
processBindPromises.push(new Promise((resolve, reject) => {
this.processManager.createProcess(processConstructor).then(resolve).catch(reject)
}))
})
await Promise.all(processBindPromises)
}
}
/**
* 插件管理
* @returns {{bind: <TPlugin=Plugin extends Plugin>(pluginConstructor: IConstructor<TPlugin>, identifier: string, config: object) => void, get: <T=Plugin extends Plugin>(name: string) => T, has: (name: string) => boolean}}
* @constructor
*/
public get Plugins() {
const self = this
return {
bind: function <TPlugin extends Plugin = Plugin>(pluginConstructor: IConstructor<TPlugin>, identifier: string, config: object): void {
self.container.bindPlugin(pluginConstructor, identifier, config)
},
get: function <T extends Plugin = Plugin>(name: string): T {
return self.container.getPlugin(name)
},
has: function (name: string): boolean {
try {
self.container.getPlugin(name)
return true
} catch (e) {
return false
}
}
}
}
/**
* 对象管理
* @returns {{bind: <TObject=BaseObject extends BaseObject>(objectConstructor: IConstructor<TObject>, config?: {[p: string]: any}) => void, unbind: <TObject=BaseObject extends BaseObject>(objectConstructor: IConstructor<TObject>) => void, get: <TObject=BaseObject extends BaseObject>(objectConstructor: IConstructor<TObject>) => TObject, has: <TObject=BaseObject extends BaseObject>(objectConstructor: IConstructor<TObject>) => boolean}}
* @constructor
*/
public get Objects() {
const self = this
return {
bind: function <TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>, config?: { [key: string]: any }): void {
self.container.bindObject(objectConstructor, config)
},
get: function <TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): TObject {
return self.container.getObject(objectConstructor)
},
has: function <TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): boolean {
return self.container.hasObject(objectConstructor)
},
unbind: function <TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): void {
self.container.unbindObject(objectConstructor)
}
}
}
/**
* 组件管理
* @returns {any}
* @constructor
*/
public get Components() {
const self = this
const baseComponents = {
get: function <T extends Component = Component>(name: string): T {
if (baseComponents.has(name)) {
return self.container.getComponent<T>(name)
} else {
throw self.generateException(ComponentNotFoundException, name)
}
},
has: function (name: string): boolean {
try {
self.container.getComponent(name)
return true
} catch (e) {
return false
}
}
}
return new Proxy(baseComponents, {
get(target: { get: <T extends Component = Component>(name: string) => T; has: (name: string) => boolean; [key: string]: any }, p: string, receiver: any): any {
if (target[p]) {
return target[p]
} else {
if (target.has(p)) {
return target.get(p)
} else {
return undefined
}
}
}
})
}
/**
* 模块管理
* @returns {any}
* @constructor
*/
public get Modules() {
const self = this
const baseModules = {
get: function <T extends Module = Module>(name: string): T {
if (baseModules.has(name)) {
return self.container.getModule<T>(name)
} else {
throw self.generateException(ModuleNotFoundException, name)
}
},
has: function (name: string): boolean {
try {
self.container.getModule(name)
return true
} catch (e) {
return false
}
}
}
return new Proxy(baseModules, {
get(target: { get: <T extends Module = Module>(name: string) => T; has: (name: string) => boolean }, p: string): any {
if (target[p]) {
return target[p]
} else {
if (target.has(p)) {
return target.get(p)
} else {
return undefined
}
}
}
})
}
/**
* 线程管理
* @returns {{bind: <T=Thread extends Thread>(threadConstructor: IThreadConstructor<T>) => Promise<boolean>, get: <T=Thread extends Thread>(threadConstructor: IThreadConstructor<T>) => T, destroy: <T=Thread extends Thread>(threadConstructor: IThreadConstructor<T>) => Promise<void>, has: <T=Thread extends Thread>(threadConstructor: IThreadConstructor<T>) => boolean}}
* @constructor
*/
public get Threads() {
const self = this
return {
bind: async function <T extends Thread = Thread>(threadConstructor: IThreadConstructor<T>): Promise<boolean> {
return await self.threadManager.createThread(threadConstructor)
},
get: function <T extends Thread = Thread>(threadConstructor: IThreadConstructor<T>): T {
return self.threadManager.get(threadConstructor) as T
},
has: function <T extends Thread = Thread>(threadConstructor: IThreadConstructor<T>): boolean {
return self.threadManager.has(threadConstructor)
},
destroy: async function <T extends Thread = Thread>(threadConstructor: IThreadConstructor<T>): Promise<void> {
return await self.threadManager.destroy(threadConstructor)
}
}
}
/**
* 进程管理
* @returns {{bind: <T=Process extends Process>(processConstructor: IProcessConstructor<T>) => Promise<boolean>, get: <T=Process extends Process>(processConstructor: IProcessConstructor<T>) => T, destroy: <T=Process extends Process>(processConstructor: IProcessConstructor<T>) => Promise<void>, has: <T=Process extends Process>(processConstructor: IProcessConstructor<T>) => boolean}}
* @constructor
*/
public get Processes() {
const self = this
return {
bind: async function <T extends Process = Process>(processConstructor: IProcessConstructor<T>): Promise<boolean> {
return await self.processManager.createProcess(processConstructor)
},
get: function <T extends Process = Process>(processConstructor: IProcessConstructor<T>): T {
return self.processManager.get(processConstructor) as T
},
has: function <T extends Process = Process>(processConstructor: IProcessConstructor<T>): boolean {
return self.processManager.has(processConstructor)
},
destroy: async function <T extends Process = Process>(processConstructor: IProcessConstructor<T>): Promise<void> {
return await self.processManager.destroy(processConstructor)
}
}
}
public on(event: 'ready', listener: (instance: this) => void): this
public on(event: 'loaded', listener: (id: string, identifier: string, constructor: IConstructor<Module> | IConstructor<Component>, loadTime: number, type: 'module' | 'component') => void): this
public on(event: string | symbol, listener: (...args: any[]) => void): this
public on(a: string | symbol, b: (...args: any[]) => void): this {
this.eventEmitter.on(a, b)
return this
}
public once(event: 'ready', listener: (instance: this) => void): this
public once(event: 'loaded', listener: (id: string, identifier: string, constructor: IConstructor<Module> | IConstructor<Component>, loadTime: number, type: 'module' | 'component') => void): this
public once(event: string | symbol, listener: (...args: any[]) => void): this
public once(a: string | symbol, b: (...args: any[]) => void): this {
this.eventEmitter.once(a, b)
return this
}
public off(event: string): void
public off(event: string | symbol, listener: (...args: any[]) => void): this
public off(a: string | symbol, b?: (...args: any[]) => void): this {
if (!b) {
this.eventEmitter.removeAllListeners(a)
} else {
this.eventEmitter.removeListener(a, b)
}
return this
}
public emit(event: string | symbol, ...args: any[]): boolean {
return this.eventEmitter.emit.apply(this.eventEmitter, [event].concat(args) as any)
}
/**
* 绑定对象
* @param {IConstructor<TObject>} objectConstructor
* @param {{[p: string]: any}} config
*/
public bind<TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>, config?: { [key: string]: any }): void {
return this.Objects.bind(objectConstructor, config)
}
/**
* 获取对象
* @param {IConstructor<TObject>} objectConstructor
* @returns {TObject}
*/
public get<TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): TObject {
return this.Objects.get(objectConstructor)
}
/**
* 解除对象绑定
* @param {IConstructor<TObject>} objectConstructor
*/
public unbind<TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): void {
return this.Objects.unbind(objectConstructor)
}
/**
* 判断对象是否已绑定
* @param {IConstructor<TObject>} objectConstructor
* @returns {boolean}
*/
public has<TObject extends BaseObject = BaseObject>(objectConstructor: IConstructor<TObject>): boolean {
return this.Objects.has(objectConstructor)
}
}