const express = require('express'); const config = require('../config/app'); const logger = require('./utils/logger'); const migrate = require('./storage/migrate'); const { createHttpJsonConnector } = require('./connectors/httpJsonConnector'); const { createHl7TcpConnector } = require('./connectors/hl7TcpConnector'); const { createAstmSerialConnector } = require('./connectors/astmSerialConnector'); const { processMessage } = require('./pipeline/workflow'); const { startWorker, stopWorker } = require('./pipeline/deliveryWorker'); const instrumentService = require('./instrumentConfig/service'); const { validateAndLoadInstrumentConfigs } = require('./instrumentConfig/validator'); const { createHealthRouter } = require('./routes/health'); const { router: instrumentRouter } = require('./routes/instrumentConfig'); const metricsRouter = require('./routes/metrics'); async function bootstrap() { validateAndLoadInstrumentConfigs(); await migrate(); await instrumentService.init(); const connectorFactories = { 'http-json': createHttpJsonConnector, 'hl7-tcp': createHl7TcpConnector, 'astm-serial': createAstmSerialConnector }; const connectors = instrumentService.list() .filter((entry) => entry.enabled) .map((entry) => { const createConnector = connectorFactories[entry.connector]; if (!createConnector) { logger.warn({ connector: entry.connector, instrument_id: entry.instrument_id }, 'unknown connector in instrument config, skipping startup'); return null; } return createConnector({ ...(entry.connectorConfig || {}), instrument_id: entry.instrument_id }); }) .filter(Boolean); if (!connectors.length) { logger.warn('no enabled connectors configured, ingestion listeners are disabled'); } connectors.forEach((connector) => { connector.onMessage(async (incoming) => { try { const payload = incoming && Object.prototype.hasOwnProperty.call(incoming, 'payload') ? incoming.payload : incoming; const context = incoming && incoming.context ? incoming.context : {}; await processMessage(connector.name(), payload, context); } catch (err) { logger.error({ err: err.message, connector: connector.name() }, 'pipeline error'); } }); connector.onError((err) => { logger.error({ err: err.message }, `${connector.name()} emitted error`); }); }); await Promise.all(connectors.map((connector) => connector.start())); await startWorker(); const app = express(); app.use('/health', createHealthRouter(connectors)); app.use('/instruments', instrumentRouter); app.use('/metrics', metricsRouter); app.listen(config.healthPort, () => { logger.info({ port: config.healthPort }, 'health server ready'); }); process.on('SIGINT', async () => { logger.info('shutdown signal received'); await shutdown(connectors); process.exit(0); }); process.on('SIGTERM', async () => { logger.info('terminate signal received'); await shutdown(connectors); process.exit(0); }); } async function shutdown(connectors) { await stopWorker(); await Promise.all(connectors.map((connector) => connector.stop())); } bootstrap().catch((err) => { logger.fatal({ err: err.message }, 'failed to start middleware'); process.exit(1); });