Do not subclass Bootstrap.ts

This commit is contained in:
Jerko Steiner 2019-08-31 15:29:37 +07:00
parent 5688a65cb0
commit dcc5b52725
5 changed files with 70 additions and 23 deletions

View File

@ -5,23 +5,60 @@ import { AddressInfo } from 'net'
import { Database } from '../database/Database' import { Database } from '../database/Database'
import { IDatabase } from '../database/IDatabase' import { IDatabase } from '../database/IDatabase'
import { loggerFactory, SqlLogger } from '../logger' import { loggerFactory, SqlLogger } from '../logger'
import { configureServer } from './configureServer' import { ServerConfigurator } from './configureServer'
import { createServer } from './createServer' import { createServer } from './createServer'
import { IApplication } from './IApplication' import { IApplication } from './IApplication'
import { IBootstrap } from './IBootstrap' import { IBootstrap } from './IBootstrap'
import { IConfig } from './IConfig' import { IConfig } from './IConfig'
import { IServerConfig } from './IServerConfig'
export interface IBootstrapParams {
readonly config: IConfig
readonly configureServer: ServerConfigurator
readonly namespace?: Namespace
readonly exit?: (code: number) => void
readonly entities?: object
readonly migrations?: object
}
// tslint:disable-next-line
function getFunctions(obj: object): Function[] {
return Object.keys(obj)
.map(k => (obj as any)[k])
.filter(f => typeof f === 'function')
}
export class Bootstrap implements IBootstrap { export class Bootstrap implements IBootstrap {
protected config: IConfig
protected configureServer: ServerConfigurator
protected namespace: Namespace
protected exit: (code: number) => void
protected server?: Server protected server?: Server
protected inUse: boolean = false protected inUse: boolean = false
readonly application: IApplication readonly application: IApplication
readonly database: IDatabase readonly database: IDatabase
constructor( constructor(params: IBootstrapParams) {
private readonly config: IConfig, this.config = {
protected readonly namespace: Namespace = createNamespace('application'), ...params.config,
protected readonly exit: (code: number) => void = process.exit, app: {
) { ...params.config.app,
db: {
...params.config.app.db,
entities: params.entities
? getFunctions(params.entities)
: params.config.app.db.entities,
migrations: params.migrations
? getFunctions(params.migrations)
: params.config.app.db.migrations,
},
},
}
this.configureServer = params.configureServer
this.namespace = params.namespace || createNamespace('application')
this.exit = params.exit || process.exit
this.database = this.createDatabase() this.database = this.createDatabase()
this.application = this.createApplication(this.database) this.application = this.createApplication(this.database)
} }
@ -31,12 +68,13 @@ export class Bootstrap implements IBootstrap {
} }
protected createDatabase(): IDatabase { protected createDatabase(): IDatabase {
const sqlLogger = new SqlLogger( const {namespace} = this
loggerFactory.getLogger('sql'), this.namespace) const sqlLogger = new SqlLogger(loggerFactory.getLogger('sql'), namespace)
return new Database(this.namespace, sqlLogger, this.getConfig().app.db) return new Database(namespace, sqlLogger, this.getConfig().app.db)
} }
protected createApplication(database: IDatabase): IApplication { protected createApplication(database: IDatabase): IApplication {
const {configureServer} = this
return createServer(configureServer(this.getConfig(), database)) return createServer(configureServer(this.getConfig(), database))
} }

View File

@ -14,14 +14,14 @@ import { TransactionalRouter } from '../router'
import { IRoutes, IContext } from '@rondo.dev/common' import { IRoutes, IContext } from '@rondo.dev/common'
import { Express } from 'express-serve-static-core' import { Express } from 'express-serve-static-core'
export type AppConfigurator< export type ServerConfigurator<
T extends IServerConfig = IServerConfig T extends IServerConfig = IServerConfig
> = ( > = (
config: IConfig, config: IConfig,
database: IDatabase, database: IDatabase,
) => T ) => T
export const configureServer: AppConfigurator = (config, database) => { export const configureServer: ServerConfigurator = (config, database) => {
const logger = loggerFactory.getLogger('api') const logger = loggerFactory.getLogger('api')

View File

@ -1,12 +1,8 @@
if (!process.env.LOG) {
process.env.LOG = 'api,sql:warn'
}
import {config} from './config' import {config} from './config'
import {Bootstrap} from './application/Bootstrap' import {Bootstrap} from './application/Bootstrap'
import {configureServer} from './application/configureServer'
export const bootstrap = new Bootstrap(config) export default new Bootstrap({
// FIXME determine a port by parsing app url from config config,
const port: string | number = process.env.PORT || 3000 configureServer,
})
bootstrap.listen(port)

View File

@ -1,3 +1,8 @@
if (require.main === module) {
if (!process.env.LOG) {
process.env.LOG = 'api,sql:warn'
}
}
export * from './application' export * from './application'
export * from './database' export * from './database'
export * from './entities' export * from './entities'
@ -14,3 +19,9 @@ export * from './validator'
import * as rpc from './rpc' import * as rpc from './rpc'
export {rpc} export {rpc}
import bootstrap from './bootstrap'
if (require.main === module) {
bootstrap.exec(process.argv[2])
}

View File

@ -1,4 +1,5 @@
import {Bootstrap} from './application/Bootstrap' import {Bootstrap} from './application/Bootstrap'
import {configureServer} from './application/configureServer'
import {IAPIDef} from '@rondo.dev/common' import {IAPIDef} from '@rondo.dev/common'
import {TestUtils} from './test-utils' import {TestUtils} from './test-utils'
import {config} from './config' import {config} from './config'
@ -6,11 +7,12 @@ import {createNamespace} from 'cls-hooked'
export const exit = jest.fn() export const exit = jest.fn()
export const bootstrap = new Bootstrap( export const bootstrap = new Bootstrap({
config, config,
createNamespace('test'), configureServer,
namespace: createNamespace('test'),
exit, exit,
) })
// TODO separate IAPIDef between projects // TODO separate IAPIDef between projects
export const test = new TestUtils<IAPIDef>(bootstrap) export const test = new TestUtils<IAPIDef>(bootstrap)