|
|
|
import {Service} from '../../../di/src/decorator/Service.ts'
|
|
|
|
import {Logging} from '../service/logging/Logging.ts'
|
|
|
|
import LifecycleUnit from './Unit.ts'
|
|
|
|
import {container, make} from '../../../di/src/global.ts'
|
|
|
|
import {DependencyKey} from '../../../di/src/type/DependencyKey.ts'
|
|
|
|
import RunLevelErrorHandler from '../error/RunLevelErrorHandler.ts'
|
|
|
|
import {Status} from '../const/status.ts'
|
|
|
|
import Instantiable from '../../../di/src/type/Instantiable.ts'
|
|
|
|
import {Collection} from '../collection/Collection.ts'
|
|
|
|
import {path} from '../external/std.ts'
|
|
|
|
import Scaffolding from '../unit/Scaffolding.ts'
|
|
|
|
import {Container} from '../../../di/src/Container.ts'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Central class for Daton applications.
|
|
|
|
*/
|
|
|
|
@Service()
|
|
|
|
export default class Application {
|
|
|
|
/**
|
|
|
|
* Collection of LifecycleUnits instantiated by this application.
|
|
|
|
* @type Collection<LifecycleUnit>
|
|
|
|
*/
|
|
|
|
protected instantiated_units: Collection<LifecycleUnit> = new Collection<LifecycleUnit>()
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
protected logger: Logging,
|
|
|
|
protected injector: Container,
|
|
|
|
protected rleh: RunLevelErrorHandler,
|
|
|
|
/**
|
|
|
|
* Array of unit classes to run for this application.
|
|
|
|
* @type Array<Instantiable<LifecycleUnit>>
|
|
|
|
*/
|
|
|
|
protected units: (Instantiable<LifecycleUnit>)[],
|
|
|
|
) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use the IoC container to instantiate the given dependency key.
|
|
|
|
* @param {DependencyKey} token
|
|
|
|
*/
|
|
|
|
make(token: DependencyKey) {
|
|
|
|
return make(token)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the IoC container.
|
|
|
|
* @return Container
|
|
|
|
*/
|
|
|
|
container() {
|
|
|
|
return container
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Launch the application.
|
|
|
|
* @return Promise<void>
|
|
|
|
*/
|
|
|
|
async up() {
|
|
|
|
this.logger.info('Starting Daton...', true)
|
|
|
|
for ( const unit_class of this.units ) {
|
|
|
|
const unit = this.make(unit_class)
|
|
|
|
this.instantiated_units.push(unit)
|
|
|
|
await this.start_unit(unit)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the application.
|
|
|
|
* @return Promise<void>
|
|
|
|
*/
|
|
|
|
async down() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run the application.
|
|
|
|
* @return Promise<void>
|
|
|
|
*/
|
|
|
|
async run() {
|
|
|
|
try {
|
|
|
|
await this.up()
|
|
|
|
await this.down()
|
|
|
|
} catch (e) {
|
|
|
|
await this.app_error(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pass an error to the top-level error handler.
|
|
|
|
* @param {Error} e
|
|
|
|
*/
|
|
|
|
async app_error(e: Error) {
|
|
|
|
this.rleh.handle(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Launch the given lifecycle unit.
|
|
|
|
* @param {LifecycleUnit} unit
|
|
|
|
*/
|
|
|
|
protected async start_unit(unit: LifecycleUnit) {
|
|
|
|
try {
|
|
|
|
unit.status = Status.Starting
|
|
|
|
this.logger.info(`Starting ${unit.constructor.name}...`)
|
|
|
|
await unit.up()
|
|
|
|
this.logger.verbose(`Successfully started ${unit.constructor.name}`)
|
|
|
|
unit.status = Status.Running
|
|
|
|
} catch (e) {
|
|
|
|
unit.status = Status.Error
|
|
|
|
this.logger.error(`Error encountered while starting ${unit.constructor.name}. Will attempt to proceed.`)
|
|
|
|
this.logger.debug(e.message)
|
|
|
|
this.logger.verbose(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the root directory of the application.
|
|
|
|
* @type string
|
|
|
|
*/
|
|
|
|
get root() {
|
|
|
|
return this.injector.make(Scaffolding).base_dir
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the root directory of application class definitions.
|
|
|
|
* @type string
|
|
|
|
*/
|
|
|
|
get app_root() {
|
|
|
|
return path.resolve(this.injector.make(Scaffolding).base_dir, 'app')
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve the given path within the application's root.
|
|
|
|
* @param {...string} parts
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
path(...parts: string[]) {
|
|
|
|
return path.resolve(this.root, ...parts)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve the given path within the application's class definition root.
|
|
|
|
* @param {...string} parts
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
app_path(...parts: string[]) {
|
|
|
|
return path.resolve(this.app_root, ...parts)
|
|
|
|
}
|
|
|
|
}
|