@bjoernboss/mws 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -6
- package/dist/base.d.ts +7 -6
- package/dist/base.js +2 -2
- package/dist/builder.d.ts +14 -0
- package/dist/builder.js +10 -10
- package/dist/cache.d.ts +42 -2
- package/dist/cache.js +81 -41
- package/dist/client.d.ts +144 -19
- package/dist/client.js +177 -153
- package/dist/handler.d.ts +70 -9
- package/dist/handler.js +71 -71
- package/dist/helper.d.ts +24 -1
- package/dist/helper.js +23 -23
- package/dist/log.d.ts +25 -14
- package/dist/log.js +21 -57
- package/dist/server.d.ts +70 -13
- package/dist/server.js +237 -163
- package/package.json +5 -5
package/dist/server.js
CHANGED
|
@@ -13,232 +13,306 @@ export class Server extends libLog.Logger {
|
|
|
13
13
|
_stop;
|
|
14
14
|
_cache;
|
|
15
15
|
_config;
|
|
16
|
-
|
|
16
|
+
_nextEndpoint;
|
|
17
17
|
constructor(config) {
|
|
18
|
-
super('server');
|
|
18
|
+
super(config?.name ?? 'server');
|
|
19
19
|
this.info(`Server created`);
|
|
20
20
|
this._config = new BurntServerConfig(config);
|
|
21
21
|
if (config?.cache instanceof libCache.CacheHost)
|
|
22
22
|
this._cache = config.cache;
|
|
23
23
|
else
|
|
24
24
|
this._cache = libCache.createCache(config?.cache);
|
|
25
|
-
this.
|
|
25
|
+
this._nextEndpoint = 0;
|
|
26
26
|
let stoppedResolver = () => { };
|
|
27
|
-
this._stop = {
|
|
27
|
+
this._stop = { list: [], stoppedPromise: new Promise((res) => stoppedResolver = res), stoppedResolver: () => { }, stopping: false };
|
|
28
28
|
this._stop.stoppedResolver = stoppedResolver;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
/** listener is automatically stopped when the server is stopped or the handler stops itself */
|
|
31
|
+
listen(handler, options) {
|
|
32
|
+
return Listener._fromParams(this, handler, ++this._nextEndpoint, this._stop, options ?? {});
|
|
33
|
+
}
|
|
34
|
+
/** shutdown the server and unlink all modules (immediately kills all open connections and listener; can be called multiple times) */
|
|
35
|
+
stop() {
|
|
36
|
+
if (this._stop.stopping)
|
|
37
|
+
return this._stop.stoppedPromise;
|
|
38
|
+
this._stop.stopping = true;
|
|
39
|
+
(async () => {
|
|
40
|
+
/* stop all connections and listener */
|
|
41
|
+
this.info('Stopping server connections and modules');
|
|
42
|
+
const promises = [];
|
|
43
|
+
for (const cb of this._stop.list)
|
|
44
|
+
promises.push(cb());
|
|
45
|
+
await Promise.all(promises);
|
|
46
|
+
this.info('Server stopped');
|
|
47
|
+
this._stop.stoppedResolver();
|
|
48
|
+
})();
|
|
49
|
+
return this._stop.stoppedPromise;
|
|
50
|
+
}
|
|
51
|
+
/** cache host used by this server */
|
|
52
|
+
get cache() {
|
|
53
|
+
return this._cache;
|
|
54
|
+
}
|
|
55
|
+
/** configuration used by this server */
|
|
56
|
+
get config() {
|
|
57
|
+
return this._config;
|
|
58
|
+
}
|
|
59
|
+
/** resolves once the server has stopped */
|
|
60
|
+
get stopped() {
|
|
61
|
+
return this._stop.stoppedPromise;
|
|
62
|
+
}
|
|
63
|
+
/** check if the server is still running */
|
|
64
|
+
get running() {
|
|
65
|
+
return !this._stop.stopping;
|
|
66
|
+
}
|
|
67
|
+
/** link the given module to the server (automatically unlinked upon server stop) */
|
|
68
|
+
linkModule(module, unlinked) {
|
|
69
|
+
const cleanup = () => attached.unlink();
|
|
70
|
+
this._stop.list.push(cleanup);
|
|
71
|
+
const attached = module._rootAttachToServer(this, () => {
|
|
72
|
+
if (unlinked != null)
|
|
73
|
+
unlinked();
|
|
74
|
+
if (!this._stop.stopping)
|
|
75
|
+
this._stop.list = this._stop.list.filter((v) => v != cleanup);
|
|
76
|
+
});
|
|
77
|
+
return attached;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Either 'listening' or 'failed' is fired, followed at some point by a 'stopped' event.
|
|
82
|
+
* 'address' of 'listening' event is null for serverless listener.
|
|
83
|
+
*/
|
|
84
|
+
export class Listener {
|
|
85
|
+
_host;
|
|
86
|
+
_self;
|
|
87
|
+
_stop;
|
|
88
|
+
_native;
|
|
89
|
+
_handling;
|
|
90
|
+
_emitter;
|
|
91
|
+
_config;
|
|
92
|
+
constructor(server, id, hostStop, clientConfig, handler) {
|
|
93
|
+
this._host = { self: server, stop: hostStop };
|
|
94
|
+
this._self = { endpoint: `endpoint!${id}`, listening: null, protocol: '' };
|
|
95
|
+
this._emitter = new libEvents.EventEmitter();
|
|
96
|
+
this._config = clientConfig;
|
|
97
|
+
this._handling = { count: 0, promise: null, resolver: () => { } };
|
|
98
|
+
let stoppedResolver = () => { };
|
|
99
|
+
this._stop = { stoppedPromise: new Promise((res) => stoppedResolver = res), stoppedResolver: () => { }, stopping: false };
|
|
100
|
+
this._stop.stoppedResolver = stoppedResolver;
|
|
101
|
+
/* register the handler and the cleanup callback */
|
|
102
|
+
const attached = handler._rootAttachToServer(this._host.self, () => this.stop());
|
|
103
|
+
const wss = new libWs.WebSocketServer({ noServer: true });
|
|
104
|
+
this._native = { wss, attached, server: null, cleanup: () => this.stop() };
|
|
105
|
+
this._host.stop.list.push(this._native.cleanup);
|
|
106
|
+
}
|
|
107
|
+
emitEventSync(event, ...args) {
|
|
32
108
|
try {
|
|
33
|
-
|
|
109
|
+
this._emitter.emit(event, ...args);
|
|
34
110
|
}
|
|
35
111
|
catch (err) {
|
|
36
|
-
|
|
112
|
+
this._host.self.error(`Unhandled exception in ${event} listener: ${err.message}`);
|
|
37
113
|
}
|
|
38
|
-
|
|
114
|
+
}
|
|
115
|
+
performServerListening(address) {
|
|
116
|
+
if (typeof address == 'string')
|
|
117
|
+
address = { address, port: 0, family: 'unix' };
|
|
118
|
+
if (address == null)
|
|
119
|
+
this._self.listening = 'serverless';
|
|
120
|
+
else
|
|
121
|
+
this._self.listening = `[${address.address}]:${address.port} [family: ${address.family}]`;
|
|
122
|
+
this._host.self.info(`Successfully started ${this._self.endpoint} on ${this._self.listening} with handler [${this._native.attached.module.identity}]`);
|
|
123
|
+
this.emitEventSync('listening', address);
|
|
124
|
+
}
|
|
125
|
+
async handleClient(request, client) {
|
|
126
|
+
if (this._handling.count++ == 0)
|
|
127
|
+
this._handling.promise = new Promise((res) => this._handling.resolver = res);
|
|
128
|
+
const endpoint = `${this._host.self.identity}.${this._self.endpoint}`;
|
|
129
|
+
/* register the completed log immediately to ensure it is logged as the first thing before the other completed awaits execute */
|
|
130
|
+
client.log(`Connected to [${endpoint}] using [method: ${request.method ?? '_'}] from [${request.socket.remoteAddress}]:${request.socket.remotePort} to [${client.url.hostname}]:[${request.url}] (user-agent: [${request.headers['user-agent'] ?? ''}])`);
|
|
131
|
+
client.completed.then(() => client.log(`Completed on [${endpoint}]`));
|
|
39
132
|
try {
|
|
40
|
-
await
|
|
133
|
+
await this._native.attached.handle(client);
|
|
41
134
|
}
|
|
42
135
|
catch (err) {
|
|
43
|
-
|
|
44
|
-
request.destroy(new Error('Unhandled exception'));
|
|
45
|
-
}
|
|
46
|
-
this.log(`Listener[${id}]: Client [${client.logIdentity}] completed`);
|
|
47
|
-
}
|
|
48
|
-
fetchAddress(server) {
|
|
49
|
-
const raw = server.address();
|
|
50
|
-
if (raw == null)
|
|
51
|
-
return null;
|
|
52
|
-
if (typeof raw == 'string')
|
|
53
|
-
return { address: raw, port: 0, family: 'unix' };
|
|
54
|
-
return raw;
|
|
55
|
-
}
|
|
56
|
-
async performServerCleanup(server, id, who, attached, wss) {
|
|
57
|
-
/* close the server and any existing connections within it */
|
|
58
|
-
const address = this.fetchAddress(server);
|
|
59
|
-
if (address != null && id != null)
|
|
60
|
-
this.info(`Stopping ${who} on [${address.address}]:${address.port} [family: ${address.family}] as listener [${id}] with handler [${attached.module.logIdentity}]`);
|
|
61
|
-
const serverStopped = new Promise((res) => server.close(() => res()));
|
|
62
|
-
server.closeAllConnections();
|
|
63
|
-
/* close all of the web-sockets (after unlinking the module to
|
|
64
|
-
* ensure it has a chance to clean the connections itself) */
|
|
65
|
-
await attached.unlink();
|
|
66
|
-
const sockets = [];
|
|
67
|
-
for (const ws of [...wss.clients]) {
|
|
68
|
-
if (ws.readyState == libWs.WebSocket.CLOSED)
|
|
69
|
-
continue;
|
|
70
|
-
sockets.push(new Promise((res) => ws.on('close', () => res())));
|
|
71
|
-
ws.terminate();
|
|
136
|
+
client.respondInternalError(`Uncaught exception: ${err.message}`);
|
|
72
137
|
}
|
|
73
|
-
|
|
74
|
-
/* await the server being fully stopped */
|
|
75
|
-
await serverStopped;
|
|
76
|
-
}
|
|
77
|
-
emitEventSync(emitter, event, ...args) {
|
|
138
|
+
/* kill the connection on any errors, as the finalizing normally ensures that the response is completed */
|
|
78
139
|
try {
|
|
79
|
-
|
|
140
|
+
await client._finalizeConnection();
|
|
80
141
|
}
|
|
81
142
|
catch (err) {
|
|
82
|
-
|
|
143
|
+
client.error(`Fatal error while finalizing [${client.identity}]: ${err.message}`);
|
|
144
|
+
request.destroy(new Error('Unhandled exception'));
|
|
83
145
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const config = {
|
|
88
|
-
requireHostHeader: true,
|
|
89
|
-
key: libFs.readFileSync(options.tls.key),
|
|
90
|
-
cert: libFs.readFileSync(options.tls.cert),
|
|
91
|
-
connectionsCheckingInterval: CONNECTION_TIMEOUT_CHECKING
|
|
92
|
-
};
|
|
93
|
-
return libHttps.createServer(config);
|
|
146
|
+
if (--this._handling.count == 0) {
|
|
147
|
+
this._handling.promise = null;
|
|
148
|
+
this._handling.resolver();
|
|
94
149
|
}
|
|
95
|
-
if (options?.server != null)
|
|
96
|
-
return options.server.server;
|
|
97
|
-
return libHttp.createServer({ requireHostHeader: true, connectionsCheckingInterval: CONNECTION_TIMEOUT_CHECKING });
|
|
98
150
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const emitter = new libEvents.EventEmitter();
|
|
104
|
-
/* setup the listener interface to be returned */
|
|
105
|
-
let stopping = null, listenLogged = false;
|
|
106
|
-
let server = null;
|
|
107
|
-
const listener = {
|
|
108
|
-
on: function (event, cb) { emitter.on(event, cb); return this; },
|
|
109
|
-
once: function (event, cb) { emitter.once(event, cb); return this; },
|
|
110
|
-
off: function (event, cb) { emitter.off(event, cb); return this; },
|
|
111
|
-
stop: () => {
|
|
112
|
-
if (stopping != null)
|
|
113
|
-
return stopping;
|
|
114
|
-
/* already setup the promise to ensure nested stop-calls will already see it set */
|
|
115
|
-
let resolver = () => { };
|
|
116
|
-
stopping = new Promise((res) => resolver = res);
|
|
117
|
-
(async () => {
|
|
118
|
-
if (server != null)
|
|
119
|
-
await this.performServerCleanup(server, (listenLogged ? idListener : null), who, attached, wss);
|
|
120
|
-
/* check if the cleanup can be removed from the stop list (only if stopping is not already in progress) */
|
|
121
|
-
if (!this._stop.stopping)
|
|
122
|
-
this._stop.listener = this._stop.listener.filter((v) => v != listener.stop);
|
|
123
|
-
this.emitEventSync(emitter, 'stopped');
|
|
124
|
-
resolver();
|
|
125
|
-
})();
|
|
126
|
-
return stopping;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
151
|
+
configure(options) {
|
|
152
|
+
this._self.protocol = ((options.tls != null || options.server?.secure === true || (options.server == null && options.serverless?.secure === true)) ? 'https' : 'http');
|
|
153
|
+
const who = (options.tls == null && options.server == null && options.serverless != null ? 'serverless' : `${this._self.protocol}|${options.hostname ?? ''}:${options.port ?? 0}`);
|
|
154
|
+
/* defer the failure to allow the caller to attach listeners */
|
|
129
155
|
const performFailure = (err) => {
|
|
130
|
-
/* defer the failure to allow the caller to attach listeners */
|
|
131
156
|
process.nextTick(() => {
|
|
132
|
-
if (stopping
|
|
133
|
-
this.emitEventSync(
|
|
134
|
-
|
|
157
|
+
if (!this._stop.stopping)
|
|
158
|
+
this.emitEventSync('failed', err);
|
|
159
|
+
this.stop();
|
|
135
160
|
});
|
|
136
161
|
};
|
|
162
|
+
this._host.self.trace(`Setting up listening to [${who}] and handler [${this._native.attached.module.identity}]`);
|
|
137
163
|
/* check if the server is being stopped, in which case nothing will be listened to */
|
|
138
|
-
if (this.
|
|
139
|
-
this.error(`Stopped server cannot listen to ${who}`);
|
|
140
|
-
performFailure(new Error('Server already stopped'));
|
|
141
|
-
return listener;
|
|
164
|
+
if (this._host.stop.stopping) {
|
|
165
|
+
this._host.self.error(`Stopped server cannot listen to [${who}]`);
|
|
166
|
+
return performFailure(new Error('Server already stopped'));
|
|
142
167
|
}
|
|
143
|
-
|
|
168
|
+
let server = null;
|
|
144
169
|
try {
|
|
145
|
-
server
|
|
170
|
+
/* setup the actual server server */
|
|
171
|
+
if (options.tls != null) {
|
|
172
|
+
const config = {
|
|
173
|
+
requireHostHeader: true,
|
|
174
|
+
key: libFs.readFileSync(options.tls.key),
|
|
175
|
+
cert: libFs.readFileSync(options.tls.cert),
|
|
176
|
+
connectionsCheckingInterval: CONNECTION_TIMEOUT_CHECKING
|
|
177
|
+
};
|
|
178
|
+
server = libHttps.createServer(config);
|
|
179
|
+
}
|
|
180
|
+
else if (options.server != null)
|
|
181
|
+
server = options.server.server;
|
|
182
|
+
else if (options.serverless == null)
|
|
183
|
+
server = libHttp.createServer({ requireHostHeader: true, connectionsCheckingInterval: CONNECTION_TIMEOUT_CHECKING });
|
|
146
184
|
}
|
|
147
185
|
catch (err) {
|
|
148
|
-
this.error(`Error creating server ${who}: ${err.message}`);
|
|
149
|
-
performFailure(err);
|
|
150
|
-
return listener;
|
|
186
|
+
this._host.self.error(`Error creating server [${who}]: ${err.message}`);
|
|
187
|
+
return performFailure(err);
|
|
151
188
|
}
|
|
152
|
-
/*
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.
|
|
189
|
+
/* check if this is a serverless run, in which case the server does not need to be configured further */
|
|
190
|
+
if (server == null)
|
|
191
|
+
return this.performServerListening(null);
|
|
192
|
+
this._native.server = server;
|
|
156
193
|
/* register the corresponding connection handlers and error handlers */
|
|
157
|
-
|
|
158
|
-
server.on('
|
|
159
|
-
const client = libClient.ClientRequest.fromRequest(protocol, req, resp, { cache: this._cache, config: clientConfig });
|
|
160
|
-
this.handleClient(req, client, attached, idListener);
|
|
161
|
-
});
|
|
162
|
-
server.on('upgrade', (req, sock, head) => {
|
|
163
|
-
const client = libClient.ClientRequest.fromUpgrade(protocol, req, sock, head, { cache: this._cache, config: clientConfig, wss });
|
|
164
|
-
this.handleClient(req, client, attached, idListener);
|
|
165
|
-
});
|
|
194
|
+
server.on('request', (req, resp) => this.handleRequest(req, resp));
|
|
195
|
+
server.on('upgrade', (req, sock, head) => this.handleUpgrade(req, sock, head));
|
|
166
196
|
server.once('error', (err) => {
|
|
167
|
-
if (stopping
|
|
197
|
+
if (this._stop.stopping)
|
|
168
198
|
return;
|
|
169
|
-
this.error(`Error while listening to ${who}: ${err.message}`);
|
|
170
|
-
this.emitEventSync(
|
|
171
|
-
|
|
199
|
+
this._host.self.error(`Error while listening to [${who}]: ${err.message}`);
|
|
200
|
+
this.emitEventSync('failed', err);
|
|
201
|
+
this.stop();
|
|
172
202
|
});
|
|
173
203
|
server.on('listening', () => {
|
|
174
|
-
if (stopping
|
|
175
|
-
|
|
176
|
-
const address = this.fetchAddress(server);
|
|
177
|
-
this.info(`Successfully started ${who} on [${address.address}]:${address.port} [family: ${address.family}] as listener [${idListener}] with handler [${handler.logIdentity}]`);
|
|
178
|
-
listenLogged = true;
|
|
179
|
-
this.emitEventSync(emitter, 'listening', address);
|
|
204
|
+
if (!this._stop.stopping)
|
|
205
|
+
this.performServerListening(server.address());
|
|
180
206
|
});
|
|
181
207
|
/* configure the server to have a minimum header receive timeout, overall connection-loss timeout,
|
|
182
208
|
* and keep-alive timeout (no request-timeout, as this is handled manually by the throughput control) */
|
|
183
|
-
server.headersTimeout = this.
|
|
184
|
-
server.timeout = this.
|
|
185
|
-
server.keepAliveTimeout = this.
|
|
209
|
+
server.headersTimeout = this._host.self.config.headerTimeout;
|
|
210
|
+
server.timeout = this._host.self.config.connectionTimeout;
|
|
211
|
+
server.keepAliveTimeout = this._host.self.config.keepAliveTimeout;
|
|
186
212
|
server.requestTimeout = 0;
|
|
187
213
|
/* start the actual server listening */
|
|
188
214
|
try {
|
|
189
|
-
server.listen(options
|
|
215
|
+
server.listen(options.port, options.hostname);
|
|
190
216
|
}
|
|
191
217
|
catch (err) {
|
|
192
|
-
this.error(`Error starting listener ${who}: ${err.message}`);
|
|
193
|
-
performFailure(err);
|
|
218
|
+
this._host.self.error(`Error starting listener [${who}]: ${err.message}`);
|
|
219
|
+
return performFailure(err);
|
|
194
220
|
}
|
|
221
|
+
}
|
|
222
|
+
static _fromParams(server, handler, id, hostStop, options) {
|
|
223
|
+
const clientConfig = (options.client != null ? libClient.BurntClientConfig.from(options.client) : server.config.client);
|
|
224
|
+
const listener = new Listener(server, id, hostStop, clientConfig, handler);
|
|
225
|
+
listener.configure(options);
|
|
195
226
|
return listener;
|
|
196
227
|
}
|
|
197
|
-
|
|
198
|
-
async
|
|
199
|
-
if (this._stop.stopping)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
for (const cb of this._stop.listener)
|
|
206
|
-
promises.push(cb());
|
|
207
|
-
await Promise.all(promises);
|
|
208
|
-
this.info('Server stopped');
|
|
209
|
-
this._stop.stoppedResolver();
|
|
210
|
-
return this._stop.stoppedPromise;
|
|
228
|
+
/** manually pass a request through the listener (takes ownership of the request; will kill the connection if the listener is not running anymore) */
|
|
229
|
+
async handleRequest(request, response) {
|
|
230
|
+
if (this._stop.stopping) {
|
|
231
|
+
request.destroy(new Error('Listener not running anymore'));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const client = libClient.ClientRequest._fromRequest(this._self.protocol, request, response, this._config, this._host.self);
|
|
235
|
+
await this.handleClient(request, client);
|
|
211
236
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
237
|
+
/** manually pass an upgrade through the listener (takes ownership of the connection; immediately closes the connection if the listener is not running anymore) */
|
|
238
|
+
async handleUpgrade(request, socket, head) {
|
|
239
|
+
if (this._stop.stopping) {
|
|
240
|
+
request.destroy(new Error('Listener not running anymore'));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const client = libClient.ClientRequest._fromUpgrade(this._self.protocol, request, socket, head, this._config, this._host.self, this._native.wss);
|
|
244
|
+
await this.handleClient(request, client);
|
|
245
|
+
}
|
|
246
|
+
/** server this listener belongs to */
|
|
247
|
+
get server() {
|
|
248
|
+
return this._host.self;
|
|
215
249
|
}
|
|
216
|
-
|
|
250
|
+
/** client configuration used for this listener */
|
|
217
251
|
get config() {
|
|
218
252
|
return this._config;
|
|
219
253
|
}
|
|
220
|
-
|
|
254
|
+
/** stop the listener and return promise which resolves once fully stopped */
|
|
255
|
+
stop() {
|
|
256
|
+
if (this._stop.stopping)
|
|
257
|
+
return this._stop.stoppedPromise;
|
|
258
|
+
this._stop.stopping = true;
|
|
259
|
+
(async () => {
|
|
260
|
+
/* close the server and any existing connections within it */
|
|
261
|
+
let serverStopped = null;
|
|
262
|
+
if (this._native.server != null) {
|
|
263
|
+
serverStopped = new Promise((res) => this._native.server.close(() => res()));
|
|
264
|
+
this._native.server.closeAllConnections();
|
|
265
|
+
}
|
|
266
|
+
else
|
|
267
|
+
serverStopped = Promise.resolve();
|
|
268
|
+
await this._native.attached.unlink();
|
|
269
|
+
/* close all of the web-sockets (after unlinking the module to
|
|
270
|
+
* ensure it has a chance to clean the connections itself) */
|
|
271
|
+
const sockets = [];
|
|
272
|
+
for (const ws of [...this._native.wss.clients]) {
|
|
273
|
+
if (ws.readyState == libWs.WebSocket.CLOSED)
|
|
274
|
+
continue;
|
|
275
|
+
sockets.push(new Promise((res) => ws.on('close', () => res())));
|
|
276
|
+
ws.terminate();
|
|
277
|
+
}
|
|
278
|
+
await Promise.all(sockets);
|
|
279
|
+
/* wait for any handled connections to be over and for the server to be fully stopped */
|
|
280
|
+
while (this._handling.promise != null)
|
|
281
|
+
await this._handling.promise;
|
|
282
|
+
await serverStopped;
|
|
283
|
+
if (this._self.listening != null)
|
|
284
|
+
this._host.self.info(`Stopped ${this._self.endpoint} on ${this._self.listening} with handler [${this._native.attached.module.identity}]`);
|
|
285
|
+
/* check if the cleanup can be removed from the stop list (only if stopping is not already in progress) */
|
|
286
|
+
if (!this._host.stop.stopping)
|
|
287
|
+
this._host.stop.list = this._host.stop.list.filter((v) => v != this._native.cleanup);
|
|
288
|
+
this.emitEventSync('stopped');
|
|
289
|
+
this._stop.stoppedResolver();
|
|
290
|
+
})();
|
|
291
|
+
return this._stop.stoppedPromise;
|
|
292
|
+
}
|
|
293
|
+
/** resolves once the server has stopped */
|
|
221
294
|
get stopped() {
|
|
222
295
|
return this._stop.stoppedPromise;
|
|
223
296
|
}
|
|
224
|
-
|
|
297
|
+
/** check if the server is still running */
|
|
225
298
|
get running() {
|
|
226
299
|
return !this._stop.stopping;
|
|
227
300
|
}
|
|
228
|
-
/*
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
301
|
+
/* -------- event handler interfaces -------- */
|
|
302
|
+
on(event, listener) {
|
|
303
|
+
this._emitter.on(event, listener);
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
once(event, listener) {
|
|
307
|
+
this._emitter.once(event, listener);
|
|
308
|
+
return this;
|
|
309
|
+
}
|
|
310
|
+
off(event, listener) {
|
|
311
|
+
this._emitter.off(event, listener);
|
|
312
|
+
return this;
|
|
239
313
|
}
|
|
240
314
|
}
|
|
241
|
-
|
|
315
|
+
/** wrapper to create a simple server */
|
|
242
316
|
export function createServer(config) {
|
|
243
317
|
return new Server(config);
|
|
244
318
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bjoernboss/mws",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Modular Web Server — a TypeScript framework for hosting isolated modules behind HTTP/HTTPS+WebSocket endpoints",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
17
|
"exports": {
|
|
18
18
|
".": {
|
|
19
|
-
"
|
|
20
|
-
"
|
|
19
|
+
"default": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts"
|
|
21
21
|
},
|
|
22
22
|
"./*.js": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"default": "./dist/*.js",
|
|
24
|
+
"types": "./dist/*.d.ts"
|
|
25
25
|
},
|
|
26
26
|
"./package.json": "./package.json"
|
|
27
27
|
},
|