import clone from 'clone' ; import { ServerService } from '../Server' ; import { ModuleManager , ModuleManagerFactory } from '../ModuleManager' ; import { Config , ConfigType } from '../Config' ; import { FactoryInterface , ServiceManager } from '../ServiceManager' ; import { EventManager , EventManagerFactory , SharedEventManager } from '../EventManager' ; import { ApplicationEvents } from './ApplicationEvents' ; import { Instantiable } from '../Core' ; import { createDebugLogger } from '../../debug' ; import * as defaultConfig from '../../config' ; import { CliService } from '../Cli' ; import { ApplicationModes } from './ApplicationModes' ; const debug = createDebugLogger ( 'application' ) ; export class Application { private mode : ApplicationModes ; private readonly environment : string = process . env . NODE_ENV || 'development' ; private readonly config : Config ; private readonly serviceManager : ServiceManager ; private readonly applicationConfigs : ConfigType [ ] ; private moduleManager : ModuleManager ; private sharedEventManager : SharedEventManager ; public constructor ( ... appConfigs ) { this . applicationConfigs = appConfigs ; this . config = new Config ( defaultConfig , ... clone ( this . applicationConfigs ) ) ; this . serviceManager = new ServiceManager ( { aliases : { config : Config , sharedEventManager : SharedEventManager } , invokables : new Map < Instantiable < Object > , Instantiable < Object > > ( [ [ SharedEventManager , SharedEventManager ] , ] ) , factories : new Map < Function , FactoryInterface > ( [ [ ModuleManager , ModuleManagerFactory ] , [ EventManager , EventManagerFactory ] , ] ) , services : new Map < Function , Object > ( [ [ Config , this . config ] , [ Application , this ] , ] ) , shared : new Map < Function , boolean > ( [ [ EventManager , false ] , ] ) , } ) ; } public getMode ( ) { return this . mode ; } public getServiceManager ( ) { return this . serviceManager ; } private async bootstrap ( mode , loadOnly = false ) { const config = this . config ; this . moduleManager = this . serviceManager . get ( ModuleManager ) ; await this . moduleManager . loadModules ( config . of ( 'modules' ) ) ; this . config . merge ( ... this . applicationConfigs ) ; this . serviceManager . configure ( config . of ( 'services' ) ) ; this . sharedEventManager = this . serviceManager . get ( SharedEventManager ) ; if ( mode === ApplicationModes . Cli ) { await this . bootstrapCli ( ) ; } else { this . bootstrapServer ( ) ; } if ( loadOnly ) { return this ; } return await this . start ( ) ; } public async start ( ) { await this . moduleManager . bootstrap ( ) ; await this . sharedEventManager . trigger ( ApplicationEvents . Ready , this ) ; return this ; } private async bootstrapCli ( ) { const cliService = await this . serviceManager . get ( CliService ) ; this . sharedEventManager . attachOnce ( ApplicationEvents . Ready , ( ) => { cliService . execute ( process . argv . slice ( 2 ) ) ; } ) ; } private bootstrapServer ( ) { const serverService = this . serviceManager . get ( ServerService ) ; this . sharedEventManager . attachOnce ( ApplicationEvents . Ready , ( ) => { serverService . start ( ) ; } ) ; } public getEnvironment ( ) { return this . environment ; } public isProduction ( ) { return this . getEnvironment ( ) === 'production' ; } public async launch ( mode = ApplicationModes . Server , loadOnly = false ) { this . config . merge ( { application : { mode } } ) ; this . mode = mode ; debug ( `Launching in ${ mode } mode` ) ; await this . bootstrap ( mode , loadOnly ) ; debug ( 'Application ready.' ) ; return this ; } }