Continue fleshing out HTTP request classes
This commit is contained in:
150
src/http/kernel/HTTPKernel.ts
Normal file
150
src/http/kernel/HTTPKernel.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import {Instantiable, Singleton, Inject} from "@extollo/di"
|
||||
import {Collection} from "@extollo/util"
|
||||
import {HTTPKernelModule} from "./HTTPKernelModule";
|
||||
import {Logging} from "../../service/Logging";
|
||||
import {AppClass} from "../../lifecycle/AppClass";
|
||||
import {Request} from "../lifecycle/Request";
|
||||
|
||||
/**
|
||||
* Interface for fluently registering kernel modules into the kernel.
|
||||
*/
|
||||
export interface ModuleRegistrationFluency {
|
||||
before: (other?: Instantiable<HTTPKernelModule>) => HTTPKernel,
|
||||
after: (other?: Instantiable<HTTPKernelModule>) => HTTPKernel,
|
||||
first: () => HTTPKernel,
|
||||
last: () => HTTPKernel,
|
||||
core: () => HTTPKernel,
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown when a kernel module is requested that does not exist w/in the kernel.
|
||||
* @extends Error
|
||||
*/
|
||||
export class KernelModuleNotFoundError extends Error {
|
||||
constructor(name: string) {
|
||||
super(`The kernel module ${name} is not registered with the kernel.`)
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton()
|
||||
export class HTTPKernel extends AppClass {
|
||||
@Inject()
|
||||
protected readonly logging!: Logging;
|
||||
|
||||
/**
|
||||
* Collection of preflight modules to apply.
|
||||
* @type Collection<HTTPKernelModule>
|
||||
*/
|
||||
protected preflight: Collection<HTTPKernelModule> = new Collection<HTTPKernelModule>()
|
||||
|
||||
/**
|
||||
* Module considered to be the main handler.
|
||||
* @type HTTPKernelModule
|
||||
*/
|
||||
protected inflight?: HTTPKernelModule
|
||||
|
||||
/**
|
||||
* Collection of postflight modules to apply.
|
||||
* @type Collection<HTTPKernelModule>
|
||||
*/
|
||||
protected postflight: Collection<HTTPKernelModule> = new Collection<HTTPKernelModule>()
|
||||
|
||||
/**
|
||||
* Handle the incoming request, applying the preflight modules, inflight module, then postflight modules.
|
||||
* @param {Request} request
|
||||
* @return Promise<Request>
|
||||
*/
|
||||
public async handle(request: Request): Promise<Request> {
|
||||
try {
|
||||
for (const module of this.preflight.toArray()) {
|
||||
this.logging.verbose(`Applying pre-flight HTTP kernel module: ${module.constructor.name}`)
|
||||
request = await module.apply(request)
|
||||
}
|
||||
|
||||
if (this.inflight) {
|
||||
this.logging.verbose(`Applying core HTTP kernel module: ${this.inflight.constructor.name}`)
|
||||
request = await this.inflight.apply(request)
|
||||
}
|
||||
|
||||
for (const module of this.postflight.toArray()) {
|
||||
this.logging.verbose(`Applying post-flight HTTP kernel module: ${module.constructor.name}`)
|
||||
request = await module.apply(request)
|
||||
}
|
||||
} catch (e: any) {
|
||||
this.logging.error(e)
|
||||
// FIXME handle error response
|
||||
// const error_response = error(e)
|
||||
// await error_response.write(request)
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fluent interface for registering the given kernel module.
|
||||
* @param {Instantiable<HTTPKernelModule>} module
|
||||
* @return ModuleRegistrationFluency
|
||||
*/
|
||||
public register(module: Instantiable<HTTPKernelModule>): ModuleRegistrationFluency {
|
||||
this.logging.verbose(`Registering HTTP kernel module: ${module.name}`)
|
||||
|
||||
return {
|
||||
before: (other?: Instantiable<HTTPKernelModule>): HTTPKernel => {
|
||||
if ( !other ) {
|
||||
this.preflight = this.preflight.push(this.app().make(module))
|
||||
return this
|
||||
}
|
||||
|
||||
let found_index = this.preflight.find((mod: HTTPKernelModule) => mod instanceof other)
|
||||
if ( typeof found_index !== 'undefined' ) {
|
||||
this.preflight = this.preflight.put(found_index, this.app().make(module))
|
||||
return this
|
||||
} else {
|
||||
found_index = this.postflight.find((mod: HTTPKernelModule) => mod instanceof other)
|
||||
}
|
||||
|
||||
if ( typeof found_index !== 'undefined' ) {
|
||||
this.postflight = this.postflight.put(found_index, this.app().make(module))
|
||||
} else {
|
||||
throw new KernelModuleNotFoundError(other.name)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
after: (other?: Instantiable<HTTPKernelModule>): HTTPKernel => {
|
||||
if ( !other ) {
|
||||
this.postflight = this.postflight.push(this.app().make(module))
|
||||
return this
|
||||
}
|
||||
|
||||
let found_index = this.preflight.find((mod: HTTPKernelModule) => mod instanceof other)
|
||||
if ( typeof found_index !== 'undefined' ) {
|
||||
this.preflight = this.preflight.put(found_index + 1, this.app().make(module))
|
||||
return this
|
||||
} else {
|
||||
found_index = this.postflight.find((mod: HTTPKernelModule) => mod instanceof other)
|
||||
}
|
||||
|
||||
if ( typeof found_index !== 'undefined' ) {
|
||||
this.postflight = this.postflight.put(found_index + 1, this.app().make(module))
|
||||
} else {
|
||||
throw new KernelModuleNotFoundError(other.name)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
first: (): HTTPKernel => {
|
||||
this.preflight = this.preflight.put(0, this.app().make(module))
|
||||
return this
|
||||
},
|
||||
last: (): HTTPKernel => {
|
||||
this.postflight = this.postflight.push(this.app().make(module))
|
||||
return this
|
||||
},
|
||||
core: (): HTTPKernel => {
|
||||
this.inflight = this.app().make(module)
|
||||
return this
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user