TypeDoc all the thngs
This commit is contained in:
@@ -22,21 +22,28 @@ export function isBindable(what: any): what is Bindable {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base for classes that gives access to the global application and container.
|
||||
*/
|
||||
export class AppClass {
|
||||
/** The global application instance. */
|
||||
private readonly appClassApplication!: Application;
|
||||
|
||||
constructor() {
|
||||
this.appClassApplication = Application.getApplication();
|
||||
}
|
||||
|
||||
/** Get the global Application. */
|
||||
protected app(): Application {
|
||||
return this.appClassApplication;
|
||||
}
|
||||
|
||||
/** Get the global Container. */
|
||||
protected container(): Container {
|
||||
return this.appClassApplication;
|
||||
}
|
||||
|
||||
/** Call the `make()` method on the global container. */
|
||||
protected make<T>(target: DependencyKey, ...parameters: any[]): T {
|
||||
return this.container().make<T>(target, ...parameters)
|
||||
}
|
||||
|
||||
@@ -16,10 +16,21 @@ import {Unit, UnitStatus} from "./Unit";
|
||||
import * as dotenv from 'dotenv';
|
||||
import {CacheFactory} from "../support/cache/CacheFactory";
|
||||
|
||||
/**
|
||||
* Helper function that resolves and infers environment variable values.
|
||||
*
|
||||
* If none is found, returns `defaultValue`.
|
||||
*
|
||||
* @param key
|
||||
* @param defaultValue
|
||||
*/
|
||||
export function env(key: string, defaultValue?: any): any {
|
||||
return Application.getApplication().env(key, defaultValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* The main application container.
|
||||
*/
|
||||
export class Application extends Container {
|
||||
public static getContainer(): Container {
|
||||
const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector')
|
||||
@@ -32,6 +43,9 @@ export class Application extends Container {
|
||||
return existing as Container
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global application instance.
|
||||
*/
|
||||
public static getApplication(): Application {
|
||||
const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector')
|
||||
if ( existing instanceof Application ) {
|
||||
@@ -49,11 +63,34 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The fully-qualified path to the base directory of the app.
|
||||
* @protected
|
||||
*/
|
||||
protected baseDir!: string
|
||||
|
||||
/**
|
||||
* Resolved universal path to the base directory of the app.
|
||||
* @protected
|
||||
*/
|
||||
protected basePath!: UniversalPath
|
||||
|
||||
/**
|
||||
* The Unit classes registered with the app.
|
||||
* @protected
|
||||
*/
|
||||
protected applicationUnits: (typeof Unit)[] = []
|
||||
|
||||
/**
|
||||
* Instances of the units registered with this app.
|
||||
* @protected
|
||||
*/
|
||||
protected instantiatedUnits: Unit[] = []
|
||||
|
||||
/**
|
||||
* If true, the "Starting Extollo..." messages will always
|
||||
* be logged.
|
||||
*/
|
||||
public forceStartupMessage: boolean = true
|
||||
|
||||
constructor() {
|
||||
@@ -72,36 +109,67 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given unit class is registered with the application.
|
||||
* @param unitClass
|
||||
*/
|
||||
public hasUnit(unitClass: typeof Unit) {
|
||||
return this.applicationUnits.includes(unitClass)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a UniversalPath to the root of the application.
|
||||
*/
|
||||
get root() {
|
||||
return this.basePath.concat()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UniversalPath to the `app/` directory in the application.
|
||||
*/
|
||||
get appRoot() {
|
||||
return this.basePath.concat('app')
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path relative to the root of the application.
|
||||
* @param parts
|
||||
*/
|
||||
path(...parts: PathLike[]) {
|
||||
return this.basePath.concat(...parts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path relative to the `app/` directory in the application.
|
||||
* @param parts
|
||||
*/
|
||||
appPath(...parts: PathLike[]) {
|
||||
return this.basePath.concat('app', ...parts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the RunLevelErrorHandler.
|
||||
*/
|
||||
get errorHandler() {
|
||||
const rleh: RunLevelErrorHandler = this.make<RunLevelErrorHandler>(RunLevelErrorHandler)
|
||||
return rleh.handle
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a base Error instance into an ErrorWithContext.
|
||||
* @param e
|
||||
* @param context
|
||||
*/
|
||||
errorWrapContext(e: Error, context: {[key: string]: any}): ErrorWithContext {
|
||||
const rleh: RunLevelErrorHandler = this.make<RunLevelErrorHandler>(RunLevelErrorHandler)
|
||||
return rleh.wrapContext(e, context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the bare essentials to get the application up and running.
|
||||
* @param absolutePathToApplicationRoot
|
||||
* @param applicationUnits
|
||||
*/
|
||||
scaffold(absolutePathToApplicationRoot: string, applicationUnits: (typeof Unit)[]) {
|
||||
this.baseDir = absolutePathToApplicationRoot
|
||||
this.basePath = universalPath(absolutePathToApplicationRoot)
|
||||
@@ -115,6 +183,10 @@ export class Application extends Container {
|
||||
this.make<Logging>(Logging).debug(`Application root: ${this.baseDir}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the logger and load the logging level from the environment.
|
||||
* @protected
|
||||
*/
|
||||
protected setupLogging() {
|
||||
const standard: StandardLogger = this.make<StandardLogger>(StandardLogger)
|
||||
const logging: Logging = this.make<Logging>(Logging)
|
||||
@@ -134,16 +206,29 @@ export class Application extends Container {
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the environment variable library and read from the `.env` file.
|
||||
* @protected
|
||||
*/
|
||||
protected bootstrapEnvironment() {
|
||||
dotenv.config({
|
||||
path: this.basePath.concat('.env').toLocal
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the loaded environment variables.
|
||||
* If no value could be found, the default value will be returned.
|
||||
* @param key
|
||||
* @param defaultValue
|
||||
*/
|
||||
public env(key: string, defaultValue?: any): any {
|
||||
return infer(process.env[key] ?? '') ?? defaultValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application by starting all units in order, then stopping them in reverse order.
|
||||
*/
|
||||
async run() {
|
||||
try {
|
||||
await this.up()
|
||||
@@ -153,6 +238,9 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all units in the application, one at a time, in order.
|
||||
*/
|
||||
async up() {
|
||||
const logging: Logging = this.make<Logging>(Logging)
|
||||
|
||||
@@ -164,6 +252,9 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all units in the application, one at a time, in reverse order.
|
||||
*/
|
||||
async down() {
|
||||
const logging: Logging = this.make<Logging>(Logging)
|
||||
|
||||
@@ -174,6 +265,10 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a single unit, setting its status.
|
||||
* @param unit
|
||||
*/
|
||||
public async startUnit(unit: Unit) {
|
||||
const logging: Logging = this.make<Logging>(Logging)
|
||||
|
||||
@@ -190,6 +285,10 @@ export class Application extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a single unit, setting its status.
|
||||
* @param unit
|
||||
*/
|
||||
public async stopUnit(unit: Unit) {
|
||||
const logging: Logging = this.make<Logging>(Logging)
|
||||
|
||||
|
||||
@@ -3,6 +3,11 @@ import {Logging} from "../service/Logging";
|
||||
import {Inject} from "@extollo/di";
|
||||
import {ErrorWithContext} from "@extollo/util";
|
||||
|
||||
/**
|
||||
* Class with logic for handling errors that are thrown at the run-level of the application.
|
||||
*
|
||||
* Colloquially, these are errors thrown ourside the request-lifecycle that are not caught by a unit.
|
||||
*/
|
||||
export class RunLevelErrorHandler {
|
||||
@Inject()
|
||||
protected logging!: Logging
|
||||
@@ -18,6 +23,11 @@ export class RunLevelErrorHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the given base Error instance into an ErrorWithContext.
|
||||
* @param e
|
||||
* @param context
|
||||
*/
|
||||
wrapContext(e: Error, context: {[key: string]: any}): ErrorWithContext {
|
||||
if ( e instanceof ErrorWithContext ) {
|
||||
e.context = {...e.context, ...context}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import {AppClass} from './AppClass';
|
||||
|
||||
/**
|
||||
* The various statuses of a Unit.
|
||||
*/
|
||||
export enum UnitStatus {
|
||||
Starting,
|
||||
Started,
|
||||
@@ -8,8 +11,26 @@ export enum UnitStatus {
|
||||
Error,
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for a service that can be registered with the application
|
||||
* that is started and stopped during the application lifecycle.
|
||||
*/
|
||||
export abstract class Unit extends AppClass {
|
||||
/** The current status of the unit. */
|
||||
public status: UnitStatus = UnitStatus.Stopped
|
||||
|
||||
/**
|
||||
* This method is called to start the unit when the application is booting.
|
||||
* Here, you should do any setup required to get the package up and running.
|
||||
*/
|
||||
public up(): Promise<void> | void {}
|
||||
|
||||
/**
|
||||
* This method is called to stop the unit when the application is shutting down.
|
||||
* Here, you should do any teardown required to stop the package cleanly.
|
||||
*
|
||||
* IN PARTICULAR take care to free blocking resources that could prevent the
|
||||
* process from exiting without a kill.
|
||||
*/
|
||||
public down(): Promise<void> | void {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user