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.
94 lines
3.9 KiB
94 lines
3.9 KiB
import {Inject, Singleton} from "@extollo/di"
|
|
import {HTTPStatus, withTimeout} from "@extollo/util"
|
|
import {Unit} from "../lifecycle/Unit";
|
|
import {createServer, IncomingMessage, Server, ServerResponse} from "http";
|
|
import {Logging} from "./Logging";
|
|
import {Request} from "../http/lifecycle/Request";
|
|
import {HTTPKernel} from "../http/kernel/HTTPKernel";
|
|
import {PoweredByHeaderInjectionHTTPModule} from "../http/kernel/module/PoweredByHeaderInjectionHTTPModule";
|
|
import {SetSessionCookieHTTPModule} from "../http/kernel/module/SetSessionCookieHTTPModule";
|
|
import {InjectSessionHTTPModule} from "../http/kernel/module/InjectSessionHTTPModule";
|
|
import {PersistSessionHTTPModule} from "../http/kernel/module/PersistSessionHTTPModule";
|
|
import {MountActivatedRouteHTTPModule} from "../http/kernel/module/MountActivatedRouteHTTPModule";
|
|
import {ExecuteResolvedRouteHandlerHTTPModule} from "../http/kernel/module/ExecuteResolvedRouteHandlerHTTPModule";
|
|
import {error} from "../http/response/ErrorResponseFactory";
|
|
import {ExecuteResolvedRoutePreflightHTTPModule} from "../http/kernel/module/ExecuteResolvedRoutePreflightHTTPModule";
|
|
import {ExecuteResolvedRoutePostflightHTTPModule} from "../http/kernel/module/ExecuteResolvedRoutePostflightHTTPModule";
|
|
|
|
@Singleton()
|
|
export class HTTPServer extends Unit {
|
|
@Inject()
|
|
protected readonly logging!: Logging
|
|
|
|
@Inject()
|
|
protected readonly kernel!: HTTPKernel
|
|
|
|
protected server?: Server
|
|
|
|
public async up() {
|
|
const port = 8000
|
|
|
|
// TODO register these by config
|
|
PoweredByHeaderInjectionHTTPModule.register(this.kernel)
|
|
SetSessionCookieHTTPModule.register(this.kernel)
|
|
InjectSessionHTTPModule.register(this.kernel)
|
|
PersistSessionHTTPModule.register(this.kernel)
|
|
MountActivatedRouteHTTPModule.register(this.kernel)
|
|
ExecuteResolvedRouteHandlerHTTPModule.register(this.kernel)
|
|
ExecuteResolvedRoutePreflightHTTPModule.register(this.kernel)
|
|
ExecuteResolvedRoutePostflightHTTPModule.register(this.kernel)
|
|
|
|
await new Promise<void>((res, rej) => {
|
|
this.server = createServer(this.handler)
|
|
|
|
this.server.listen(port, () => {
|
|
this.logging.success(`Server listening on port ${port}. Press ^C to stop.`)
|
|
})
|
|
|
|
process.on('SIGINT', res)
|
|
})
|
|
}
|
|
|
|
public async down() {
|
|
if ( this.server ) {
|
|
this.server.close(err => {
|
|
if ( err ) {
|
|
this.logging.error(`Error encountered while closing HTTP server: ${err.message}`)
|
|
this.logging.debug(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
public get handler() {
|
|
return async (request: IncomingMessage, response: ServerResponse) => {
|
|
const extolloReq = new Request(request, response)
|
|
|
|
// FIXME make timeout configurable
|
|
withTimeout(10000, extolloReq.response.sent$.toPromise())
|
|
.onTime(req => {
|
|
this.logging.verbose(`Request lifecycle finished on time. (Path: ${extolloReq.path})`)
|
|
})
|
|
.late(req => {
|
|
this.logging.warn(`Request lifecycle finished late, so an error response was returned! (Path: ${extolloReq.path})`)
|
|
})
|
|
.timeout(() => {
|
|
this.logging.error(`Request lifecycle has timed out. Will send error response instead. (Path: ${extolloReq.path})`)
|
|
extolloReq.response.setStatus(HTTPStatus.REQUEST_TIMEOUT)
|
|
extolloReq.response.body = 'Sorry, your request timed out.'
|
|
extolloReq.response.send()
|
|
})
|
|
.run()
|
|
.catch(e => this.logging.error(e))
|
|
|
|
try {
|
|
await this.kernel.handle(extolloReq)
|
|
} catch (e) {
|
|
await error(e).write(extolloReq)
|
|
}
|
|
|
|
await extolloReq.response.send()
|
|
}
|
|
}
|
|
}
|