Add foreground service, some cleanup, and start websocket server
This commit is contained in:
@@ -8,7 +8,6 @@ import {Inject} from '../di'
|
||||
import * as nodePath from 'path'
|
||||
import {Unit} from '../lifecycle/Unit'
|
||||
import {isCanonicalReceiver} from '../support/CanonicalReceiver'
|
||||
import {env} from '../lifecycle/Application'
|
||||
|
||||
/**
|
||||
* Interface describing a definition of a single canonical item loaded from the app.
|
||||
|
||||
24
src/service/Foreground.ts
Normal file
24
src/service/Foreground.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {Unit} from '../lifecycle/Unit'
|
||||
import {Inject} from '../di'
|
||||
import {Logging} from './Logging'
|
||||
import * as process from 'process'
|
||||
|
||||
export class Foreground extends Unit {
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
protected resolver?: () => unknown
|
||||
|
||||
public up(): Promise<void> {
|
||||
return new Promise<void>(res => {
|
||||
this.resolver = res
|
||||
this.logging.success(`Application started! Press ^C or send SIGINT to stop.`)
|
||||
process.stdin.resume()
|
||||
process.on('SIGINT', res)
|
||||
})
|
||||
}
|
||||
|
||||
public down(): void {
|
||||
this.resolver?.()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Inject, Singleton} from '../di'
|
||||
import {ErrorWithContext, HTTPStatus, withTimeout} from '../util'
|
||||
import {ErrorWithContext} from '../util'
|
||||
import {Unit} from '../lifecycle/Unit'
|
||||
import {createServer, IncomingMessage, RequestListener, Server, ServerResponse} from 'http'
|
||||
import {Logging} from './Logging'
|
||||
@@ -67,10 +67,9 @@ export class HTTPServer extends Unit {
|
||||
this.server = createServer(this.handler)
|
||||
|
||||
this.server.listen(port, () => {
|
||||
this.logging.success(`Server listening on port ${port}. Press ^C to stop.`)
|
||||
this.logging.success(`Server listening on port ${port}.`)
|
||||
res()
|
||||
})
|
||||
|
||||
process.on('SIGINT', res)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -85,37 +84,19 @@ export class HTTPServer extends Unit {
|
||||
}
|
||||
}
|
||||
|
||||
public get handler(): RequestListener {
|
||||
// const timeout = this.config.get('server.timeout', 10000)
|
||||
// const timeout = 0 // temporarily disable this because it is causing problems
|
||||
public getServer(): Server {
|
||||
if ( !this.server ) {
|
||||
throw new ErrorWithContext('Unable to access server: it has not yet been created')
|
||||
}
|
||||
|
||||
return this.server
|
||||
}
|
||||
|
||||
public get handler(): RequestListener {
|
||||
return async (request: IncomingMessage, response: ServerResponse) => {
|
||||
const extolloReq = new Request(request, response)
|
||||
|
||||
await this.requestLocalStorage.run(extolloReq, async () => {
|
||||
/* withTimeout(timeout, extolloReq.response.sent$.toPromise())
|
||||
.onTime(() => {
|
||||
this.logging.verbose(`Request lifecycle finished on time. (Path: ${extolloReq.path})`)
|
||||
})
|
||||
.late(() => {
|
||||
if ( !extolloReq.bypassTimeout ) {
|
||||
this.logging.warn(`Request lifecycle finished late, so an error response was returned! (Path: ${extolloReq.path})`)
|
||||
}
|
||||
})
|
||||
.timeout(() => {
|
||||
if ( extolloReq.bypassTimeout ) {
|
||||
this.logging.info(`Request lifecycle has timed out, but bypassRequest was set. (Path: ${extolloReq.path})`)
|
||||
return
|
||||
}
|
||||
|
||||
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))*/
|
||||
|
||||
this.logging.info(`${extolloReq.method} ${extolloReq.path}`)
|
||||
|
||||
try {
|
||||
|
||||
@@ -12,7 +12,6 @@ import {PackageDiscovered} from '../support/PackageDiscovered'
|
||||
import {staticServer} from '../http/servers/static'
|
||||
import {Bus} from '../support/bus'
|
||||
import {RequestLocalStorage} from '../http/RequestLocalStorage'
|
||||
import {env} from '../lifecycle/Application'
|
||||
|
||||
/**
|
||||
* Application unit that loads the various route files from `app/http/routes` and pre-compiles the route handlers.
|
||||
@@ -106,7 +105,7 @@ export class Routing extends Unit {
|
||||
* @param method
|
||||
* @param path
|
||||
*/
|
||||
public match(method: HTTPMethod, path: string): Route<unknown, unknown[]> | undefined {
|
||||
public match(method: 'ws' | HTTPMethod, path: string): Route<unknown, unknown[]> | undefined {
|
||||
return this.compiledRoutes.firstWhere(route => {
|
||||
return route.match(method, path)
|
||||
})
|
||||
|
||||
50
src/service/WebsocketServer.ts
Normal file
50
src/service/WebsocketServer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import {Unit, UnitStatus} from '../lifecycle/Unit'
|
||||
import {Inject, Singleton} from '../di'
|
||||
import * as WebSocket from 'ws'
|
||||
import {HTTPServer} from './HTTPServer'
|
||||
import {Logging} from './Logging'
|
||||
import {ErrorWithContext} from '../util'
|
||||
import {Request} from '../http/lifecycle/Request'
|
||||
|
||||
@Singleton()
|
||||
export class WebsocketServer extends Unit {
|
||||
@Inject()
|
||||
protected readonly http!: HTTPServer
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
protected server?: WebSocket.Server
|
||||
|
||||
public async up(): Promise<void> {
|
||||
// Make sure the HTTP server is started. Otherwise, this is going to fail anyway
|
||||
if ( this.http.status !== UnitStatus.Started ) {
|
||||
throw new ErrorWithContext('Cannot start WebsocketServer without HTTPServer.', {
|
||||
suggestion: 'Make sure the HTTPServer is registered in your Units.extollo.ts file, and it is listed before the WebsocketServer.',
|
||||
})
|
||||
}
|
||||
|
||||
// Start the websocket server
|
||||
this.logging.info('Starting WebSocket server...')
|
||||
this.server = new WebSocket.Server<WebSocket.WebSocket>({
|
||||
server: this.http.getServer(),
|
||||
})
|
||||
|
||||
// Register the websocket handler
|
||||
this.server.on('connection', (ws, request) => {
|
||||
this.logging.info('Got WebSocket connection! ' + request.method)
|
||||
const extolloReq = new Request(request)
|
||||
this.logging.debug(ws)
|
||||
this.logging.debug(request)
|
||||
})
|
||||
}
|
||||
|
||||
public down(): Promise<void> {
|
||||
return new Promise(res => {
|
||||
// Stop the websocket server, if it exists
|
||||
if ( this.server ) {
|
||||
this.server.close(() => res())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user