@microfleet/core
Version:
Abstract microservice core
147 lines (119 loc) • 3.78 kB
text/typescript
import assert = require('assert')
import { NotPermittedError } from 'common-errors'
import { Plugin, Server, ServerOptions } from '@hapi/hapi'
import Joi = require('@hapi/joi')
import { ActionTransport, Microfleet } from '../../../..'
import { PluginInterface } from '../../../../types'
import attachRouter, { HapiRouterConfig } from './router/attach'
import * as RequestTracker from '../../../router/request-tracker'
export interface HapiPlugin {
plugin: string | Plugin<any>;
options?: any;
once?: boolean;
}
const defaultPlugins: HapiPlugin[] = [{
options: {},
plugin: './plugins/redirect',
}, {
options: {},
plugin: './plugins/state',
}]
export interface HapiPluginConfig {
server: {
handlerConfig: {
server: ServerOptions
plugins: {
list: any[]
options?: any
}
views?: any
}
host?: string
port?: number
attachSocketIO?: boolean
}
router: HapiRouterConfig & {
enabled: boolean
}
}
function createHapiServer(config: HapiPluginConfig, service: Microfleet): PluginInterface {
const { handlerConfig } = config.server
handlerConfig.server.address = config.server.host || '0.0.0.0'
handlerConfig.server.port = config.server.port ? config.server.port : 0
assert(service.hasPlugin('logger'), 'must include logger plugin')
const server = service.http = new Server(handlerConfig.server)
server.validator(Joi)
let routerPlugin: HapiPlugin
if (config.router.enabled) {
routerPlugin = attachRouter(service, config.router)
}
// exposes microfleet inside the server for tighter integrations
server.decorate('server', 'microfleet', service as any)
async function initPlugins() {
const { list, options } = handlerConfig.plugins
const plugins = defaultPlugins.concat(list)
if (handlerConfig.views) {
plugins.push({
options: {},
plugin: '@hapi/vision',
})
plugins.push({
options: handlerConfig.views,
plugin: './plugins/views',
})
}
if (routerPlugin !== undefined) {
plugins.push(routerPlugin)
}
const registrations = []
for (const pluguinConfiguration of plugins) {
registrations.push({
options: pluguinConfiguration.options,
plugin: typeof pluguinConfiguration.plugin === 'string'
? require(pluguinConfiguration.plugin)
: pluguinConfiguration.plugin,
})
}
return server.register(registrations, options)
}
async function startServer() {
if (config.server.attachSocketIO) {
if (!service.socketIO) {
throw new NotPermittedError('SocketIO plugin not found')
}
service.socketIO.listen(server.listener, (service.config.socketIO as any)?.options)
}
await initPlugins()
await server.start()
service.log.info(
{ transport: 'http', http: '@hapi/hapi' },
'listening on http://%s:%s',
handlerConfig.server.address,
server.info.port
)
service.emit('plugin:start:http', server)
return server
}
function getRequestCount() {
return RequestTracker.getRequestCount(service, ActionTransport.http)
}
async function stopServer() {
const { started } = server.info
if (started) {
/* Socket depends on Http transport. Wait for its requests here */
/* Call of socketIO.close() causes all active connections close */
if (config.server.attachSocketIO) {
await RequestTracker.waitForRequestsToFinish(service, ActionTransport.socketIO)
}
/* Server waits for connection finish anyway */
await server.stop()
}
service.emit('plugin:stop:http', server)
}
return {
getRequestCount,
close: stopServer,
connect: startServer,
}
}
export default createHapiServer