You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
3.7 KiB

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'
/**
* 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 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 path.resolve('.')
}
/**
* Get the root directory of application class definitions.
* @type string
*/
get app_root() {
return path.resolve('./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)
}
}