@nsshunt/stsappframework 2.19.205 → 2.19.207
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/dist/masterprocessbase.js +18 -68
- package/dist/masterprocessbase.js.map +1 -1
- package/dist/processbase.js +59 -1
- package/dist/processbase.js.map +1 -1
- package/dist/processoptions.js +9 -0
- package/dist/processoptions.js.map +1 -1
- package/dist/serverprocessbase.js +342 -0
- package/dist/serverprocessbase.js.map +1 -0
- package/dist/singleprocessbase.js +13 -220
- package/dist/singleprocessbase.js.map +1 -1
- package/dist/tcpclient/app.js +21 -0
- package/dist/tcpclient/app.js.map +1 -0
- package/dist/tcpclient/app2.js +55 -0
- package/dist/tcpclient/app2.js.map +1 -0
- package/dist/tcpclientserver/app.js +15 -0
- package/dist/tcpclientserver/app.js.map +1 -0
- package/dist/tcpclientserver/appConfig.js +61 -0
- package/dist/tcpclientserver/appConfig.js.map +1 -0
- package/dist/workerprocessbase.js +15 -224
- package/dist/workerprocessbase.js.map +1 -1
- package/package.json +3 -2
- package/run.sh +24 -0
- package/runc1.sh +24 -0
- package/runc2.sh +24 -0
- package/src/commonTypes.ts +1 -1
- package/src/masterprocessbase.ts +11 -66
- package/src/processbase.ts +62 -2
- package/src/processoptions.ts +9 -9
- package/src/serverprocessbase.ts +390 -0
- package/src/singleprocessbase.ts +20 -254
- package/src/tcpclient/app.ts +19 -0
- package/src/tcpclient/app2.ts +55 -0
- package/src/tcpclientserver/app.ts +9 -0
- package/src/tcpclientserver/appConfig.ts +66 -0
- package/src/workerprocessbase.ts +24 -251
- package/types/commonTypes.d.ts +1 -1
- package/types/commonTypes.d.ts.map +1 -1
- package/types/masterprocessbase.d.ts.map +1 -1
- package/types/processbase.d.ts +4 -0
- package/types/processbase.d.ts.map +1 -1
- package/types/processoptions.d.ts +8 -8
- package/types/processoptions.d.ts.map +1 -1
- package/types/serverprocessbase.d.ts +21 -0
- package/types/serverprocessbase.d.ts.map +1 -0
- package/types/singleprocessbase.d.ts +3 -7
- package/types/singleprocessbase.d.ts.map +1 -1
- package/types/tcpclient/app.d.ts +2 -0
- package/types/tcpclient/app.d.ts.map +1 -0
- package/types/tcpclient/app2.d.ts +2 -0
- package/types/tcpclient/app2.d.ts.map +1 -0
- package/types/tcpclientserver/app.d.ts +2 -0
- package/types/tcpclientserver/app.d.ts.map +1 -0
- package/types/tcpclientserver/appConfig.d.ts +3 -0
- package/types/tcpclientserver/appConfig.d.ts.map +1 -0
- package/types/workerprocessbase.d.ts +2 -7
- package/types/workerprocessbase.d.ts.map +1 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ServerProcessBase = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const debug = (0, debug_1.default)(`proc:${process.pid}`);
|
|
9
|
+
const stsconfig_1 = require("@nsshunt/stsconfig");
|
|
10
|
+
const goptions = (0, stsconfig_1.$Options)();
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const cluster_adapter_1 = require("@socket.io/cluster-adapter");
|
|
13
|
+
const redis_streams_adapter_1 = require("@socket.io/redis-streams-adapter");
|
|
14
|
+
const stsutils_1 = require("@nsshunt/stsutils");
|
|
15
|
+
const processoptions_1 = require("./processoptions");
|
|
16
|
+
const processbase_1 = require("./processbase");
|
|
17
|
+
const prom_client_1 = require("prom-client");
|
|
18
|
+
const https_1 = require("https");
|
|
19
|
+
const http_1 = require("http");
|
|
20
|
+
const node_tls_1 = __importDefault(require("node:tls"));
|
|
21
|
+
const socket_io_1 = require("socket.io");
|
|
22
|
+
const redis_1 = require("redis");
|
|
23
|
+
const jayson_1 = __importDefault(require("jayson"));
|
|
24
|
+
/**
|
|
25
|
+
* todo
|
|
26
|
+
* @typedef {Object} options - todo
|
|
27
|
+
* @property {boolean} [wssServer=false] - Create a web socket server on this worker instance
|
|
28
|
+
*/
|
|
29
|
+
class ServerProcessBase extends processbase_1.ProcessBase {
|
|
30
|
+
#masterProcessExitTime = goptions.masterProcessExitTime;
|
|
31
|
+
#io = null;
|
|
32
|
+
#redisClient = null;
|
|
33
|
+
#httpServer = null;
|
|
34
|
+
#expressServer = null;
|
|
35
|
+
#sockets = [];
|
|
36
|
+
#shuttingDown = false;
|
|
37
|
+
constructor(options) {
|
|
38
|
+
super(options);
|
|
39
|
+
}
|
|
40
|
+
get httpServer() {
|
|
41
|
+
return this.#httpServer;
|
|
42
|
+
}
|
|
43
|
+
get io() {
|
|
44
|
+
return this.#io;
|
|
45
|
+
}
|
|
46
|
+
get expressServer() {
|
|
47
|
+
return this.#expressServer;
|
|
48
|
+
}
|
|
49
|
+
set expressServer(val) {
|
|
50
|
+
this.#expressServer = val;
|
|
51
|
+
}
|
|
52
|
+
// Setup server to Prometheus scrapes:
|
|
53
|
+
#SetupPrometheusEndPoints = (expressServer) => {
|
|
54
|
+
// AggregatorRegistry is required here in the worker as well as the master in order for prom-client to work correctly.
|
|
55
|
+
new prom_client_1.AggregatorRegistry();
|
|
56
|
+
const prefix = 'sts_';
|
|
57
|
+
(0, prom_client_1.collectDefaultMetrics)({
|
|
58
|
+
labels: { NODE_APP_INSTANCE: process.pid },
|
|
59
|
+
prefix: prefix
|
|
60
|
+
});
|
|
61
|
+
const c = new prom_client_1.Counter({
|
|
62
|
+
name: 'sts_test_counter',
|
|
63
|
+
help: 'Example of a counter',
|
|
64
|
+
labelNames: ['code'],
|
|
65
|
+
});
|
|
66
|
+
setInterval(() => {
|
|
67
|
+
c.inc({ code: 200 });
|
|
68
|
+
}, 1000).unref();
|
|
69
|
+
setInterval(() => {
|
|
70
|
+
c.inc({ code: 400 });
|
|
71
|
+
c.inc({ code: 'worker_' + process.pid });
|
|
72
|
+
}, 500).unref();
|
|
73
|
+
expressServer.get('/metrics', async (req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
res.set('Content-Type', prom_client_1.register.contentType);
|
|
76
|
+
res.end(await prom_client_1.register.metrics());
|
|
77
|
+
}
|
|
78
|
+
catch (ex) {
|
|
79
|
+
res.status(500).end(ex);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
expressServer.get('/metrics/counter', async (req, res) => {
|
|
83
|
+
try {
|
|
84
|
+
res.set('Content-Type', prom_client_1.register.contentType);
|
|
85
|
+
res.end(await prom_client_1.register.getSingleMetricAsString('test_counter'));
|
|
86
|
+
}
|
|
87
|
+
catch (ex) {
|
|
88
|
+
res.status(500).end(ex);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
#SetupTLSServer = async (socket) => {
|
|
93
|
+
// Add a 'close' event handler to this instance of socket
|
|
94
|
+
console.log('CONNECTED: ' + socket.remoteAddress + ':' + socket.remotePort + ' ' + process.pid);
|
|
95
|
+
this.#sockets.push(socket);
|
|
96
|
+
const self = this;
|
|
97
|
+
socket.on('close', function (data) {
|
|
98
|
+
const index = self.#sockets.findIndex(function (o) {
|
|
99
|
+
return o.remoteAddress === socket.remoteAddress && o.remotePort === socket.remotePort;
|
|
100
|
+
});
|
|
101
|
+
if (index !== -1)
|
|
102
|
+
self.#sockets.splice(index, 1);
|
|
103
|
+
console.log('CLOSED: ' + socket.remoteAddress + ' ' + socket.remotePort + ' ' + process.pid);
|
|
104
|
+
});
|
|
105
|
+
socket.on('data', function (data) {
|
|
106
|
+
console.log('DATA ' + socket.remoteAddress + ': ' + socket.remotePort + ': ' + data);
|
|
107
|
+
socket.write(socket.remoteAddress + ':' + socket.remotePort + " said " + data + '\n');
|
|
108
|
+
// Write the data back to all the connected, the client will receive it as data from the server
|
|
109
|
+
/*
|
|
110
|
+
self.#sockets.forEach(function(socket, index, array) {
|
|
111
|
+
socket.write(socket.remoteAddress + ':' + socket.remotePort + " said " + data + '\n');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
*/
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
#SetupRPCServer = async (socket) => {
|
|
118
|
+
console.log('CONNECTED: ' + socket.remoteAddress + ':' + socket.remotePort + ' ' + process.pid);
|
|
119
|
+
socket.on('close', function (data) {
|
|
120
|
+
console.log('CLOSED: ' + socket.remoteAddress + ' ' + socket.remotePort + ' ' + process.pid);
|
|
121
|
+
});
|
|
122
|
+
socket.on('data', function (data) {
|
|
123
|
+
console.log('DATA ' + socket.remoteAddress + ': ' + data);
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
#SetupWSSServer = async (clusterMode) => {
|
|
127
|
+
// socket.io
|
|
128
|
+
// WebSocket
|
|
129
|
+
const options = {
|
|
130
|
+
transports: ["websocket"] // or [ "websocket", "polling" ] (to use long-poolling. Note that the order matters)
|
|
131
|
+
// The default path is /socket.io
|
|
132
|
+
// This can be changed with the path option as shown below
|
|
133
|
+
//,path: '/zzz'
|
|
134
|
+
};
|
|
135
|
+
//this.#io = require("socket.io")(this.#httpServer, options);
|
|
136
|
+
this.#io = new socket_io_1.Server(this.#httpServer, options);
|
|
137
|
+
if (clusterMode) {
|
|
138
|
+
if (this.options.useRedisAdaptor) {
|
|
139
|
+
this.LogEx(`Using Redis for socket.io cluster management (worker)`);
|
|
140
|
+
if (this.options.redisAdaptorUrl) {
|
|
141
|
+
this.LogEx(`Redis url: [${this.options.redisAdaptorUrl}]`);
|
|
142
|
+
this.#redisClient = (0, redis_1.createClient)({ url: this.options.redisAdaptorUrl });
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
this.LogEx(`Redis url: [localhost]`);
|
|
146
|
+
this.#redisClient = (0, redis_1.createClient)();
|
|
147
|
+
}
|
|
148
|
+
await this.#redisClient.connect();
|
|
149
|
+
this.#io.adapter((0, redis_streams_adapter_1.createAdapter)(this.#redisClient));
|
|
150
|
+
this.LogEx(`Redis successfully connected.`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.#io.adapter((0, cluster_adapter_1.createAdapter)());
|
|
154
|
+
this.LogEx(`Using nodejs cluster mode for socket.io cluster management`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.LogEx(`Not using any adaptors for socket.io cluster management.}`);
|
|
159
|
+
}
|
|
160
|
+
// To use a seperate socket server, the code below can be applied.
|
|
161
|
+
// this.#io = require("socket.io")(options);
|
|
162
|
+
// this.#io.adapter(createAdapter());
|
|
163
|
+
// this.#io.listen(3006);
|
|
164
|
+
// LogEx(`socket.io init`);
|
|
165
|
+
this.#io.engine.on("connection_error", (err) => {
|
|
166
|
+
this.LogEx(err.req); // the request object
|
|
167
|
+
this.LogEx(err.code); // the error code, for example 1
|
|
168
|
+
this.LogEx(err.message); // the error message, for example "Session ID unknown"
|
|
169
|
+
this.LogEx(err.context); // some additional error context
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
#GetTLSOptions = () => {
|
|
173
|
+
return {
|
|
174
|
+
key: fs_1.default.readFileSync(this.options.httpsServerKeyPath),
|
|
175
|
+
cert: fs_1.default.readFileSync(this.options.httpsServerCertificatePath)
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
#SetupExpressServer = async (useTls) => {
|
|
179
|
+
if (useTls) {
|
|
180
|
+
this.#httpServer = (0, https_1.createServer)(this.#GetTLSOptions(), this.#expressServer.App);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.#httpServer = (0, http_1.createServer)(this.#expressServer.App);
|
|
184
|
+
}
|
|
185
|
+
if (this.options.prometheusSupport === true) {
|
|
186
|
+
this.#SetupPrometheusEndPoints(this.#expressServer.App);
|
|
187
|
+
}
|
|
188
|
+
if (this.options.wssServer === true) {
|
|
189
|
+
await this.#SetupWSSServer(true);
|
|
190
|
+
}
|
|
191
|
+
// https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions
|
|
192
|
+
//@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>
|
|
193
|
+
//@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>
|
|
194
|
+
this.#httpServer.listen(this.options.listenPort, () => {
|
|
195
|
+
//@@chmodSync(this.options.port, 511);
|
|
196
|
+
}).on('listening', () => {
|
|
197
|
+
this.LogEx(`live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
#SetupTCPRawServer = async () => {
|
|
201
|
+
// The second parameter is the automatic listener for the secureConnection event from the tls.Server class
|
|
202
|
+
this.#httpServer = node_tls_1.default.createServer(this.#GetTLSOptions(), this.#SetupTLSServer);
|
|
203
|
+
this.#httpServer.listen(this.options.listenPort, 'stscore.stsmda.org', () => {
|
|
204
|
+
console.log('TCP Server is running on port ' + this.options.listenPort + '.');
|
|
205
|
+
}).on('listening', () => {
|
|
206
|
+
this.LogEx(`TCP live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
#SetupJSONRPCServer = async () => {
|
|
210
|
+
const jaysonServer = new jayson_1.default.server();
|
|
211
|
+
// Supported methods here - move somewhere else ...
|
|
212
|
+
jaysonServer.method("add", function (args, callback) {
|
|
213
|
+
callback(null, args[0] + args[1]);
|
|
214
|
+
});
|
|
215
|
+
this.#httpServer = jaysonServer.tls(this.#GetTLSOptions());
|
|
216
|
+
this.#httpServer.on('secureConnection', this.#SetupRPCServer);
|
|
217
|
+
this.#httpServer.listen(this.options.listenPort, 'stscore.stsmda.org', () => {
|
|
218
|
+
console.log('JSON RPC 2.0 Server is running on port ' + this.options.listenPort + '.');
|
|
219
|
+
}).on('listening', () => {
|
|
220
|
+
this.LogEx(`JSON RPC 2.0 live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
ProcessTerminating = async () => {
|
|
224
|
+
return;
|
|
225
|
+
};
|
|
226
|
+
// Terminate in order;
|
|
227
|
+
// forked worker threads (send signal)
|
|
228
|
+
// De-Register service
|
|
229
|
+
// systeminformation observers
|
|
230
|
+
// instrument timers (gauge etc.)
|
|
231
|
+
// publisher
|
|
232
|
+
// terminate UI (if loaded)
|
|
233
|
+
Terminate = async (clusterMode, clusterPerformExit, signal) => {
|
|
234
|
+
if (this.#shuttingDown === false) {
|
|
235
|
+
this.#shuttingDown = true;
|
|
236
|
+
await this.ProcessTerminate();
|
|
237
|
+
await this.ProcessTerminating();
|
|
238
|
+
if (!clusterMode) {
|
|
239
|
+
if (this.GetUIController() !== null) {
|
|
240
|
+
this.LogEx('Destroy the user interface controller.');
|
|
241
|
+
this.GetUIController().DestroyUI();
|
|
242
|
+
}
|
|
243
|
+
if (signal) {
|
|
244
|
+
this.LogEx(this.GetSignalColour(signal)(`Main Process (singleprocess): ${process.pid} received signal: ${signal}`));
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
this.LogEx(this.GetSignalColour(null)(`Main Process (singleprocess): ${process.pid} received Terminate without signal.`));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (this.options.wssServer === true && this.#io !== null) {
|
|
251
|
+
this.LogEx(`Disconnect Sockets.`);
|
|
252
|
+
if (this.socketIoHelper !== null) {
|
|
253
|
+
this.socketIoHelper.DisconnectSockets();
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
this.#io.disconnectSockets();
|
|
257
|
+
}
|
|
258
|
+
this.socketIoHelper = null;
|
|
259
|
+
this.#io = null;
|
|
260
|
+
// Note that this.#redisClient.disconnect() is not required becuase DisconnectSockets performs this action.
|
|
261
|
+
}
|
|
262
|
+
if (this.#httpServer) {
|
|
263
|
+
if (this.options.serverType === processoptions_1.STSServerType.TCPRAW_TLS) {
|
|
264
|
+
this.#sockets.forEach((socket, index, array) => {
|
|
265
|
+
this.LogEx(`TCP Socket destroy, remote address: [${socket.remoteAddress}], remote port: [${socket.remotePort}]`.yellow);
|
|
266
|
+
socket.destroy();
|
|
267
|
+
//socket.end();
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
this.LogEx(`Closing httpServer.`);
|
|
271
|
+
await this.#httpServer.close();
|
|
272
|
+
}
|
|
273
|
+
if (this.options.useDatabase) {
|
|
274
|
+
this.LogEx(`Ending database connections and pools.`);
|
|
275
|
+
await this.TerminateDatabase();
|
|
276
|
+
//await this.accessLayer.enddatabase();
|
|
277
|
+
}
|
|
278
|
+
if (clusterMode) {
|
|
279
|
+
this.LogEx(`Performing exit value: [${clusterPerformExit}]`);
|
|
280
|
+
if (clusterPerformExit) {
|
|
281
|
+
this.LogEx(`Process will self terminate with process.exit(0).`);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
this.LogEx(`Child process will not self terminate. Terminate will be handled by master process.`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
|
|
288
|
+
this.LogEx(`Ending publisher.`);
|
|
289
|
+
setTimeout(() => {
|
|
290
|
+
if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
|
|
291
|
+
this.InstrumentController.InstrumentTerminate();
|
|
292
|
+
}
|
|
293
|
+
}, 100);
|
|
294
|
+
}
|
|
295
|
+
//@@ always return here appears to always cleanly exit
|
|
296
|
+
// and cleanly exit from socket.io cluster adaptor
|
|
297
|
+
// without return here, socket.io cluster adaptor terminates in an error state
|
|
298
|
+
// as the implementation relies on cluster.on to send messages to worker threads
|
|
299
|
+
// but these have already been closed from the process.exit(0) below.
|
|
300
|
+
await (0, stsutils_1.Sleep)(1000); // Allow socket.io time to clean-up
|
|
301
|
+
if (clusterMode) {
|
|
302
|
+
if (clusterPerformExit) {
|
|
303
|
+
setTimeout(() => {
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}, 0);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
if (this.options.processExitOnTerminate && this.options.processExitOnTerminate === true) {
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
this.LogEx(`Performing process.exit(0).`);
|
|
312
|
+
process.exit(0);
|
|
313
|
+
}, this.#masterProcessExitTime); // Give the workers time to terminate gracefully
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
this.LogEx(`Performing process.exit(0) - Immediate.`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
this.LogEx(`Process already terminating.`);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
SetupSTSServer = async () => {
|
|
325
|
+
switch (this.options.serverType) {
|
|
326
|
+
case processoptions_1.STSServerType.EXPRESS:
|
|
327
|
+
await this.#SetupExpressServer(false);
|
|
328
|
+
break;
|
|
329
|
+
case processoptions_1.STSServerType.EXPRESS_TLS:
|
|
330
|
+
await this.#SetupExpressServer(true);
|
|
331
|
+
break;
|
|
332
|
+
case processoptions_1.STSServerType.TCPRAW_TLS:
|
|
333
|
+
await this.#SetupTCPRawServer();
|
|
334
|
+
break;
|
|
335
|
+
case processoptions_1.STSServerType.JSONRPC2_TLS:
|
|
336
|
+
await this.#SetupJSONRPCServer();
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
exports.ServerProcessBase = ServerProcessBase;
|
|
342
|
+
//# sourceMappingURL=serverprocessbase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverprocessbase.js","sourceRoot":"","sources":["../src/serverprocessbase.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,24 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SingleProcessBase = void 0;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
7
|
const systeminformation_1 = __importDefault(require("systeminformation")); // https://systeminformation.io/
|
|
9
8
|
const os_1 = __importDefault(require("os"));
|
|
10
9
|
const numCPUs = os_1.default.cpus().length;
|
|
11
|
-
const socket_io_1 = require("socket.io");
|
|
12
|
-
const https_1 = require("https");
|
|
13
|
-
const http_1 = require("http");
|
|
14
|
-
const stsutils_1 = require("@nsshunt/stsutils");
|
|
15
|
-
const colors_1 = __importDefault(require("colors"));
|
|
16
10
|
const stsconfig_1 = require("@nsshunt/stsconfig");
|
|
17
11
|
const goptions = (0, stsconfig_1.$Options)();
|
|
18
12
|
const stsinstrumentation_1 = require("@nsshunt/stsinstrumentation");
|
|
19
|
-
const processbase_1 = require("./processbase");
|
|
20
|
-
const network_js_1 = require("./network.js");
|
|
21
13
|
const server_1 = require("./server");
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
class SingleProcessBase extends processbase_1.ProcessBase {
|
|
14
|
+
const serverprocessbase_1 = require("./serverprocessbase");
|
|
15
|
+
class SingleProcessBase extends serverprocessbase_1.ServerProcessBase {
|
|
25
16
|
#masterProcessExitTime = goptions.masterProcessExitTime;
|
|
26
17
|
#io = null;
|
|
27
18
|
#redisClient = null;
|
|
@@ -68,15 +59,6 @@ class SingleProcessBase extends processbase_1.ProcessBase {
|
|
|
68
59
|
ProcessStarted() {
|
|
69
60
|
return null;
|
|
70
61
|
}
|
|
71
|
-
get io() {
|
|
72
|
-
return this.#io;
|
|
73
|
-
}
|
|
74
|
-
ProcessTerminating() {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
get expressServer() {
|
|
78
|
-
return this.#expressServer;
|
|
79
|
-
}
|
|
80
62
|
SetupServer() {
|
|
81
63
|
return new Promise((resolve, reject) => {
|
|
82
64
|
try {
|
|
@@ -96,223 +78,34 @@ class SingleProcessBase extends processbase_1.ProcessBase {
|
|
|
96
78
|
}
|
|
97
79
|
});
|
|
98
80
|
}
|
|
99
|
-
/*
|
|
100
|
-
SetupServer = async () =>
|
|
101
|
-
{
|
|
102
|
-
this.SetupInstrumentation();
|
|
103
|
-
setTimeout(() => {
|
|
104
|
-
this.SetupServerEx();
|
|
105
|
-
}, 100);
|
|
106
|
-
}
|
|
107
|
-
*/
|
|
108
81
|
SetupServerEx = async () => {
|
|
109
82
|
this.ProcessStartup();
|
|
110
83
|
if (this.options.expressServerRouteFactory || this.options.expressServerRouteStaticFactory) {
|
|
111
84
|
this.#expressServer = new server_1.STSExpressServer(this.options, this);
|
|
112
85
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this.instruments[Gauge.LOGGER].consoleLogging = this.options.consoleLogging;
|
|
117
|
-
this.instruments[Gauge.LOGGER].instrumentLogging = this.options.instrumentLogging;
|
|
118
|
-
}
|
|
119
|
-
*/
|
|
120
|
-
LogEx(`Service instance starting. Instance Id: [${this.options.serviceInstanceId}]`);
|
|
121
|
-
LogEx(`Master process:${process.pid} started`);
|
|
122
|
-
const hostaddr = (0, network_js_1.GetFirstNetworkInterface)();
|
|
123
|
-
if (hostaddr !== null) {
|
|
124
|
-
LogEx(`Host Address: ${hostaddr}`);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
LogEx(`Unknown Host Address.`);
|
|
128
|
-
}
|
|
129
|
-
LogEx(`Server starting with ${numCPUs} Cores/Threads`);
|
|
130
|
-
// https://systeminformation.io/
|
|
131
|
-
const valueObject = {
|
|
132
|
-
system: '*',
|
|
133
|
-
osInfo: '*',
|
|
134
|
-
cpu: '*',
|
|
135
|
-
mem: '*'
|
|
136
|
-
};
|
|
137
|
-
const sysinfo = await systeminformation_1.default.get(valueObject);
|
|
138
|
-
const hostname = sysinfo.osInfo.hostname;
|
|
139
|
-
LogEx(`Hostname: ${hostname}`);
|
|
140
|
-
LogEx(`System: ${JSON.stringify(sysinfo.system)}`);
|
|
141
|
-
LogEx(`OS Info: ${JSON.stringify(sysinfo.osInfo)}`);
|
|
142
|
-
LogEx(`CPU: ${JSON.stringify(sysinfo.cpu)}`);
|
|
143
|
-
LogEx(`Memory: ${JSON.stringify(sysinfo.mem)}`);
|
|
144
|
-
const GetSignalColour = (signal) => {
|
|
145
|
-
let msgcolor = null;
|
|
146
|
-
if (signal === 'SIGINT') {
|
|
147
|
-
msgcolor = colors_1.default.yellow;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
msgcolor = colors_1.default.red;
|
|
151
|
-
}
|
|
152
|
-
return msgcolor;
|
|
153
|
-
};
|
|
154
|
-
this.#httpServer = null;
|
|
155
|
-
// Terminate in order;
|
|
156
|
-
// forked worker threads (send signal)
|
|
157
|
-
// De-Register service
|
|
158
|
-
// systeminformation observers
|
|
159
|
-
// instrument timers (gauge etc.)
|
|
160
|
-
// publisher
|
|
161
|
-
// terminate UI (if loaded)
|
|
162
|
-
const Terminate = async (signal) => {
|
|
163
|
-
if (this.#shuttingDown === false) {
|
|
164
|
-
this.#shuttingDown = true;
|
|
165
|
-
await this.ProcessTerminate();
|
|
166
|
-
this.ProcessTerminating();
|
|
167
|
-
if (this.GetUIController() !== null) {
|
|
168
|
-
LogEx('Destroy the user interface controller.');
|
|
169
|
-
this.GetUIController().DestroyUI();
|
|
170
|
-
}
|
|
171
|
-
if (signal) {
|
|
172
|
-
LogEx(GetSignalColour(signal)(`Main Process (singleprocess): ${process.pid} received signal: ${signal}`));
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
LogEx(GetSignalColour(null)(`Main Process (singleprocess): ${process.pid} received Terminate without signal.`));
|
|
176
|
-
}
|
|
177
|
-
LogEx(`De-Registering service.`);
|
|
178
|
-
//@@ De-register here ...
|
|
179
|
-
LogEx(`Stopping instruments.`);
|
|
180
|
-
//@@StopInstruments(this.instruments);
|
|
181
|
-
if (this.options.wssServer === true && this.#io !== null) {
|
|
182
|
-
LogEx(`Disconnect Sockets.`);
|
|
183
|
-
if (this.socketIoHelper !== null) {
|
|
184
|
-
this.socketIoHelper.DisconnectSockets();
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
this.#io.disconnectSockets();
|
|
188
|
-
}
|
|
189
|
-
this.socketIoHelper = null;
|
|
190
|
-
this.#io = null;
|
|
191
|
-
// Note that this.#redisClient.disconnect() is not required becuase DisconnectSockets performs this action.
|
|
192
|
-
}
|
|
193
|
-
if (this.options.httpServer === true) {
|
|
194
|
-
LogEx(`Closing httpServer.`);
|
|
195
|
-
await this.#httpServer.close();
|
|
196
|
-
}
|
|
197
|
-
if (this.options.useDatabase) {
|
|
198
|
-
LogEx(`Ending database connections and pools.`);
|
|
199
|
-
await this.TerminateDatabase();
|
|
200
|
-
//await this.accessLayer.enddatabase();
|
|
201
|
-
}
|
|
202
|
-
// Now allow some time for the workers to die and send any remaining messages ...
|
|
203
|
-
if (this.InstrumentController && this.InstrumentController.Workers.length > 0) {
|
|
204
|
-
LogEx(`Ending publisher.`);
|
|
205
|
-
setTimeout(() => {
|
|
206
|
-
if (this.InstrumentController) {
|
|
207
|
-
this.InstrumentController.InstrumentTerminate();
|
|
208
|
-
}
|
|
209
|
-
}, 100);
|
|
210
|
-
}
|
|
211
|
-
await (0, stsutils_1.Sleep)(1000); // Allow socket.io time to clean-up
|
|
212
|
-
if (this.options.processExitOnTerminate && this.options.processExitOnTerminate === true) {
|
|
213
|
-
setTimeout(() => {
|
|
214
|
-
LogEx(`Performing process.exit(0).`);
|
|
215
|
-
process.exit(0);
|
|
216
|
-
}, this.#masterProcessExitTime); // Give the workers time to terminate gracefully
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
LogEx(`Performing process.exit(0) - Immediate.`);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
LogEx(`Service instance stopped.`);
|
|
223
|
-
};
|
|
224
|
-
this.#Terminate = Terminate;
|
|
86
|
+
this.LogEx(`Service instance starting. Instance Id: [${this.options.serviceInstanceId}]`);
|
|
87
|
+
this.LogEx(`Master process:${process.pid} started`);
|
|
88
|
+
this.LogSystemTelemetry();
|
|
225
89
|
process.on('SIGINT', async () => {
|
|
226
|
-
await Terminate('SIGINT');
|
|
90
|
+
await this.Terminate(false, false, 'SIGINT');
|
|
227
91
|
});
|
|
228
92
|
process.on('SIGTERM', async () => {
|
|
229
|
-
await Terminate('SIGTERM');
|
|
93
|
+
await this.Terminate(false, false, 'SIGTERM');
|
|
230
94
|
});
|
|
231
95
|
process.on('exit', (code) => {
|
|
232
96
|
if (code === 0) {
|
|
233
|
-
LogEx(`Main Process: ${process.pid} terminated gracefully with code: ${code}`.green);
|
|
97
|
+
this.LogEx(`Main Process: ${process.pid} terminated gracefully with code: ${code}`.green);
|
|
234
98
|
}
|
|
235
99
|
else {
|
|
236
|
-
LogEx(`Main Process: ${process.pid} terminated with code: ${code}`.red);
|
|
100
|
+
this.LogEx(`Main Process: ${process.pid} terminated with code: ${code}`.red);
|
|
237
101
|
}
|
|
238
102
|
});
|
|
239
|
-
|
|
240
|
-
if (this.options.httpsServer === true) {
|
|
241
|
-
const options = {
|
|
242
|
-
key: fs_1.default.readFileSync(this.options.httpsServerKeyPath),
|
|
243
|
-
cert: fs_1.default.readFileSync(this.options.httpsServerCertificatePath)
|
|
244
|
-
};
|
|
245
|
-
this.#httpServer = (0, https_1.createServer)(options, this.#expressServer.App);
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
this.#httpServer = (0, http_1.createServer)(this.#expressServer.App);
|
|
249
|
-
}
|
|
250
|
-
//this.#httpServer.maxConnections = 50;
|
|
251
|
-
// Setup the web socket server (using socket.io) if enabled.
|
|
252
|
-
if (this.options.wssServer === true) {
|
|
253
|
-
// socket.io
|
|
254
|
-
// WebSocket
|
|
255
|
-
const options = {
|
|
256
|
-
transports: ["websocket"] // or [ "websocket", "polling" ] (to use long-poolling. Note that the order matters)
|
|
257
|
-
// The default path is /socket.io
|
|
258
|
-
// This can be changed with the path option as shown below
|
|
259
|
-
//,path: '/zzz'
|
|
260
|
-
};
|
|
261
|
-
this.#io = new socket_io_1.Server(this.#httpServer, options);
|
|
262
|
-
if (this.options.useRedisAdaptor) {
|
|
263
|
-
LogEx(`Using Redis for socket.io cluster management (worker)`);
|
|
264
|
-
if (this.options.redisAdaptorUrl) {
|
|
265
|
-
LogEx(`Redis url: [${this.options.redisAdaptorUrl}]`);
|
|
266
|
-
this.#redisClient = (0, redis_1.createClient)({ url: this.options.redisAdaptorUrl });
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
LogEx(`Redis url: [localhost]`);
|
|
270
|
-
this.#redisClient = (0, redis_1.createClient)();
|
|
271
|
-
}
|
|
272
|
-
await this.#redisClient.connect();
|
|
273
|
-
this.#io.adapter((0, redis_streams_adapter_1.createAdapter)(this.#redisClient));
|
|
274
|
-
LogEx(`Redis successfully connected.`);
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
LogEx(`Not using any adaptors for socket.io cluster management.}`);
|
|
278
|
-
}
|
|
279
|
-
// To use a seperate socket server, the code below can be applied.
|
|
280
|
-
// this.#io = require("socket.io")(options);
|
|
281
|
-
// this.#io.listen(3006);
|
|
282
|
-
// LogEx(`socket.io init`);
|
|
283
|
-
this.#io.engine.on("connection_error", (err) => {
|
|
284
|
-
LogEx(err.req); // the request object
|
|
285
|
-
LogEx(err.code); // the error code, for example 1
|
|
286
|
-
LogEx(err.message); // the error message, for example "Session ID unknown"
|
|
287
|
-
LogEx(err.context); // some additional error context
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
try {
|
|
291
|
-
// https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions
|
|
292
|
-
//@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>
|
|
293
|
-
//@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>
|
|
294
|
-
this.#httpServer.listen(this.options.listenPort, () => {
|
|
295
|
-
//@@chmodSync(listenPort, 511);
|
|
296
|
-
}).on('listening', () => {
|
|
297
|
-
LogEx(`live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
console.error(error);
|
|
302
|
-
throw error;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
/*
|
|
306
|
-
if (this.publishBroker !== null) {
|
|
307
|
-
setTimeout(() => {
|
|
308
|
-
this.publishBroker.StartPublish();
|
|
309
|
-
}, 0);
|
|
310
|
-
}
|
|
311
|
-
*/
|
|
103
|
+
await this.SetupSTSServer();
|
|
312
104
|
this.ProcessStarted();
|
|
105
|
+
this.LogEx(`Main process:${process.pid} started`.green);
|
|
313
106
|
};
|
|
314
|
-
async
|
|
315
|
-
await this
|
|
107
|
+
async TerminateApplication() {
|
|
108
|
+
await this.Terminate(false, false, 'SIGINT');
|
|
316
109
|
this.#Terminate = null;
|
|
317
110
|
}
|
|
318
111
|
}
|