import type { ServerAdapter } from './adapter/ServerAdapter'; import type { ServerConfig } from './ServerConfig'; import { ActionBox } from './ActionBox'; import { SpecialPropertiesFactoryManager } from './SpecialPropertiesFactoryManager'; import { Meta } from './actions/Meta'; import { ServerController } from './ServerController'; export class Server { public readonly actions = new Map>(); public readonly specialFactories = new SpecialPropertiesFactoryManager(); protected readonly adapter: ServerAdapter; protected readonly controller: ServerController; constructor(public readonly config: ServerConfig) { const { adapter } = config; this.controller = new ServerController(this); if (adapter) { this.adapter = adapter; adapter.setServerController(this.controller); } else { throw new Error('Adapter is required.'); } } public getAdapter(): ServerAdapter { return this.adapter; } public getServerController(): ServerController { return this.controller; } public async addAction(name: string, action: T): Promise> { if (this.actions.has(name)) { throw new Error(`Action ${name} is already exists.`); } if (name !== '#meta') { await this.initMetaAction(); } const box = this.createActionBox(name, action); this.actions.set(name, box); await box.init(); return box; } public getActionBox(actionName: string): ActionBox { if (!this.actions.has(actionName)) { throw new Error(`Action ${actionName} is not found.`); } return this.actions.get(actionName)!; } public async close() { return this.adapter.close(); } protected createActionBox(name: string, action: T): ActionBox { const Ab = this.config.actionBoxConstructor || ActionBox; const ab = new Ab(name, action, this); this.prepareActionSettings(ab); ab.check(); return ab; } protected async initMetaAction(): Promise { if (!this.actions.has('#meta')) { const { config } = this; const MetaType = config.metaAction ? config.metaAction : Meta; const mab = await this.addAction('#meta', new MetaType()); this.config.onMetaActionReady?.(mab); } } protected prepareActionSettings(ab: ActionBox) { const { config } = ab; if (config.momentOfInit === 'connect') { config.maxInstances = 1; config.permanent = true; } if (config.placeOfInit === 'server' && config.momentOfInit === 'call') { throw new Error( `Bad configuration ${ab.name}: You cannot create an instance at the time of the call if "placeOfInit" is set to "server".`, ); } } }