-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExpressAdapter.js
More file actions
112 lines (98 loc) · 3.07 KB
/
ExpressAdapter.js
File metadata and controls
112 lines (98 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* ExpressAdapter — CDI-managed Express server.
*
* Creates an Express application during init(), registers controllers,
* starts listening during run(), and closes the server on destroy().
*
* Reads from config:
* server.port — listen port (default: 3000)
* server.host — listen host (default: '0.0.0.0')
*
* Makes the ApplicationContext available to route handlers via app.locals.ctx.
*/
import express from 'express';
import MiddlewarePipeline from '@alt-javascript/boot/MiddlewarePipeline.js';
import ControllerRegistrar from './ControllerRegistrar.js';
export default class ExpressAdapter {
constructor() {
this._app = null;
this._server = null;
this._applicationContext = null;
this._port = 3000;
this._host = '0.0.0.0';
}
/**
* CDI aware interface — receives the ApplicationContext.
* @param {ApplicationContext} ctx
*/
setApplicationContext(ctx) {
this._applicationContext = ctx;
}
/** @returns {object|null} logger from context, or null */
get _logger() {
try {
return this._applicationContext?.get('logger', null);
} catch {
return null;
}
}
/**
* CDI init lifecycle — create Express app, register controllers.
*/
init() {
const config = this._applicationContext.config;
if (config.has('server.port')) {
this._port = config.get('server.port');
}
if (config.has('server.host')) {
this._host = config.get('server.host');
}
this._app = express();
this._app.use(express.json());
this._app.locals.ctx = this._applicationContext;
// Collect CDI middleware sorted by order
const middlewares = MiddlewarePipeline.collect(this._applicationContext);
// Register controllers with the middleware pipeline
ControllerRegistrar.register(this._app, this._applicationContext, middlewares);
if (this._logger) {
this._logger.verbose(`Express app created, ${ControllerRegistrar.routeCount} routes registered`);
}
}
/**
* CDI run lifecycle — start listening.
*/
async run() {
return new Promise((resolve) => {
this._server = this._app.listen(this._port, this._host, () => {
if (this._logger) {
this._logger.info(`Express listening on ${this._host}:${this._port}`);
}
resolve();
});
});
}
/**
* CDI destroy lifecycle — close the HTTP server and exit cleanly.
* Called once per SIGINT/SIGTERM by the CDI lifecycle. Idempotent.
*/
destroy() {
if (!this._server) return;
const server = this._server;
this._server = null; // guard against double-call
if (this._logger) {
this._logger.info('Express server closing...');
}
server.closeAllConnections?.(); // Node 18.2+ — drop keep-alive sockets immediately
server.close();
// Give the event loop 500ms to flush logs, then exit.
setTimeout(() => process.exit(0), 500);
}
/** @returns {express.Application} the Express app instance */
get app() {
return this._app;
}
/** @returns {http.Server} the HTTP server (after run()) */
get server() {
return this._server;
}
}