@nsshunt/stsappframework 3.1.241 → 3.2.1

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.
Files changed (108) hide show
  1. package/.github/dependabot.yml +13 -0
  2. package/.github/workflows/npm-publish.yml +47 -0
  3. package/.gitignore copy +108 -0
  4. package/build.sh +37 -0
  5. package/dist/index.js +30 -0
  6. package/esbuild.config.js +81 -0
  7. package/eslint.config.mjs +55 -0
  8. package/jest/setEnvVars.js +19 -0
  9. package/keys/server.cert +21 -0
  10. package/keys/server.key +28 -0
  11. package/local-redis-stack.conf +2 -0
  12. package/package.json +10 -23
  13. package/run-grpc-client.sh +2 -0
  14. package/run-grpc-server.sh +2 -0
  15. package/run1.sh +20 -0
  16. package/run2.sh +20 -0
  17. package/run3.sh +20 -0
  18. package/runc1.sh +19 -0
  19. package/runc2.sh +19 -0
  20. package/runkafka.sh +19 -0
  21. package/runkafkaconsume01.sh +21 -0
  22. package/runkafkaconsume02.sh +21 -0
  23. package/runpromise.sh +5 -0
  24. package/runredis.sh +5 -0
  25. package/runredis1.sh +4 -0
  26. package/runredis2.sh +24 -0
  27. package/runredis3.sh +4 -0
  28. package/runtest1.sh +19 -0
  29. package/runtest2.sh +19 -0
  30. package/runtest_ipc_legacy.sh +19 -0
  31. package/runtest_ipcex.sh +19 -0
  32. package/runtest_redis.sh +19 -0
  33. package/runtest_ww.sh +19 -0
  34. package/src/commonTypes.ts +374 -0
  35. package/src/controller/stscontrollerbase.ts +14 -0
  36. package/src/controller/stslatencycontroller.ts +26 -0
  37. package/src/index.ts +13 -0
  38. package/src/logger/stsTransportLoggerWinston.ts +24 -0
  39. package/src/logger/stsTransportWinston.ts +48 -0
  40. package/src/middleware/serverNetworkMiddleware.ts +243 -0
  41. package/src/network.ts +36 -0
  42. package/src/process/masterprocessbase.ts +674 -0
  43. package/src/process/processbase.ts +483 -0
  44. package/src/process/serverprocessbase.ts +455 -0
  45. package/src/process/singleprocessbase.ts +63 -0
  46. package/src/process/workerprocessbase.ts +224 -0
  47. package/src/publishertransports/publishTransportUtils.ts +53 -0
  48. package/src/route/stslatencyroute.ts +15 -0
  49. package/src/route/stsrouterbase.ts +21 -0
  50. package/src/stsexpressserver.ts +137 -0
  51. package/src/validation/errors.ts +6 -0
  52. package/src/vitesttesting/appConfig.ts +111 -0
  53. package/src/vitesttesting/appSingleWSS.ts +142 -0
  54. package/src/vitesttesting/server.ts +17 -0
  55. package/src/vitesttesting/singleservertest.test.ts +352 -0
  56. package/src/vitesttesting/wsevents.ts +44 -0
  57. package/tsconfig.json +42 -0
  58. package/types/commonTypes.d.ts +230 -0
  59. package/types/commonTypes.d.ts.map +1 -0
  60. package/types/controller/stscontrollerbase.d.ts +7 -0
  61. package/types/controller/stscontrollerbase.d.ts.map +1 -0
  62. package/types/controller/stslatencycontroller.d.ts +7 -0
  63. package/types/controller/stslatencycontroller.d.ts.map +1 -0
  64. package/types/index.d.ts +14 -0
  65. package/types/index.d.ts.map +1 -0
  66. package/types/logger/stsTransportLoggerWinston.d.ts +11 -0
  67. package/types/logger/stsTransportLoggerWinston.d.ts.map +1 -0
  68. package/types/logger/stsTransportWinston.d.ts +15 -0
  69. package/types/logger/stsTransportWinston.d.ts.map +1 -0
  70. package/types/middleware/serverNetworkMiddleware.d.ts +33 -0
  71. package/types/middleware/serverNetworkMiddleware.d.ts.map +1 -0
  72. package/types/network.d.ts +4 -0
  73. package/types/network.d.ts.map +1 -0
  74. package/types/process/masterprocessbase.d.ts +27 -0
  75. package/types/process/masterprocessbase.d.ts.map +1 -0
  76. package/types/process/processbase.d.ts +44 -0
  77. package/types/process/processbase.d.ts.map +1 -0
  78. package/types/process/serverprocessbase.d.ts +26 -0
  79. package/types/process/serverprocessbase.d.ts.map +1 -0
  80. package/types/process/singleprocessbase.d.ts +21 -0
  81. package/types/process/singleprocessbase.d.ts.map +1 -0
  82. package/types/process/workerprocessbase.d.ts +35 -0
  83. package/types/process/workerprocessbase.d.ts.map +1 -0
  84. package/types/publishertransports/publishTransportUtils.d.ts +5 -0
  85. package/types/publishertransports/publishTransportUtils.d.ts.map +1 -0
  86. package/types/route/stslatencyroute.d.ts +6 -0
  87. package/types/route/stslatencyroute.d.ts.map +1 -0
  88. package/types/route/stsrouterbase.d.ts +9 -0
  89. package/types/route/stsrouterbase.d.ts.map +1 -0
  90. package/types/stsexpressserver.d.ts +8 -0
  91. package/types/stsexpressserver.d.ts.map +1 -0
  92. package/types/validation/errors.d.ts +7 -0
  93. package/types/validation/errors.d.ts.map +1 -0
  94. package/types/vitesttesting/appConfig.d.ts +3 -0
  95. package/types/vitesttesting/appConfig.d.ts.map +1 -0
  96. package/types/vitesttesting/appSingleWSS.d.ts +7 -0
  97. package/types/vitesttesting/appSingleWSS.d.ts.map +1 -0
  98. package/types/vitesttesting/server.d.ts +6 -0
  99. package/types/vitesttesting/server.d.ts.map +1 -0
  100. package/types/vitesttesting/singleservertest.test.d.ts +2 -0
  101. package/types/vitesttesting/singleservertest.test.d.ts.map +1 -0
  102. package/types/vitesttesting/wsevents.d.ts +29 -0
  103. package/types/vitesttesting/wsevents.d.ts.map +1 -0
  104. package/vite.config.ts +19 -0
  105. package/dist/stsappframework.mjs +0 -156498
  106. package/dist/stsappframework.mjs.map +0 -7
  107. package/dist/stsappframework.umd.js +0 -156516
  108. package/dist/stsappframework.umd.js.map +0 -7
@@ -0,0 +1,224 @@
1
+ /* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF
2
+ import chalk from 'chalk';
3
+
4
+ import { Gauge, InstrumentGaugeTelemetry } from '@nsshunt/stsobservability'
5
+ import { JSONObject } from '@nsshunt/stsutils'
6
+ import { IPCMessage, IPCMessages, IPCMessagePayload, IPCMessageCommand, IWorkerProcessBase, ProcessOptions } from './../commonTypes'
7
+ import { ServerProcessBase } from './serverprocessbase'
8
+
9
+ import { v4 as uuidv4 } from 'uuid';
10
+
11
+ import { goptions } from '@nsshunt/stsconfig'
12
+
13
+ import si from 'systeminformation' // https://systeminformation.io/
14
+ import { GetFirstNetworkInterface } from './../network'
15
+
16
+ /**
17
+ * todo
18
+ * @typedef {Object} options - todo
19
+ * @property {boolean} [wssServer=false] - Create a web socket server on this worker instance
20
+ */
21
+ export class WorkerProcessBase extends ServerProcessBase implements IWorkerProcessBase {
22
+ #inFlightMessage: IPCMessages = { }
23
+ #requestResponseMessageTimeout = 5000; //@@ config
24
+ #pingTimeout: NodeJS.Timeout | null = null;
25
+
26
+ constructor(options: ProcessOptions) {
27
+ super(options);
28
+ }
29
+
30
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
+ ReceivedMessageFromMaster(msg: any) {
32
+ // Override in subclass if required
33
+ }
34
+
35
+ override CollectAdditionalTelemetry(): void {
36
+ this.httpServer.getConnections((error: any, count: any) => {
37
+ //@@this.instruments[Gauge.CONNECTION_COUNT_GAUGE].val = count;
38
+ this.UpdateInstrument(Gauge.CONNECTION_COUNT_GAUGE, {
39
+ val: count
40
+ } as InstrumentGaugeTelemetry);
41
+ });
42
+ }
43
+
44
+ #SendMessageToParentProcess = (message: IPCMessagePayload): Promise<JSONObject> => {
45
+ return new Promise((resolve, reject) => {
46
+ if (this.#inFlightMessage[message.id]) {
47
+ reject(`Message with id: [${message.id}] already exists within the Request/Response record structure`);
48
+ } else {
49
+ this.#inFlightMessage[message.id] = {
50
+ iPCMessagePayload: { ...message },
51
+ cb: () => {
52
+ const detail: JSONObject = this.#inFlightMessage[message.id].iPCMessagePayload.responseDetail as JSONObject
53
+ clearTimeout(this.#inFlightMessage[message.id].timeout);
54
+ setTimeout(() => {
55
+ delete this.#inFlightMessage[message.id];
56
+ }, 0).unref();
57
+ //this.#LogDebugMessage(chalk.green(`Resolving response message with id: [${message.id}] from parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));
58
+ resolve(detail);
59
+ },
60
+ timeout: setTimeout(() => {
61
+ setTimeout(() => {
62
+ delete this.#inFlightMessage[message.id];
63
+ }, 0).unref();
64
+ //this.#LogDebugMessage(chalk.red(`Timeout has occurred after: [${this.#requestResponseMessageTimeout}]ms with message id: [${message.id}]. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));
65
+ reject('Did not receive response form parent process.');
66
+ }, this.#requestResponseMessageTimeout) // max message timeout allowed
67
+ };
68
+ //this.#LogDebugMessage(chalk.yellow(`Sending message with id: [${message.id}] to parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));
69
+ (process as any).send(message);
70
+ }
71
+ });
72
+ }
73
+
74
+
75
+ AddWorker = async (options: any): Promise<string> => {
76
+ const workerResponse: JSONObject = await this.#SendMessageToParentProcess({
77
+ requestResponse: true,
78
+ id: uuidv4(),
79
+ command: IPCMessageCommand.AddWorker,
80
+ requestDetail: {
81
+ options
82
+ }
83
+ });
84
+ return workerResponse.workerId;
85
+ }
86
+
87
+ DeleteWorker = async (workerId: string, options: any): Promise<JSONObject> => {
88
+ const workerResponse: JSONObject = await this.#SendMessageToParentProcess({
89
+ requestResponse: true,
90
+ id: uuidv4(),
91
+ command: IPCMessageCommand.DeleteWorker,
92
+ requestDetail: {
93
+ options,
94
+ workerId
95
+ }
96
+ });
97
+ return workerResponse;
98
+ }
99
+
100
+ GetMasterProcessOptions = async (): Promise<JSONObject> => {
101
+ const parentResponse: JSONObject = await this.#SendMessageToParentProcess({
102
+ requestResponse: true,
103
+ id: uuidv4(),
104
+ command: IPCMessageCommand.GetConfig,
105
+ requestDetail: { }
106
+ });
107
+ return parentResponse;
108
+ }
109
+
110
+ GetNumCPUs = async (): Promise<number> => {
111
+ // https://systeminformation.io/
112
+ const valueObject = {
113
+ cpu: '*'
114
+ }
115
+
116
+ const sysinfo = await si.get(valueObject);
117
+ let numCPUs = 2;
118
+ if (goptions.useCPUs > 0) {
119
+ if (goptions.useCPUs >= 1) {
120
+ numCPUs = goptions.useCPUs;
121
+ } else {
122
+ numCPUs = Math.round(sysinfo.cpu.cores * goptions.useCPUs);
123
+ }
124
+ } else {
125
+ numCPUs = sysinfo.cpu.physicalCores;
126
+ }
127
+ return numCPUs;
128
+ }
129
+
130
+ GetSystemTelemetry = async () => {
131
+ // https://systeminformation.io/
132
+ const valueObject = {
133
+ system: '*',
134
+ osInfo: '*',
135
+ cpu: '*',
136
+ mem: '*',
137
+ dockerInfo: '*',
138
+ //dockerImages: '*',
139
+ dockerContainers: '*',
140
+ }
141
+
142
+ const sysinfo = await si.get(valueObject);
143
+ const numCPUs = await this.GetNumCPUs();
144
+ const hostname = sysinfo.osInfo.hostname;
145
+ const hostaddr = GetFirstNetworkInterface();
146
+
147
+ const promArray: Promise<any>[] = [ ];
148
+
149
+ sysinfo.dockerContainers.forEach((dc: { id: string; }) => {
150
+ const dcs = promArray.push(si.dockerContainerStats(dc.id));
151
+ console.log(dcs);
152
+ });
153
+ const dockerContainerStats = await Promise.all(promArray);
154
+
155
+ const sysInfo = {
156
+ serviceInstanceId: this.options.serviceInstanceId,
157
+ serviceProcessContext: this.options.serviceProcessContext,
158
+ hostname,
159
+ numCPUs,
160
+ hostaddr,
161
+ system: sysinfo.system,
162
+ osInfo: sysinfo.osInfo,
163
+ cpu: sysinfo.cpu,
164
+ mem: sysinfo.mem,
165
+ dockerInfo: sysinfo.dockerInfo,
166
+ dockerContainers: sysinfo.dockerContainers,
167
+ dockerContainerStats
168
+ }
169
+
170
+ return sysInfo;
171
+ }
172
+
173
+ override SetupServerEx = async (): Promise<boolean> => {
174
+ await super.SetupServerEx();
175
+
176
+ process.on('message', async (msg: any) => {
177
+ if (msg.requestResponse) {
178
+ const iPCMessagePayload: IPCMessagePayload = msg as IPCMessagePayload;
179
+ if (iPCMessagePayload.id) {
180
+ if (this.#inFlightMessage[iPCMessagePayload.id]) {
181
+ const responseMessage: IPCMessage = this.#inFlightMessage[iPCMessagePayload.id];
182
+ responseMessage.iPCMessagePayload.responseDetail = { ...iPCMessagePayload.responseDetail }
183
+ responseMessage.cb();
184
+ } else {
185
+ throw new Error(`Could not find Request/Response message with id: [${iPCMessagePayload.id}]`);
186
+ }
187
+ } else {
188
+ throw new Error(`Message does not have id attribute. [${JSON.stringify(iPCMessagePayload)}]`);
189
+ }
190
+ return;
191
+ }
192
+ if (msg.command) //@@ constants
193
+ {
194
+ switch (msg.command)
195
+ {
196
+ case 'Terminate' :
197
+ this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Terminate`) + ` message from master thread`));
198
+ await this.Terminate(true, false); // Don't kill the child process here, the master will take care of that ...
199
+ break;
200
+ case 'TerminateAndKill' :
201
+ this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Terminate`) + ` message from master thread`));
202
+ await this.Terminate(true, true);
203
+ break;
204
+ case 'Message' :
205
+ //this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Message`) + ` message from master thread`));
206
+ this.ReceivedMessageFromMaster(msg.data);
207
+ break;
208
+ case 'Response' : // General response to a req/response interaction
209
+ //msg.details
210
+ }
211
+ }
212
+ });
213
+
214
+ return true;
215
+ };
216
+
217
+ override ProcessTerminate(): Promise<void> {
218
+ //this.#redisMessageHandler?.off()
219
+ if (this.#pingTimeout) {
220
+ clearTimeout(this.#pingTimeout);
221
+ }
222
+ return super.ProcessTerminate();
223
+ }
224
+ }
@@ -0,0 +1,53 @@
1
+ import { ModelDelimeter } from '@nsshunt/stsutils'
2
+ import { IServiceProcessContext } from './../commonTypes'
3
+
4
+ export class PublishTransportUtils
5
+ {
6
+ static GetServiceContext(nid: string): IServiceProcessContext {
7
+ // Return null if no context is required
8
+ //return null;
9
+ if (nid === ModelDelimeter.ROOT) {
10
+ return { root: ModelDelimeter.ROOT };
11
+ }
12
+ const context: IServiceProcessContext = { nid };
13
+ const idsplit = nid.split(ModelDelimeter.SEPERATOR);
14
+
15
+ const serviceId = idsplit[0];
16
+ const serviceInstanceId = idsplit[1].split(ModelDelimeter.NID_SEPERATOR)[0];
17
+ const serviceInstanceProcessId = idsplit[1].split(ModelDelimeter.NID_SEPERATOR)[1];
18
+
19
+ const serviceIdSplit = serviceId.split(ModelDelimeter.COMPONENT_SEPERATOR);
20
+ const serviceName =serviceIdSplit[0]; // Defined in .env or environment variable
21
+ const serviceVersion = serviceIdSplit[1]; // Defined in .env or environment variable
22
+
23
+ context.serviceId = serviceId; // Service name and the service version
24
+
25
+ if (typeof serviceInstanceId != 'undefined') {
26
+ const serviceInstanceIdSplit = serviceInstanceId.split(ModelDelimeter.COMPONENT_SEPERATOR);
27
+ const sid = serviceInstanceIdSplit[0];
28
+ const hostName = serviceInstanceIdSplit[1];
29
+
30
+ context.serviceInstanceId = serviceInstanceId; // Service unique id and the host name
31
+ context.sid = sid; // Service unique id only, does not include host
32
+ context.hostName = hostName; // Service Instance Host Name
33
+
34
+ if (typeof serviceInstanceProcessId != 'undefined') {
35
+ const serviceInstanceProcessIdSplit = serviceInstanceProcessId.split(ModelDelimeter.COMPONENT_SEPERATOR);
36
+ const pid = parseInt(serviceInstanceProcessIdSplit[0]);
37
+ const ppid = parseInt(serviceInstanceProcessIdSplit[1]);
38
+ const isMaster = (pid === ppid ? true : false);
39
+
40
+ context.serviceInstanceProcessId = serviceInstanceProcessId; // Service Instance OS Process ID (parent process id)
41
+ context.pid = pid; // Service Instance OS Process ID (parent process id)
42
+ context.ppid = ppid; // Service Instance OS Parent Process ID if worker. Will be pid if parent process.
43
+ context.isMaster = isMaster; // True if is Master Process
44
+ context.isWorker = !isMaster; // True if is Worker Process
45
+ context.serviceName = serviceName; // Defined in .env or environment variable
46
+ context.serviceVersion = serviceVersion; // Defined in .env or environment variable
47
+ context.serviceInstanceId = serviceInstanceId; // unique service id with host
48
+ }
49
+ }
50
+
51
+ return context;
52
+ }
53
+ }
@@ -0,0 +1,15 @@
1
+ import { STSRouterBase } from './stsrouterbase'
2
+ import { STSLatencyController } from './../controller/stslatencycontroller'
3
+ import { IProcessBase } from './../commonTypes'
4
+
5
+ export class STSLatencyRoute extends STSRouterBase {
6
+ constructor(stsApp: IProcessBase)
7
+ {
8
+ super(stsApp);
9
+
10
+ const latencyController = new STSLatencyController(stsApp);
11
+ const { stslatency } = latencyController;
12
+
13
+ this.router.get('/latency', stslatency.bind(latencyController)); // Create new test
14
+ }
15
+ }
@@ -0,0 +1,21 @@
1
+ /* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF
2
+ import { Router } from 'express';
3
+ import { IProcessBase } from './../commonTypes';
4
+
5
+ export abstract class STSRouterBase {
6
+ #router: Router;
7
+ #stsApp: any;
8
+
9
+ constructor(stsApp: IProcessBase) {
10
+ this.#stsApp = stsApp;
11
+ this.#router = Router();
12
+ }
13
+
14
+ get router(): Router {
15
+ return this.#router;
16
+ }
17
+
18
+ get stsApp(): IProcessBase {
19
+ return this.#stsApp
20
+ }
21
+ }
@@ -0,0 +1,137 @@
1
+ /* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF
2
+ import express, { Express, Request, Response, NextFunction } from 'express';
3
+
4
+ import cors from 'cors';
5
+ import cookieParser from 'cookie-parser';
6
+
7
+ import { RequestLoggerMiddleware, RequestLoggerMiddlewareEventName } from '@nsshunt/stsobservability'
8
+
9
+ import { goptions } from '@nsshunt/stsconfig'
10
+
11
+ import { IProcessBase, ProcessOptions } from './commonTypes'
12
+ import { Gauge, InstrumentGaugeTelemetry, InstrumentHistogramTelemetry, InstrumentVelocityTelemetry } from '@nsshunt/stsobservability'
13
+
14
+ import { ISocketRecord, ServerNetworkMiddleware, ServerNetworkMiddlewareEventName } from './middleware/serverNetworkMiddleware'
15
+
16
+ export class STSExpressServer {
17
+ #app: Express;
18
+
19
+ constructor(options: ProcessOptions, stsApp: IProcessBase)
20
+ {
21
+ // Standard RequestLoggerMiddleware for all STS services
22
+ const requestLoggerMiddleware = new RequestLoggerMiddleware({
23
+ ignoresocketio: goptions.ignoresocketio
24
+ });
25
+
26
+ const serverNetworkMiddleware = new ServerNetworkMiddleware({
27
+ name: (stsApp.options as ProcessOptions).serviceName,
28
+ outputDebug: false,
29
+ logger: stsApp.options?.logger
30
+ });
31
+
32
+ serverNetworkMiddleware.on(ServerNetworkMiddlewareEventName.UpdateInstrument_SERVER_NET_VAL, (data: ISocketRecord) => {
33
+ //this.#LogInfoMessage(chalk.magenta(`serverNetworkMiddleware: [${JSON.stringify(data)}]`));
34
+ stsApp.UpdateInstrument(Gauge.NETWORK_RX_GAUGE, {
35
+ Inc: data.requestBytesRead
36
+ } as InstrumentGaugeTelemetry);
37
+
38
+ stsApp.UpdateInstrument(Gauge.NETWORK_TX_GAUGE, {
39
+ Inc: data.requestBytesWritten
40
+ } as InstrumentGaugeTelemetry);
41
+ });
42
+
43
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_AR_INC, () => {
44
+ stsApp.UpdateInstrument(Gauge.ACTIVE_REQUEST_GAUGE, {
45
+ Inc: 1
46
+ } as InstrumentGaugeTelemetry);
47
+ });
48
+
49
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_AR_DEC, () => {
50
+ stsApp.UpdateInstrument(Gauge.ACTIVE_REQUEST_GAUGE, {
51
+ Dec: 1
52
+ } as InstrumentGaugeTelemetry);
53
+ });
54
+
55
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_DH_VAL, (timeInMs) => {
56
+ stsApp.UpdateInstrument(Gauge.DURATION_HISTOGRAM_GAUGE, {
57
+ val: timeInMs
58
+ } as InstrumentHistogramTelemetry);
59
+ });
60
+
61
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_D_VAL, (timeInMs) => {
62
+ stsApp.UpdateInstrument(Gauge.DURATION_GAUGE, {
63
+ val: timeInMs
64
+ } as InstrumentHistogramTelemetry);
65
+ });
66
+
67
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_RC_INC, () => {
68
+ stsApp.UpdateInstrument(Gauge.REQUEST_COUNT_GAUGE, {
69
+ Inc: 1
70
+ } as InstrumentGaugeTelemetry);
71
+ });
72
+
73
+ requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_V_INC, () => {
74
+ if (stsApp.InstrumentExists(Gauge.VELOCITY_GAUGE)) {
75
+ stsApp.UpdateInstrument(Gauge.VELOCITY_GAUGE, {
76
+ Inc: 1
77
+ } as InstrumentVelocityTelemetry);
78
+ }
79
+ });
80
+
81
+ const app = express();
82
+ this.#app = app;
83
+
84
+ // https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i
85
+ // See answer from Christoph Hansen is thread above ...
86
+ // https://expressjs.com/en/resources/middleware/cors.html
87
+ const corsConfig = {
88
+ credentials: true,
89
+ origin: true,
90
+ };
91
+
92
+ app.use(cors(corsConfig));
93
+
94
+ app.use(cookieParser())
95
+
96
+ app.use(express.urlencoded({ extended: false, limit: goptions.maxPayloadSize }));
97
+
98
+ app.use(express.json({limit: goptions.maxPayloadSize}));
99
+
100
+ // Allow the static SPA to also be servered by this app
101
+ //app.use('/static', express.static(path.join(__dirname, 'public')))
102
+ if (options.expressServerRouteStaticFactory) {
103
+ options.expressServerRouteStaticFactory(app, stsApp);
104
+ }
105
+
106
+ app.use(requestLoggerMiddleware.Middleware.bind(requestLoggerMiddleware));
107
+
108
+ app.use(serverNetworkMiddleware.Middleware.bind(serverNetworkMiddleware));
109
+
110
+ if (options.expressServerRouteFactory) {
111
+ options.expressServerRouteFactory(app, stsApp);
112
+ }
113
+
114
+ // Express error handling fall-back
115
+ app.use(function(err: any, req: Request, res: Response, next: NextFunction) {
116
+ //@@ add to errors metric here - perhaps break down by type
117
+
118
+ if (err) {
119
+ //@@this.#LogInfoMessage(err);
120
+ res.status(err.status).send(err);
121
+ } else {
122
+ next();
123
+ }
124
+ /*
125
+ if(err.name === 'UnauthorizedError') {
126
+ res.status(401).send(err);
127
+ } else {
128
+ next();
129
+ }
130
+ */
131
+ });
132
+ }
133
+
134
+ get App(): Express {
135
+ return this.#app;
136
+ }
137
+ }
@@ -0,0 +1,6 @@
1
+ export const AppFrameworkErrorCode = Object.freeze({
2
+ APPFRAMEWORK_MISSING_PERMISSION: {
3
+ code: 'STS_AF_0001',
4
+ description: 'STS_AF_0001: Missing Permission(s).'
5
+ },
6
+ });
@@ -0,0 +1,111 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import express from 'express';
3
+
4
+ import { goptions } from '@nsshunt/stsconfig'
5
+
6
+ import { ProcessOptions, IProcessBase } from './..'
7
+
8
+ import { STSExpressRouteFactory } from './server'
9
+
10
+ import winston from 'winston'
11
+
12
+ /*
13
+ // nid: `${goptions.rest01servicename} @ ${goptions.rest01serviceversion} | ${this.options.globalServiceData.serviceInstanceId} @ ${os.hostname()} ^ ${process.pid} @ ${(cluster.isMaster ? process.pid : process.ppid)}`,
14
+ // <serviceId> <serviceInstanceId> <serviceInstanceProcessId>
15
+ // <serviceName> <serviceVersion> <sid> <hostName> <pid> <ppid>
16
+ // << ............... Static Nid ............... >> << ............... Dynamic Nid ............... >>
17
+ // Note: The final nid will NOT contain the NID_SEPERATOR character. This will be replaced with the SEPERATOR character.
18
+ const Context = (isMaster, serviceInstanceId) => {
19
+ return {
20
+ nid: `\
21
+ ${goptions.rest01servicename}${ModelDelimeter.COMPONENT_SEPERATOR}${goptions.rest01serviceversion}\
22
+ ${ModelDelimeter.SEPERATOR}\
23
+ ${serviceInstanceId}${ModelDelimeter.COMPONENT_SEPERATOR}${os.hostname()}\
24
+ ${ModelDelimeter.NID_SEPERATOR}\
25
+ ${process.pid}${ModelDelimeter.COMPONENT_SEPERATOR}${(isMaster ? process.pid : process.ppid)}`
26
+ }
27
+ }
28
+ */
29
+
30
+ export function ServiceConfigOptions(clusterMode: boolean, isMaster: boolean): ProcessOptions {
31
+ winston.format.combine(
32
+ winston.format.colorize(),
33
+ winston.format.simple()
34
+ );
35
+
36
+ const logger = winston.createLogger({
37
+ level: 'debug',
38
+ format: winston.format.combine(
39
+ winston.format.colorize(),
40
+ winston.format.simple()
41
+ ),
42
+ transports: [
43
+ new winston.transports.Console()
44
+ ]
45
+ });
46
+
47
+ const publisherLogger = winston.createLogger({
48
+ level: 'info',
49
+ format: winston.format.combine(
50
+ winston.format.colorize(),
51
+ winston.format.simple()
52
+ ),
53
+ transports: [
54
+ new winston.transports.Console()
55
+ ]
56
+ });
57
+
58
+ if (isMaster === true) {
59
+ const serviceInstanceId = uuidv4();
60
+ const data: ProcessOptions = {
61
+ clusterMode: clusterMode,
62
+ wssServer: true,
63
+ useLatency: true,
64
+ httpsServerKeyPath: goptions.httpsserverkeypath,
65
+ httpsServerCertificatePath: goptions.httpsservercertpath,
66
+ processExitOnTerminate: true,
67
+ serviceInstanceId: serviceInstanceId,
68
+ useDatabase: false,
69
+
70
+ isMaster: isMaster,
71
+ endpoint: goptions.rest01endpoint,
72
+ apiRoot: goptions.rest01apiroot,
73
+ listenPort: goptions.rest01hostport,
74
+ port: goptions.rest01port,
75
+ prometheusSupport: goptions.rest01prometheussupport,
76
+ prometheusClusterPort: goptions.rest01prometheusclusterport,
77
+ serviceName: goptions.rest01servicename,
78
+ serviceVersion: goptions.rest01serviceversion,
79
+ consoleLogging: false, //@@
80
+ instrumentLogging: true,
81
+
82
+ instrumentationObservationInterval: goptions.instrumentationObservationInterval,
83
+ instrumentationTimeWindow: goptions.instrumentationTimeWindow,
84
+
85
+ useSocketIoRedisAdaptor: true,
86
+ socketIoRedisAdaptorUrl: goptions.socketIoRedisAdaptorUrl,
87
+ //socketIoRedisAdaptorUrl: 'redis://192.168.50.5:6379',
88
+ //workerExec: './dist/testing/app.js',
89
+
90
+ logger: logger,
91
+ publisherLogger: publisherLogger,
92
+ publishInterval: goptions.publishinterval
93
+ }
94
+
95
+ if (!clusterMode) {
96
+ data.expressServerRouteFactory = (app: express.Express, stsApp: IProcessBase) => {
97
+ return new STSExpressRouteFactory(app, stsApp);
98
+ }
99
+ }
100
+
101
+ return data;
102
+ } else {
103
+ const data: ProcessOptions = JSON.parse(process.env['STS_GSD_SII'] as string) as ProcessOptions;
104
+ data.expressServerRouteFactory = (app: express.Express, stsApp: IProcessBase) => {
105
+ return new STSExpressRouteFactory(app, stsApp);
106
+ }
107
+ data.logger = logger;
108
+ data.publisherLogger = publisherLogger;
109
+ return data;
110
+ }
111
+ }