@nsshunt/stsappframework 3.1.235 → 3.1.237

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 (61) hide show
  1. package/dist/stsappframework.mjs +1979 -0
  2. package/dist/stsappframework.mjs.map +1 -0
  3. package/dist/stsappframework.umd.js +1954 -0
  4. package/dist/stsappframework.umd.js.map +1 -0
  5. package/package.json +21 -7
  6. package/.github/dependabot.yml +0 -13
  7. package/.github/workflows/npm-publish.yml +0 -46
  8. package/.gitignore copy +0 -108
  9. package/build.sh +0 -36
  10. package/dist/index.js +0 -30
  11. package/eslint.config.mjs +0 -55
  12. package/jest/setEnvVars.js +0 -19
  13. package/keys/server.cert +0 -21
  14. package/keys/server.key +0 -28
  15. package/local-redis-stack.conf +0 -2
  16. package/run-grpc-client.sh +0 -2
  17. package/run-grpc-server.sh +0 -2
  18. package/run1.sh +0 -20
  19. package/run2.sh +0 -20
  20. package/run3.sh +0 -20
  21. package/runc1.sh +0 -19
  22. package/runc2.sh +0 -19
  23. package/runkafka.sh +0 -19
  24. package/runkafkaconsume01.sh +0 -21
  25. package/runkafkaconsume02.sh +0 -21
  26. package/runpromise.sh +0 -5
  27. package/runredis.sh +0 -5
  28. package/runredis1.sh +0 -4
  29. package/runredis2.sh +0 -24
  30. package/runredis3.sh +0 -4
  31. package/runtest1.sh +0 -19
  32. package/runtest2.sh +0 -19
  33. package/runtest_ipc_legacy.sh +0 -19
  34. package/runtest_ipcex.sh +0 -19
  35. package/runtest_redis.sh +0 -19
  36. package/runtest_ww.sh +0 -19
  37. package/src/commonTypes.ts +0 -374
  38. package/src/controller/stscontrollerbase.ts +0 -14
  39. package/src/controller/stslatencycontroller.ts +0 -26
  40. package/src/index.ts +0 -13
  41. package/src/logger/stsTransportLoggerWinston.ts +0 -24
  42. package/src/logger/stsTransportWinston.ts +0 -48
  43. package/src/middleware/serverNetworkMiddleware.ts +0 -243
  44. package/src/network.ts +0 -36
  45. package/src/process/masterprocessbase.ts +0 -674
  46. package/src/process/processbase.ts +0 -483
  47. package/src/process/serverprocessbase.ts +0 -455
  48. package/src/process/singleprocessbase.ts +0 -63
  49. package/src/process/workerprocessbase.ts +0 -224
  50. package/src/publishertransports/publishTransportUtils.ts +0 -53
  51. package/src/route/stslatencyroute.ts +0 -15
  52. package/src/route/stsrouterbase.ts +0 -21
  53. package/src/stsexpressserver.ts +0 -137
  54. package/src/validation/errors.ts +0 -6
  55. package/src/vitesttesting/appConfig.ts +0 -111
  56. package/src/vitesttesting/appSingleWSS.ts +0 -142
  57. package/src/vitesttesting/server.ts +0 -17
  58. package/src/vitesttesting/singleservertest.test.ts +0 -352
  59. package/src/vitesttesting/wsevents.ts +0 -44
  60. package/tsconfig.json +0 -42
  61. package/vite.config.ts +0 -19
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stsappframework.mjs","sources":["../src/commonTypes.ts","../src/network.ts","../src/process/processbase.ts","../src/logger/stsTransportLoggerWinston.ts","../src/process/masterprocessbase.ts","../src/middleware/serverNetworkMiddleware.ts","../src/stsexpressserver.ts","../src/process/serverprocessbase.ts","../src/process/singleprocessbase.ts","../src/process/workerprocessbase.ts","../src/controller/stscontrollerbase.ts","../src/controller/stslatencycontroller.ts","../src/route/stsrouterbase.ts","../src/route/stslatencyroute.ts","../src/publishertransports/publishTransportUtils.ts","../src/logger/stsTransportWinston.ts"],"sourcesContent":["/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport express from 'express'\n\nimport { JSONObject, ISTSLogger, ModelDelimeter, CheckValidChar } from \"@nsshunt/stsutils\"\nimport { PublishInstrumentController, InstrumentDefinitions, \n IContextBase, InstrumentBaseTelemetry, Gauge} from '@nsshunt/stsobservability'\n\nimport { STSDefaultClientToServerEvents, STSDefaultServerToClientEvents } from '@nsshunt/stssocketioutils'\n\nimport { IDBAccessLayer } from '@nsshunt/stsdatamanagement'\nimport { TinyEmitter } from \"tiny-emitter\";\n\nimport { Worker, Address } from 'node:cluster'\n\nimport { ISocketIoServerHelper } from '@nsshunt/stssocketioutils'\n\nexport interface IServiceProcessContext extends IContextBase {\n\tserviceId?: string // Service name and the service version\n\n\tserviceInstanceId?: string // Service unique id and the host name\n\tsid?: string // Service unique id only, does not include host\n\thostName?: string // Service Instance Host Name\n\n\t// Leaf level attributes\n\tserviceInstanceProcessId?: string // Service Instance OS Process ID (parent process id)\n\tpid?: number // Service Instance OS Process ID (parent process id)\n\tppid?: number// Service Instance OS Parent Process ID if worker. Will be pid if parent process.\n\tisMaster?: boolean // True if is Master Process\n\tisWorker?: boolean // True if is Worker Process\n\tserviceName?: string // Defined in .env or environment variable\n\tserviceVersion?: string // Defined in .env or environment variable\n}\n\nexport function CreateServiceProcessContext(serviceName: string, serviceVersion: string, serviceInstanceId: string,\n hostName: string, processId: number, parentProcessId: number): IServiceProcessContext {\n\n const checkParams = [\n [ 'servicename', serviceName ], \n [ 'serviceversion', serviceVersion ],\n [ 'hostname', hostName ],\n [ 'serviceInstanceId', serviceInstanceId ]\n ];\n \n // CHeck for invalid strings\n CheckValidChar(checkParams);\n \n return {\n nid: `\\\n${serviceName}${ModelDelimeter.COMPONENT_SEPERATOR}${serviceVersion}\\\n${ModelDelimeter.SEPERATOR}\\\n${serviceInstanceId}${ModelDelimeter.COMPONENT_SEPERATOR}${hostName}\\\n${ModelDelimeter.NID_SEPERATOR}\\\n${processId.toString()}${ModelDelimeter.COMPONENT_SEPERATOR}${parentProcessId.toString()}`,\n serviceName,\n serviceVersion,\n serviceInstanceId,\n hostName,\n processId: processId.toString(),\n parentProcessId: parentProcessId.toString()\n }\n}\n\nexport enum IPCMessageCommand {\n AddWorker = 'AddWorker',\n DeleteWorker = 'DeleteWorker',\n GetConfig = 'GetConfig'\n}\n\nexport interface IPCMessagePayload {\n\trequestResponse: boolean,\n\tid: string,\n command: IPCMessageCommand,\n\trequestDetail?: JSONObject,\n responseDetail?: JSONObject\n}\n\nexport interface IPCMessage {\n\tiPCMessagePayload: IPCMessagePayload\n\tcb: () => void,\n\ttimeout: NodeJS.Timeout\n}\n\nexport type IPCMessages = Record<string, IPCMessage>\n\n//------------------------------------\n\nexport interface IProcessBaseEvents {\n 'processSigint': []\n 'processSigterm': []\n 'processExit': [ workerid: number ]\n\n 'ProcessTerminate': []\n\n 'clusterListening': [ worker: Worker, address: Address ];\n 'clusterOnline': [ worker: Worker ]\n 'clusterExit': [ worker: Worker, code: number, signal: string ]\n 'allListening': []\n\n 'workerMessage': [ id: number, payload: any ]\n 'workerError': [ error: Error ]\n 'workerAdded': [ id: number ]\n 'workerExit': [ code: number, signal: string ]\n\n 'prometheusScrapesListening': [ url: string, endpoint: string, prometheusClusterPort: string ]\n}\n\nexport interface IProcessBase extends TinyEmitter {\n SetupInstrumentation(): void\n GetAdditionalInstruments(): InstrumentDefinitions\n CollectAdditionalTelemetry(): void\n ProcessStartup: () => void\n UpdateInstrument: (instrumentName: Gauge, telemetry: InstrumentBaseTelemetry) => void\n get InstrumentController(): PublishInstrumentController | null\n \n LogErrorMessage(message: any): void\n LogInfoMessage(message: any): void\n LogMessageToLoggerInstrument(message: any): void\n InstrumentExists(instrumentName: Gauge): boolean\n ProcessTerminate(): Promise<void>\n \n GetUIController(): any\n get options(): ProcessOptions\n get socketIoServerHelper(): ISocketIoServerHelper<STSDefaultClientToServerEvents, STSDefaultServerToClientEvents> | null\n set socketIoServerHelper(value: ISocketIoServerHelper<STSDefaultClientToServerEvents, STSDefaultServerToClientEvents> | null)\n TerminateDatabase(): Promise<void>\n get accessLayer(): IDBAccessLayer | null\n get shuttingDown(): boolean\n //@@get redisMessageHandler(): RedisMessageHandler\n\n emit<K extends keyof IProcessBaseEvents>(event: K, ...arg: IProcessBaseEvents[K]): this\n on<K extends keyof IProcessBaseEvents>(event: K, callback: (...arg: IProcessBaseEvents[K]) => void): this\n off<K extends keyof IProcessBaseEvents>(event: K, callback: (...arg: IProcessBaseEvents[K]) => void): this\n}\n\nexport interface IMasterProcessBase extends IProcessBase {\n WorkerMessageEvent(messageId: number, msg: any): any\n SetupServer: () => Promise<void>\n SetupServerEx: () => Promise<void>\n \n KillWorker: (id: string, signal: NodeJS.Signals, options: any, killProcess: boolean, allowKillAll: boolean) => boolean\n KillWorkers: (signal: NodeJS.Signals, keepOne?: boolean) => void\n IncWorkers: () => void\n DecWorkers: () => void\n \n AddWorker: (options: any) => number\n MasterStarted(): void\n \n BroadcastDataToWorkers: (command: any, data: any) => void\n ProcessIPCCommand(iPCMessagePayload: IPCMessagePayload): Promise<IPCMessagePayload>\n}\n\nexport interface IServerProcessBase extends IProcessBase {\n get httpServer(): any\n get io(): any\n get expressServer(): STSExpressServer | null\n set expressServer(server: STSExpressServer | null)\n Terminate: (clusterPerformExit: boolean, signal?: any) => Promise<void>\n SetupSTSServer: () => Promise<void>\n CollectAdditionalTelemetry(): void\n SetupServer(): Promise<boolean>\n SetupServerEx: () => Promise<boolean>\n ProcessStarted(): void\n}\n\nexport interface ISingleProcessBase extends IServerProcessBase {\n TerminateApplication(): Promise<void>\n}\n\nexport interface IWorkerProcessBase extends IServerProcessBase {\n ReceivedMessageFromMaster(msg: any): void\n AddWorker: (options: any) => Promise<string>\n DeleteWorker: (workerId: string, options: any) => Promise<JSONObject>\n GetMasterProcessOptions: () => Promise<JSONObject>\n}\n\n// -----------------------------------------------------------------------------\n\n/*\nexport interface IInfluxDBManagerOptions {\n token: string // API access token\n url: string // end-pont for API\n org: string // organisation\n bucket: string // bucket to store results\n agent?: {\n influxDB_keepAlive: boolean\n influxDB_maxSockets?: number\n influxDB_maxTotalSockets?: number\n influxDB_maxFreeSockets?: number\n influxDB_timeout?: number\n influxDB_rejectUnauthorized?: boolean\n }\n logger: ISTSLogger\n}\n*/\n\n/*\nexport type ConsumeMessageCB = (topic: string, partition: number, message: KafkaMessage, heartbeat: () => Promise<void>, pause: () => () => void) => void;\nexport type ConsumeMessageErrorCB = (error: any) => void;\n\nexport interface IKafkaConsumer {\n get consumer(): Consumer\n get id(): string\n Connect(errorCb: (error: any) => void): Promise<void>\n Disconnect(errorCb: (error: any) => void): Promise<void>\n Subscribe: (topics: string[], fromBeginning: boolean, errorCb: (error: any) => void) => Promise<void>\n Stop: (errorCb: (error: any) => void) => Promise<void>\n StartConsumingMessages: (autoCommit: boolean, cb: ConsumeMessageCB, errorCb: ConsumeMessageErrorCB) => Promise<void>\n}\n*/\n\nexport const iss = `https://stscore.stsmda.org/oauth2/v2.0`;\n\nexport interface STSExpressServer {\n\tget App(): express.Express\n}\n\n/**\n * Factory method that adds express routes to the express app object.\n */\nexport type ExpressRouteFactory = (app: express.Express, stsApp: IProcessBase) => void\n\n/*\nexport enum STSServerType {\n NONE = \"NONE\",\n EXPRESS = \"EXPRESS\",\n EXPRESS_TLS = \"EXPRESS_TLS\",\n\tTCPRAW_TLS = \"TCPRAW_TLS\",\n JSONRPC2_TLS = \"JSONRPC_TLS\"\n}\n*/\n\n//export interface ProcessOptions extends JSONObject {\nexport interface ProcessOptions {\n /**\n * Is this service worker the master worker (thread).\n */\n isMaster: boolean\n\n /**\n * Unique service instance ID (uuidv4).\n */\n\tserviceInstanceId: string\n\n\t/**\n\t * HTTPS service public key path.\n\t */\n httpsServerKeyPath: string\n\n\t/**\n\t * HTTPS service certificate (private key) path.\n\t */\n httpsServerCertificatePath: string\n\n /**\n * Determines whether the process will explicitly exit (using code 0) when any terminate signal is received.\n */\n processExitOnTerminate: boolean\n\n /**\n * Does this service run a Web Socket Server (wss).\n */\n wssServer: boolean\n\n\t/**\n\t * Service Prometheus metric support.\n\t */\n prometheusSupport: boolean\n\n\t/**\n\t * Service endpoint (without trailing /). Example: https://localhost\n\t */\n endpoint: string\n\n\t/**\n\t * Service API root (without trailing /). Example: /stsrest01/v1\n\t */\n apiRoot: string\n\n /**\n * Service listen port. Example: 3001.\n * Note that unix domain sockets are also supported. Example: /tmp/stsrest01.sock.\n * The socket file may also need permissions changed, i.e. chmodSync(port, 511); or chmodSync(port, 777);\n * Axios client calls will also need to use socketPath. Example: ..., socketPath: '/tmp/stsrest01.sock'\n * Ref: https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions\n * To setup side car service (per running machine/node)\n * sudo mkdir /var/run/sts\n * sudo chown marcusbettens /var/run/sts\n * In .env file per service\n * PORT=/var/run/sts/stsrest01.sock\n */\n listenPort: string\n\n /**\n * Port that this service will be exposed externally on, i.e. clients will use this port to invoke APIs on this service.\n */\n port: string\n\n\t/**\n\t * Prometheus Cluster Server port (port used for cluster prometheus scrapes). Example: 3011.\n\t */\n prometheusClusterPort: string\n\n\t/**\n\t * Service Name. Example: Rest01\n\t */\n serviceName: string\n\n /**\n\t * Service Version. Example: 1.0.0\n\t */\n serviceVersion: string\n\n /**\n * Determines where logging is output to the console (stdout).\n */\n consoleLogging: boolean\n\n /**\n * Determines where logging is output to the logging instrument (if present).\n */\n instrumentLogging: boolean\n \n // Publisher options.\n\n serviceProcessContext?: IServiceProcessContext\n\n /**\n * Factory method that adds express routes to the express app object. Used for non-static content.\n * Non-Static content is applied after logging middleware.\n */\n expressServerRouteFactory?: ExpressRouteFactory\n\n /**\n * Factory method that adds express routes to the express app object for static content.\n * Static content is applied before logging middleware.\n */\n expressServerRouteStaticFactory?: ExpressRouteFactory\n\n /**\n * Determines whether the service will monitor its own health via the /latency API endpoint.\n * Note: The service must implement the /latency end-point for this to work.\n */\n useLatency: boolean\n\n /**\n * Determines whether this service is going to need database access.\n */\n useDatabase: boolean\n\n instrumentationObservationInterval: number\n\n instrumentationTimeWindow: number\n\n useSocketIoRedisAdaptor: boolean\n \n socketIoRedisAdaptorUrl?: string\n\n useRedisInstrumentationTransport?: boolean\n \n redisInstrumentationTransportUrl?: string\n\n workerExec?: string\n\n /**\n * Is this application using nodejs cluster mode?\n */\n clusterMode: boolean\n\n logger: ISTSLogger\n\n publisherLogger: ISTSLogger\n\n publishInterval: number\n}\n","import os from 'os'\n\nexport type NetworkInterfaces = Record<string, string[]>\n\nexport function GetNetworkInterfaces(): NetworkInterfaces {\n const nets = os.networkInterfaces();\n const results: NetworkInterfaces = { };\n for (const name of Object.keys(nets)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n for (const net of nets[name] as any) {\n // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses\n if (net.family === 'IPv4' && !net.internal) {\n if (!results[name]) {\n results[name] = [];\n }\n results[name].push(net.address);\n }\n }\n }\n return results;\n}\n\nexport function GetFirstNetworkInterface(): string | null {\n const nics: NetworkInterfaces = GetNetworkInterfaces();\n let hostaddr = null;\n for (const nic in nics)\n {\n const val: string[] = nics[nic];\n if (val.length > 0)\n {\n hostaddr = val[0];\n break;\n }\n }\n return hostaddr;\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF\nimport pidusage from 'pidusage'\nimport { memoryUsage } from 'process'\nimport cluster from 'node:cluster'\nimport si from 'systeminformation' // https://systeminformation.io/\nimport { GetFirstNetworkInterface } from './../network'\n\nimport chalk from 'chalk';\n\nimport { Gauge, InstrumentBaseTelemetry, InstrumentGaugeTelemetry, InstrumentObjectTelemetry, InstrumentLogTelemetry } from '@nsshunt/stsobservability'\n\nimport { IDBAccessLayer, accessLayerType, DBAccessLayerManager, IDBAccessLayerEvents } from '@nsshunt/stsdatamanagement'\n\nimport { goptions } from '@nsshunt/stsconfig'\n\nimport { JSONObject } from '@nsshunt/stsutils'\nimport { StatusCodes } from 'http-status-codes'\n\nimport { PublishInstrumentController, IPublishInstrumentControllerOptions, InstrumentDefinitions, \n TransportType, IPublishTransportRESTServerOptions, GetInstruments } from '@nsshunt/stsobservability'\n\nimport { STSDefaultClientToServerEvents, STSDefaultServerToClientEvents } from '@nsshunt/stssocketioutils'\nimport os from 'os';\n\nimport { IProcessBase, CreateServiceProcessContext, ProcessOptions, IProcessBaseEvents } from './../commonTypes'\n\nimport { TinyEmitter } from 'tiny-emitter';\n\nimport { ISocketIoServerHelper } from '@nsshunt/stssocketioutils'\n\nexport abstract class ProcessBase extends TinyEmitter implements IProcessBase \n{\n #options: ProcessOptions;\n #instrumentController: PublishInstrumentController | null = null;\n #systemInformationInterval: NodeJS.Timeout | null = null;\n #socketIoServerHelper: ISocketIoServerHelper<STSDefaultClientToServerEvents, STSDefaultServerToClientEvents> | null = null;\n #accessLayer: IDBAccessLayer | null = null;\n //#redisMessageHandler: RedisMessageHandler | null = null;\n\n constructor(options: ProcessOptions) {\n super();\n this.#options = options;\n\n if (options.serviceName) {\n this.options.serviceProcessContext = CreateServiceProcessContext(options.serviceName, options.serviceVersion, options.serviceInstanceId,\n os.hostname(), process.pid, options.isMaster ? process.pid : process.ppid)\n }\n }\n\n #GetFormattedLogMessage(message: string): string {\n let prefix = '';\n let col = null;\n const appName = this.options.serviceName;\n\n if (cluster.isPrimary) {\n prefix = 'M';\n col = chalk.bold.cyan;\n } else {\n prefix = 'W';\n col = chalk.green;\n }\n return col(`${prefix}(${process.pid}) [${appName}]: ${message}`);\n }\n\n LogErrorMessage(message: any) {\n this.options.logger.error(this.#GetFormattedLogMessage(message));\n }\n\n LogInfoMessage(message: any) {\n this.options.logger.info(this.#GetFormattedLogMessage(message));\n }\n\n LogMessageToLoggerInstrument(message: any) {\n this.UpdateInstrument(Gauge.LOGGER, {\n LogMessage: this.#GetFormattedLogMessage(message)\n } as InstrumentLogTelemetry);\n }\n\n get options(): ProcessOptions {\n return this.#options as ProcessOptions;\n }\n\n get shuttingDown(): boolean {\n return false;\n }\n\n SetupInstrumentation()\n {\n if (!this.options.serviceProcessContext) {\n return;\n }\n\n let publishTransportOptions: IPublishTransportRESTServerOptions | null = null;\n if (goptions.observabilityPublishMode.localeCompare('PROXY') === 0) {\n publishTransportOptions = {\n transportType: TransportType.RESTAPI,\n url: `${goptions.imendpoint}:${goptions.import}${goptions.imapiroot}/publishmessage`,\n // socketPath: '/var/run/sts/stsrest01.sock'\n agentOptions: {\n keepAlive: goptions.keepAlive,\n maxSockets: goptions.maxSockets,\n maxTotalSockets: goptions.maxTotalSockets,\n maxFreeSockets: goptions.maxFreeSockets,\n timeout: goptions.timeout,\n rejectUnauthorized: goptions.isProduction // Allows self signed certs in non production mode(s)\n },\n logger: this.options.publisherLogger\n };\n } else {\n // Currently, now other types are supported\n return;\n }\n\n const httpServer: boolean = (goptions.STSServerType.localeCompare('EXPRESS') === 0) || (goptions.STSServerType.localeCompare('EXPRESS_TLS') === 0);\n\n //const fileName = './dist/publishInstrumentsWebWorker.js';\n //const worker = new Worker(fileName);\n\n const instrumentControllerOptions: IPublishInstrumentControllerOptions = {\n\n processContext: this.options.serviceProcessContext,\n //payloadType: InstrumentPayloadType.service,\n consoleLogging: this.options.consoleLogging,\n instrumentLogging: this.options.instrumentLogging,\n httpServer,\n instrumentationObservationInterval: this.options.instrumentationObservationInterval,\n instrumentationTimeWindow: this.options.instrumentationTimeWindow,\n logger: this.options.publisherLogger,\n publishInterval: this.options.publishInterval,\n publishPostFailInterval: 5000, //@@\n instrumentDefinitions: GetInstruments('service'),\n publishTransportBaseOptions: publishTransportOptions,\n autoStart: true\n /*\n [\n ...this.#GetDefaultServiceInstruments(httpServer),\n ...this.GetAdditionalInstruments()\n ]\n */\n }\n\n this.#instrumentController = new PublishInstrumentController(instrumentControllerOptions);\n }\n\n /*\n #GetDefaultServiceInstruments(httpServer: boolean): InstrumentDefinitions {\n const standardInstruments: InstrumentDefinitions = [\n [ Gauge.TIMER_GAUGE, GaugeTypes.INSTRUMENT_TIMER ],\n [ Gauge.LOGGER, GaugeTypes.INSTRUMENT_LOG, {\n consoleLogging: this.options.consoleLogging,\n instrumentLogging: this.options.instrumentLogging } as InstrumentLogOptions],\n [ Gauge.NETWORK_RX_GAUGE , GaugeTypes.INSTRUMENT_VELOCITY ],\n [ Gauge.NETWORK_TX_GAUGE, GaugeTypes.INSTRUMENT_VELOCITY ],\n [ Gauge.CPU_LOAD_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: this.options.instrumentationObservationInterval, \n sampleSize: this.options.instrumentationTimeWindow } as InstrumentGaugeOptions],\n [ Gauge.OBJECT_GAUGE, GaugeTypes.INSTRUMENT_OBJECT, {\n label:'InstrumentObjectMaster' } as InstrumentObjectOptions]\n ];\n\n let httpServerInstruments: InstrumentDefinitions = [ ];\n if (httpServer) {\n httpServerInstruments = [\n [ Gauge.REQUEST_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ], // Total number of requests serviced\n [ Gauge.AUTHENTICATION_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ], // Total number of new token requests\n [ Gauge.AUTHENTICATION_ERROR_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ], // Total number of new token requests errors\n [ Gauge.AUTHENTICATION_RETRY_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ], // Total number of new token requests retries\n\n [ Gauge.ACTIVE_REQUEST_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: this.options.instrumentationObservationInterval, \n sampleSize: this.options.instrumentationTimeWindow } as InstrumentGaugeOptions],\n [ Gauge.DURATION_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: this.options.instrumentationObservationInterval,\n sampleSize: this.options.instrumentationTimeWindow } as InstrumentGaugeOptions],\n [ Gauge.DURATION_HISTOGRAM_GAUGE, GaugeTypes.INSTRUMENT_HISTOGRAM ],\n [ Gauge.CONNECTION_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, { \n interval: this.options.instrumentationObservationInterval, \n sampleSize: this.options.instrumentationTimeWindow } as InstrumentGaugeOptions],\n \n [ Gauge.CONNECTION_POOL_TOTAL_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ],\n [ Gauge.CONNECTION_POOL_IDLE_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ],\n [ Gauge.CONNECTION_POOL_WAITING_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ],\n [ Gauge.VELOCITY_GAUGE, GaugeTypes.INSTRUMENT_VELOCITY ], // Requests per second\n [ Gauge.ERROR_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ],\n [ Gauge.RETRY_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ],\n [ Gauge.LATENCY_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: this.options.instrumentationObservationInterval,\n sampleSize: this.options.instrumentationTimeWindow } as InstrumentGaugeOptions],\n [ Gauge.LATENCY_HISTOGRAM_GAUGE, GaugeTypes.INSTRUMENT_HISTOGRAM ],\n [ Gauge.CORE_COUNT_GAUGE, GaugeTypes.INSTRUMENT_GAUGE ]\n ]\n }\n return [\n ...standardInstruments,\n ...httpServerInstruments\n ]\n }\n */\n\n GetAdditionalInstruments(): InstrumentDefinitions {\n return [ ];\n }\n\n CollectAdditionalTelemetry(): void { // eslint-disable @typescript-eslint/no-empty-function\n \n }\n\n ProcessStartup = () => {\n // use this as well\n // performance.eventLoopUtilization([utilization1[, utilization2]])\n // https://nodejs.org/api/perf_hooks.html#perf_hooksmonitoreventloopdelayoptions\n\n const ExecuteGetStats = async () => {\n const startTime = performance.now();\n\n if (this.#instrumentController) {\n const stats = await pidusage(process.pid);\n let useStatsCpu = stats.cpu;\n if (useStatsCpu < 0.01) {\n useStatsCpu = 0.01; //@@ Endure we record something about 0. 0's are filtered from monitoring tools.\n }\n this.#instrumentController.UpdateInstrument(Gauge.CPU_LOAD_GAUGE, {\n val: useStatsCpu\n } as InstrumentGaugeTelemetry);\n };\n\n /*\n pidusage(process.pid, (err, stats) => {\n if (this.#instrumentController) {\n let useStatsCpu = stats.cpu;\n if (useStatsCpu < 3) {\n useStatsCpu = 3; //@@ Endure we record something about 0. 0's are filtered from monitoring tools.\n }\n this.#instrumentController.UpdateInstrument(Gauge.CPU_LOAD_GAUGE, {\n val: useStatsCpu\n } as InstrumentGaugeTelemetry);\n }\n });\n */\n\n // https://nodejs.org/api/process.html#processmemoryusage\n const usage = memoryUsage();\n const telemetry: JSONObject = {\n r: usage.rss,\n t: usage.heapTotal,\n u: usage.heapUsed,\n x: usage.external,\n a: usage.arrayBuffers,\n }\n\n this.UpdateInstrument(Gauge.OBJECT_GAUGE, {\n val: telemetry\n } as InstrumentObjectTelemetry);\n\n this.CollectAdditionalTelemetry();\n\n const totalTime = performance.now() - startTime;\n const nextLoopTime = goptions.systemInformationInterval - totalTime;\n\n this.#systemInformationInterval = setTimeout(ExecuteGetStats, nextLoopTime).unref();\n }\n\n this.#systemInformationInterval = setTimeout(ExecuteGetStats, goptions.systemInformationInterval).unref();\n\n if (this.options.useDatabase) {\n // Get the accessLayer to force DB connection test\n const accessLayer = this.accessLayer;\n }\n\n //@@this.LogInfoMessage(`RedisMessageHandler: redisUrl: [${goptions.imRedisMessageProcessorUrl}]`);\n }\n\n UpdateInstrument = (instrumentName: Gauge, telemetry: InstrumentBaseTelemetry) => {\n if (this.#instrumentController) {\n this.#instrumentController.UpdateInstrument(instrumentName, telemetry);\n }\n }\n\n ProcessExit = (processExitDelay: number) => {\n if (this.options.processExitOnTerminate && this.options.processExitOnTerminate === true) {\n setTimeout(() => {\n this.LogInfoMessage(`Performing process.exit(0).`);\n process.exit(0);\n }, processExitDelay); // Give the workers time to terminate gracefully\n } else {\n this.LogInfoMessage(`Performing process.exit(0) - Immediate.`);\n }\n }\n\n TerminateInstrumentController = () => {\n if (this.InstrumentController) {\n this.LogInfoMessage(`ProcessBase:TerminateInstrumentController()`);\n setTimeout(() => {\n if (this.InstrumentController) {\n this.InstrumentController.EndPublish();\n }\n }, 100);\n }\n }\n\n get InstrumentController(): PublishInstrumentController | null {\n return this.#instrumentController;\n }\n\n InstrumentExists(instrumentName: Gauge): boolean\n {\n if (this.#instrumentController) {\n return this.#instrumentController.InstrumentExists(instrumentName);\n }\n return false;\n }\n\n TerminateUIController = () => {\n if (this.GetUIController() !== null) {\n this.LogInfoMessage('ProcessBase:TerminateUIController(): Destroy the user interface controller.');\n this.GetUIController().DestroyUI();\n }\n }\n\n async ProcessTerminate(): Promise<void> {\n this.emit('ProcessTerminate');\n\n if (this.#systemInformationInterval) {\n clearTimeout(this.#systemInformationInterval);\n }\n this.#systemInformationInterval = null;\n\n //@@this.#redisMessageHandler?.Stop();\n }\n\n /**\n\t * UIController (instance of UIController) to manage a console based user interface associated for this node application.\n\t * @returns UIController instance to manage a console based user interface associated for this node application.\n\t */\n GetUIController(): any {\n return null;\n }\n\n get socketIoServerHelper(): ISocketIoServerHelper<STSDefaultClientToServerEvents, STSDefaultServerToClientEvents> | null\n {\n return this.#socketIoServerHelper;\n }\n\n set socketIoServerHelper(value: ISocketIoServerHelper<STSDefaultClientToServerEvents, STSDefaultServerToClientEvents> | null)\n {\n this.#socketIoServerHelper = value;\n }\n\n #UpdatePGPoolManagerInstrument = (data: any) => {\n this.UpdateInstrument(Gauge.CONNECTION_POOL_TOTAL_GAUGE, {\n val: data.totalCount\n } as InstrumentGaugeTelemetry);\n\n this.UpdateInstrument(Gauge.CONNECTION_POOL_IDLE_GAUGE, {\n val: data.idleCount\n } as InstrumentGaugeTelemetry);\n\n this.UpdateInstrument(Gauge.CONNECTION_POOL_WAITING_GAUGE, {\n val: data.waitingCount\n } as InstrumentGaugeTelemetry);\n }\n\n async TerminateDatabase(): Promise<void> {\n if (this.#accessLayer) {\n const logPrefix = `ProcessBase:TerminateDatabase():${process.pid}:`;\n this.LogInfoMessage(`${logPrefix} Ending database connections and pools.`);\n this.#accessLayer.off(IDBAccessLayerEvents.UpdateInstruments, this.#UpdatePGPoolManagerInstrument)\n await this.#accessLayer.EndDatabase();\n }\n }\n\n get accessLayer(): IDBAccessLayer | null\n {\n if (this.options.useDatabase) {\n if (this.#accessLayer === null) {\n\n this.#accessLayer = new DBAccessLayerManager().CreateAccessLayer({\n accessLayerType: accessLayerType.postgresql,\n accessLayerOptions: {\n logger: this.options.logger,\n usedefaultdb: false\n }\n });\n \n this.#accessLayer.on(IDBAccessLayerEvents.UpdateInstruments, this.#UpdatePGPoolManagerInstrument);\n\n (async () => {\n try {\n const retVal = await (this.accessLayer as IDBAccessLayer).GetResourceCount();\n if (retVal.status !== StatusCodes.OK) {\n this.LogInfoMessage(chalk.red(`Unable to get resources from the database. Is the database running? [${JSON.stringify(retVal)}]`));\n } else {\n this.LogInfoMessage(chalk.green(`Database connection successful. Resources: [${retVal.detail}]`));\n }\n } catch (error) {\n this.LogInfoMessage(chalk.red(`Unable to get resources from the database. Is the database running? Error: [${error}]`));\n }\n })();\n }\n return this.#accessLayer;\n }\n return null;\n }\n\n GetNumCPUs = async (): Promise<number> => {\n // https://systeminformation.io/\n const valueObject = {\n cpu: '*'\n }\n\n const sysinfo = await si.get(valueObject);\n let numCPUs = 2;\n if (goptions.useCPUs > 0) {\n if (goptions.useCPUs >= 1) {\n numCPUs = goptions.useCPUs;\n } else {\n numCPUs = Math.round(sysinfo.cpu.cores * goptions.useCPUs);\n }\n } else {\n numCPUs = sysinfo.cpu.physicalCores;\n }\n return numCPUs;\n }\n\n LogSystemTelemetry = async () => {\n // https://systeminformation.io/\n const valueObject = {\n system: '*',\n osInfo: '*',\n cpu: '*',\n mem: '*'\n }\n\n const sysinfo = await si.get(valueObject);\n const numCPUs = await this.GetNumCPUs();\n const hostname = sysinfo.osInfo.hostname;\n\n const hostaddr = GetFirstNetworkInterface();\n if (hostaddr !== null) {\n this.LogInfoMessage(`Host Address: ${hostaddr}`);\n } else {\n this.LogInfoMessage(`Unknown Host Address.`);\n }\n this.LogInfoMessage(`Server starting with ${numCPUs} Cores/Threads`);\n\n this.LogInfoMessage(`Hostname: ${hostname}`);\n this.LogInfoMessage(`System: ${JSON.stringify(sysinfo.system)}`);\n this.LogInfoMessage(`OS Info: ${JSON.stringify(sysinfo.osInfo)}`);\n this.LogInfoMessage(`CPU: ${JSON.stringify(sysinfo.cpu)}`);\n this.LogInfoMessage(`Memory: ${JSON.stringify(sysinfo.mem)}`);\n }\n\n GetSignalColour = (signal: any) => {\n let msgcolor = null;\n if (signal === 'SIGINT') {\n msgcolor = chalk.yellow;\n } else {\n msgcolor = chalk.red;\n }\n return msgcolor;\n };\n\n emit<K extends keyof IProcessBaseEvents>(event: K, ...arg: IProcessBaseEvents[K]): this {\n super.emit(event, arg);\n return this;\n }\n\n on<K extends keyof IProcessBaseEvents>(event: K, callback: (...arg: IProcessBaseEvents[K]) => void): this {\n super.on(event, callback);\n return this;\n }\n\n off<K extends keyof IProcessBaseEvents>(event: K, callback: (...arg: IProcessBaseEvents[K]) => void): this {\n super.off(event, callback);\n return this;\n }\n\n /*@@\n get redisMessageHandler(): RedisMessageHandler {\n return this.#redisMessageHandler as RedisMessageHandler;\n }\n */\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport Transport, { TransportStreamOptions } from 'winston-transport'\n\nimport { IProcessBase } from './../commonTypes'\n\nexport interface ISTSTransportLoggerWinstonOptions extends TransportStreamOptions {\n stsApp: IProcessBase\n}\n\nexport class STSTransportLoggerWinston extends Transport {\n\n #options: ISTSTransportLoggerWinstonOptions;\n\n constructor(opts: ISTSTransportLoggerWinstonOptions) {\n super(opts);\n this.#options = opts;\n }\n \n log(info: any, callback: any) {\n this.#options.stsApp.LogMessageToLoggerInstrument(info.message);\n this.emit('logged', info);\n callback();\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF\nimport fs from \"node:fs\"\nimport si from 'systeminformation' // https://systeminformation.io/\n\nimport axios from 'axios';\n\nimport cluster, { Worker, Address } from 'node:cluster'\n\nimport chalk from 'chalk';\n\nimport express from 'express'\n\nimport { setupPrimary } from '@socket.io/cluster-adapter'\nimport { createServer as createServerHttps } from 'node:https'\nimport { createServer } from 'node:http'\nimport { AggregatorRegistry } from 'prom-client'\n\nimport { goptions, STSAxiosConfig, AgentManager } from '@nsshunt/stsconfig'\n\nimport { Gauge, GaugeTypes, InstrumentGaugeTelemetry, InstrumentGaugeOptions, InstrumentHistogramTelemetry } from '@nsshunt/stsobservability'\n\nimport { ProcessBase } from './processbase';\nimport { IMasterProcessBase, ProcessOptions } from './../commonTypes';\n\nimport { InstrumentDefinitions } from '@nsshunt/stsobservability'\nimport { IPCMessagePayload, IPCMessageCommand } from './../commonTypes'\n\nimport { STSTransportLoggerWinston } from './../logger/stsTransportLoggerWinston'\n\nimport { Sleep } from '@nsshunt/stsutils'\n\n//import { GetFirstNetworkInterface } from './network';\n\nexport class MasterProcessBase extends ProcessBase implements IMasterProcessBase\n{\n //static WORKER_MESSAGE_EVENT = 'sts_worker_message_event';\n #masterProcessExitTime = goptions.masterProcessExitTime;\n #childProcessExitTime = goptions.childProcessExitTime;\n #siValueObject = {\n currentLoad: 'currentLoad'\n }\n #httpServer: any = null; // Prometheus cluster server. See https://github.com/siimon/prom-client/blob/master/example/cluster.js\n #metricsServer: any= null;\n #aggregatorRegistry: any = null;\n #checkLatency: NodeJS.Timeout | null = null;\n #killWorkers: Record<string, string> = { };\n #workers = 1; // Start at 1 becuase of main thread\n #shuttingDown = false;\n #agentManager: AgentManager;\n\n constructor(options: ProcessOptions)\n {\n super(options);\n\n this.#agentManager = new AgentManager({\n agentOptions: {\n keepAlive: false, // Use basic defaults. This agent will not use keep-alive.\n maxFreeSockets: goptions.maxFreeSockets,\n maxSockets: goptions.maxSockets,\n maxTotalSockets: goptions.maxTotalSockets,\n timeout: goptions.timeout,\n rejectUnauthorized: goptions.isProduction // Allows self-signed certificates if non-production\n }\n });\n }\n\n #LogErrorMessage(message: any) {\n this.options.logger.error(message);\n }\n\n #LogDebugMessage(message: any) {\n this.options.logger.debug(message);\n }\n\n override CollectAdditionalTelemetry(): void {\n si.get(this.#siValueObject).then(data => {\n this.UpdateInstrument(Gauge.CPU_SYSTEM_LOAD_GAUGE, {\n val: data.currentLoad.currentLoad\n } as InstrumentGaugeTelemetry);\n });\n }\n\n override GetAdditionalInstruments(): InstrumentDefinitions {\n return [\n [ Gauge.CPU_SYSTEM_LOAD_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: goptions.instrumentationObservationInterval, \n sampleSize: goptions.instrumentationTimeWindow\n } as InstrumentGaugeOptions]\n ]\n }\n\n /**\n\t * Note: msg removed from signature but will be passed at run-time.\n\t * @param {*} msg \n\t */\n \n WorkerMessageEvent(workerId: number, msg: any) {\n return null;\n }\n\n \n #WorkerMessageEvent(workerId: number, msg: any) {\n if (msg.command) {\n this.WorkerMessageEvent(workerId, msg);\n }\n }\n\n #InitCluster = () => {\n cluster.on('listening', (worker: Worker, address: Address) => {\n this.emit('clusterListening', worker, address);\n let allListening = true;\n for (const worker of Object.values(cluster.workers as NodeJS.Dict<Worker>)) {\n if (worker?.isConnected) {\n allListening = false;\n break;\n }\n }\n if (allListening) {\n this.LogInfoMessage(`Service instance started.`);\n this.emit('allListening');\n }\n });\n };\n\n // https://github.com/siimon/prom-client/blob/master/example/cluster.js\n #SetupPrometheusForMaster = () => {\n this.#metricsServer = express();\n this.#aggregatorRegistry = new AggregatorRegistry();\n\n switch (goptions.STSServerType) {\n case 'EXPRESS_TLS' : {\n const options = {\n key: fs.readFileSync(this.options.httpsServerKeyPath),\n cert: fs.readFileSync(this.options.httpsServerCertificatePath)\n };\n this.#httpServer = createServerHttps(options, this.#metricsServer);\n }\n break;\n case 'EXPRESS' : {\n this.#httpServer = createServer(this.#metricsServer);\n }\n }\n //this.#httpServer.maxConnections = 50;\n\n this.#metricsServer.get('/cluster_metrics', async (req: any, res: any) => {\n try {\n const metrics = await this.#aggregatorRegistry.clusterMetrics();\n res.set('Content-Type', this.#aggregatorRegistry.contentType);\n res.send(metrics);\n } catch (ex: any) {\n res.statusCode = 500;\n res.send(ex.message);\n }\n });\n\n //@@@ options wrong\n\n try {\n // https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions\n //@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>\n //@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>\n //@@httpServer.listen('/var/lib/sts/stsrest01.sock').on('listening', () =>\n this.#httpServer.listen(this.options.prometheusClusterPort, () => { \n //@@chmodSync(this.options.port, 511);\n }).on('listening', () =>\n {\n this.emit('prometheusScrapesListening', `${this.options.endpoint}:${this.options.prometheusClusterPort}/metrics`,\n this.options.endpoint,\n this.options.prometheusClusterPort);\n this.LogInfoMessage(`Prometheus scrapes ready and live on ${this.options.endpoint}:${this.options.prometheusClusterPort}/metrics`);\n });\n } catch (error)\n {\n this.#LogErrorMessage(error);\n throw error;\n }\n }\n\n #CheckLatency = async () => {\n const start = process.hrtime();\n await this.#GetLatency();\n this.#LatencyRequestCompleted(start);\n }\n\n \n #GetLatency = async (): Promise<any> => {\n let retVal: any = null;\n // We use port rather than hostport becuase this test going outside the service and comes back in as a regular client\n const url = `${this.options.endpoint}:${this.options.port}${this.options.apiRoot}/latency`;\n try {\n retVal = await axios(new STSAxiosConfig(url, 'get')\n .withDefaultHeaders()\n .withAgentManager(this.#agentManager).config);\n if (retVal.status !== 200) {\n this.#LogDebugMessage(chalk.magenta(`Error (MasterProcessBase:#GetLatency): Invalid response from server: [${retVal.status}]`));\n return null;\n }\n return retVal.data.detail;\n } catch (error: any) {\n this.#LogDebugMessage(chalk.red(`Error (MasterProcessBase:#GetLatency:catch): [${error}]`));\n this.#LogDebugMessage(chalk.red(` url: [${url}]`));\n if (error.response && error.response.data) {\n this.#LogDebugMessage(chalk.red(` Details: [${JSON.stringify(error.response.data)}]`));\n }\n }\n }\n\n #LatencyRequestCompleted = (start: any) => {\n // Update request duration histo data\n let timeInMs = 0;\n const end = process.hrtime(start);\n timeInMs = (end[0]* 1000000000 + end[1]) / 1000000;\n timeInMs = parseFloat(timeInMs.toFixed(4));\n\t\t\n this.UpdateInstrument(Gauge.LATENCY_HISTOGRAM_GAUGE, {\n val: timeInMs\n } as InstrumentHistogramTelemetry);\n\n this.UpdateInstrument(Gauge.LATENCY_GAUGE, {\n val: timeInMs\n } as InstrumentGaugeTelemetry);\n };\n\n SetupServer = async () => {\n this.SetupInstrumentation();\n setTimeout(() => {\n this.SetupServerEx();\n }, 100);\n }\n\n #_KillWorker = (id: string, signal: NodeJS.Signals, killProcess: boolean): boolean => {\n try {\n if (cluster.workers && cluster.workers[id]) {\n const worker = cluster.workers[id] as Worker;\n if (worker.process) {\n this.LogInfoMessage(chalk.grey(`Sending terminate message `) + chalk.yellow(`(initiated by ${signal})`) + chalk.grey(` for worker PID: ${worker.process.pid}`));\n const command: string = (killProcess ? 'TerminateAndKill' : 'Terminate');\n try {\n worker.send( { command } );\n //worker.process.send( { command } );\n } catch (error) {\n this.LogInfoMessage(chalk.red(`MasterProcessBase:#_KillWorker() (1): id: [${id}], signal: [${signal}], killProcess: [${killProcess}], error: [${error}]`));\n return false;\n }\n return true;\n } else {\n this.LogInfoMessage(chalk.red(`MasterProcessBase:#_KillWorker(): Could not kill worker with id: [${id}]. The process does not exists`));\n return false;\n }\n } else {\n this.LogInfoMessage(chalk.red(`MasterProcessBase:#_KillWorker(): Could not kill worker with id: [${id}]. Worker does not exist within workers collection`));\n return false;\n }\n } catch (error) {\n this.LogInfoMessage(chalk.red(`MasterProcessBase:#_KillWorker() (2): id: [${id}], signal: [${signal}], killProcess: [${killProcess}], error: [${error}]`));\n return false;\n }\n }\n\n \n KillWorker = (id: string, signal: NodeJS.Signals = \"SIGTERM\", options: any, killProcess: boolean, allowKillAll: boolean): boolean => {\n try {\n if (allowKillAll || Object.keys(cluster.workers as NodeJS.Dict<Worker>).length > 1) {\n if (id.localeCompare('0') === 0) {\n const keys = Object.keys(cluster.workers as NodeJS.Dict<Worker>);\n for (let i=keys.length-1; i > 0; i--) {\n // Kill the last one added (assumed node keeps them in order)\n id = keys[i];\n if (!this.#killWorkers[id]) {\n this.#killWorkers[id] = id;\n // Allow some time for the worker to be terminated before clean-up of the killWorkers array\n setTimeout(() => {\n delete this.#killWorkers[id];\n }, 2000).unref(); //@@\n return this.#_KillWorker(id, signal, killProcess);\n }\n }\n return false;\n } else {\n return this.#_KillWorker(id, signal, killProcess);\n }\n } else {\n this.LogInfoMessage(chalk.yellow(`MasterProcessBase:KillWorker(): Not allowed to kill the last worker process.`));\n return false;\n }\n } catch (error) {\n this.LogInfoMessage(chalk.red(`MasterProcessBase:KillWorker(): id: [${id}], signal: [${signal}], killProcess: [${killProcess}], error: [${error}]`));\n return false;\n }\n }\n\n KillWorkers = (signal: NodeJS.Signals, keepOne?: boolean): void => {\n const logPrefix = `MasterProcessBase:KillWorkers():${process.pid}:`;\n try {\n this.LogInfoMessage(`${logPrefix} Killing Workers.`);\n const keepOneAlive = (keepOne ? keepOne : false);\n let skippedFirst = false;\n const sortedIdList: number[] = [ ];\n for (const id in cluster.workers) {\n sortedIdList.push(parseInt(id));\n }\n sortedIdList.sort().forEach((id) => {\n if (keepOneAlive && !skippedFirst) {\n skippedFirst = true;\n } else {\n this.KillWorker(id.toString(), signal, null, false, true);\n }\n });\n } catch (error) {\n this.LogInfoMessage(chalk.red(`${logPrefix} signal: [${signal}], keepOne: [${keepOne}], error: [${error}]`));\n }\n }\n\n #UpdateWorkersInstrument = (): void => {\n setTimeout(() => {\n this.UpdateInstrument(Gauge.CORE_COUNT_GAUGE, {\n val: this.#workers\n } as InstrumentGaugeTelemetry);\n }, 2000);\n }\n\n IncWorkers = (): void => {\n this.#workers++;\n this.#LogDebugMessage(` Inc Workers. Total thread count: [${this.#workers}]`);\n this.#UpdateWorkersInstrument();\n }\n\n DecWorkers = (): void => {\n this.#workers--;\n this.#LogDebugMessage(` Dec Workers. Total thread count: [${this.#workers}]`);\n this.#UpdateWorkersInstrument();\n }\n\n \n AddWorker = (options: any): number => {\n const workerId: number = this.#SpawnWorker(options);\n this.#LogDebugMessage(chalk.yellow(` Spawned worker with id: [${workerId}]`));\n if (options) {\n this.#LogDebugMessage(chalk.yellow(` Options: [${JSON.stringify(options)}]`));\n }\n return workerId;\n }\n\n async ProcessIPCCommand(iPCMessagePayload: IPCMessagePayload): Promise<IPCMessagePayload> {\n return this.#processIPCCommand(iPCMessagePayload);\n }\n\n #processIPCCommand = async (iPCMessagePayload: IPCMessagePayload): Promise<IPCMessagePayload> => {\n this.#LogDebugMessage(chalk.yellow(` Processing message command: [${iPCMessagePayload.command}]`));\n switch (iPCMessagePayload.command) {\n case IPCMessageCommand.AddWorker : {\n const workerId = this.AddWorker(iPCMessagePayload.requestDetail?.options);\n iPCMessagePayload.responseDetail = {\n workerId\n }\n return iPCMessagePayload;\n }\n case IPCMessageCommand.DeleteWorker : {\n const workerId = iPCMessagePayload.requestDetail?.workerId;\n const workerKilled = this.KillWorker(workerId, \"SIGTERM\", iPCMessagePayload.requestDetail?.options, true, false);\n this.#LogDebugMessage(chalk.yellow(` Killed worker with id: [${workerId}]`));\n iPCMessagePayload.responseDetail = {\n workerId,\n workerKilled\n }\n return iPCMessagePayload;\n }\n case IPCMessageCommand.GetConfig : {\n const safeOptions = { ...this.options };\n delete (safeOptions as any).logger\n delete (safeOptions as any).publisherLogger\n delete (safeOptions as any).expressServerRouteFactory\n //this.#LogDebugMessage(chalk.yellow(` Safe options: [${JSON.stringify(safeOptions)}]`));\n iPCMessagePayload.responseDetail = {\n safeOptions\n }\n return iPCMessagePayload;\n }\n default : {\n const errorMessage = `Could not process command: [${iPCMessagePayload.command}].`;\n this.#LogDebugMessage(chalk.red(` ${errorMessage}`));\n throw new Error(errorMessage);\n }\n }\n }\n\n \n #SpawnWorker = (spawnWorkerOptions?: any): number => {\n const workerEnv: any = { };\n\n const tempOptions = { ...this.options };\n\n // Remove the assigned loggers (this will need to be re-created in the worker thread)\n delete (tempOptions as any).logger;\n delete (tempOptions as any).publisherLogger;\n\n workerEnv['STS_GSD_SII'] = JSON.stringify(tempOptions);\n if (spawnWorkerOptions) {\n workerEnv['STS_GSD_OPTIONS'] = JSON.stringify(spawnWorkerOptions);\n }\n\n // https://nodejs.org/api/cluster.html#clustersetupprimarysettings\n if (this.options.workerExec) {\n cluster.setupPrimary({\n exec: this.options.workerExec,\n silent: true,\n });\n }\n\n const worker = cluster.fork(workerEnv);\n this.IncWorkers();\n\n worker.on('exit', (code, signal) => {\n this.emit('workerExit', code, signal);\n if (signal) {\n this.LogInfoMessage(`Worker: ${worker.process.pid} was killed by signal: ${signal}`);\n } else if (code !== 0) {\n this.LogInfoMessage(`Worker: ${worker.process.pid} exited with error code: ${code}`);\n } else {\n this.LogInfoMessage(`Worker: ${worker.process.pid} exited successfully, code: ${code}, signal: ${signal}`);\n }\n });\n\n worker.on('message', async (payload) => {\n this.emit('workerMessage', worker.id, payload);\n // Only handle request/response message types here ...\n if (payload.requestResponse) {\n const iPCMessagePayload: IPCMessagePayload = payload as IPCMessagePayload;\n //this.#LogDebugMessage(chalk.yellow(`Received message with id: [${iPCMessagePayload.id}] from worker: [${worker.process.pid}]. Details: [${JSON.stringify(iPCMessagePayload)}]`));\n const response: IPCMessagePayload = await this.ProcessIPCCommand(iPCMessagePayload);\n //this.#LogDebugMessage(chalk.green(`Sending response message with id: [${iPCMessagePayload.id}] to worker: [${worker.process.pid}]. Details: [${JSON.stringify(response)}]`));\n worker.send(response);\n } else {\n this.#WorkerMessageEvent(worker.id, payload);\n }\n });\n\n worker.on('error', (error) => {\n this.emit('workerError', error);\n const message = chalk.red(`#SpawnWorker():worker.on('error'): Error: [${error}]`);\n this.LogErrorMessage(message);\n });\n\n this.emit('workerAdded', worker.id);\n\n return worker.id;\n };\n\n MasterStarted(): void { // eslint-disable @typescript-eslint/no-empty-function\n const transport = new STSTransportLoggerWinston({\n stsApp: this\n });\n setTimeout(() => {\n (this.options.logger as any).add(transport);\n }, 0);\n }\n\n override get shuttingDown(): boolean {\n return this.#shuttingDown;\n }\n\n SetupServerEx = async () =>\n {\n this.ProcessStartup();\n\n this.LogInfoMessage(`Service instance starting. Instance Id: [${this.options.serviceInstanceId}]`);\n\n this.LogSystemTelemetry();\n\n // socket.io\n // setup connections between the workers\n if (this.options.wssServer === true) {\n if (this.options.useSocketIoRedisAdaptor) {\n this.LogInfoMessage(`Using Redis for socket.io cluster management (master)`);\n } else {\n this.LogInfoMessage(`Using nodejs cluster mode for socket.io cluster management`);\n setupPrimary();\n }\n }\n\n if (this.options.prometheusSupport === true) {\n this.#SetupPrometheusForMaster();\n }\n\n const numCPUs = await this.GetNumCPUs();\n for (let i=0; i < numCPUs; i++) {\n this.#SpawnWorker();\n }\n\n this.#InitCluster();\n\n cluster.on('listening', (worker, address) => {\n this.emit('clusterListening', worker, address);\n this.LogInfoMessage(`Worker process ${worker.process.pid} is listening at address: ${JSON.stringify(address)}`);\n });\n\n //Setting up lifecycle event listeners for worker processes\n cluster.on('online', worker => {\n this.emit('clusterOnline', worker);\n this.LogInfoMessage(`Worker process ${worker.process.pid} is online`);\n });\n\n cluster.on('exit', (worker, code, signal) => {\n this.emit('clusterExit', worker, code, signal);\n if ((code !== null && code === 0) || (signal === 'SIGINT')) {\n this.LogInfoMessage(chalk.green(`Process ${worker.process.pid} terminated gracefully with code: ${code}, signal: ${signal}`));\n this.DecWorkers();\n } else if ((code !== null && code === 15) || (signal === 'SIGTERM')) {\n this.DecWorkers();\n this.LogInfoMessage(chalk.red(`Process ${worker.process.pid} terminated with code: ${code}, signal: ${signal}`));\n } else {\n this.DecWorkers();\n this.LogInfoMessage(chalk.red(`worker ${worker.process.pid} died`));\n this.LogInfoMessage(chalk.red(`code: ${code}`));\n this.LogInfoMessage(chalk.red(`signal: ${signal}`));\n this.LogInfoMessage(chalk.red('process terminated in an error state'));\n if (goptions.respawnOnFail === true) {\n this.LogInfoMessage(chalk.magenta(`Attemping to respawn worker`));\n this.#SpawnWorker();\n }\n }\n });\n\n const TerminateLatency = () => {\n if (this.#checkLatency) {\n clearInterval(this.#checkLatency);\n this.#checkLatency = null;\n }\n }\n\n const TerminateHTTPServer = async (): Promise<void> => {\n if (this.#httpServer !== null) {\n const logPrefix = `ServerProcessBase:TerminateHTTPServer():${process.pid}:`;\n this.LogInfoMessage(`${logPrefix} Closing httpServer.`);\n await this.#httpServer.close();\n this.#httpServer = null;\n }\n }\n\n // Terminate in order;\n // forked worker threads (send signal)\n // De-Register service\n // systeminformation observers\n // instrument timers (gauge etc.)\n // publisher\n // terminate UI (if loaded)\n const Terminate = async (signal: any): Promise<void> => {\n const logPrefix = `MasterProcessBase:Terminate():${process.pid}:`;\n if (this.#shuttingDown === false) {\n this.#shuttingDown = true;\n\n if (signal) {\n this.LogInfoMessage(this.GetSignalColour(signal)(`${logPrefix} Received signal: ${signal}`));\n } else {\n this.LogInfoMessage(this.GetSignalColour(null)(`${logPrefix} Received Terminate without signal.`));\n }\n\n TerminateLatency();\n\n await this.ProcessTerminate();\n\n this.TerminateUIController();\n \n this.LogInfoMessage(`${logPrefix} De-Registering service.`);\n //@@ De-register here ...\n\n await TerminateHTTPServer();\n\n this.KillWorkers(signal);\n\n await this.TerminateDatabase();\n\n this.TerminateInstrumentController();\n\n await Sleep(1000);\n\n this.ProcessExit(this.#childProcessExitTime + this.#masterProcessExitTime);\n\n } else {\n this.LogInfoMessage(`${logPrefix} Process already terminating.`);\n }\n }\n\n process.on('SIGINT', async () => {\n this.emit('processSigint');\n await Terminate('SIGINT');\n });\n\n process.on('SIGTERM', async () => {\n this.emit('processSigterm');\n await Terminate('SIGTERM');\n });\n\n process.on('exit', (code) => {\n this.emit('processExit', code);\n if (code === 0) {\n this.LogInfoMessage(chalk.green(`Main Process: ${process.pid} terminated gracefully with code: ${code}`));\n } else {\n this.LogInfoMessage(chalk.red(`Main Process: ${process.pid} terminated with code: ${code}`));\n }\n });\n\n if (this.options.useLatency) {\n this.#checkLatency = setInterval(() => {\n this.#CheckLatency();\n }, 1000).unref();\n }\n\n this.MasterStarted();\n\n this.LogInfoMessage(chalk.green(`Master process:${process.pid} started`));\n }\n\n BroadcastDataToWorkers = (command: any, data: any) => {\n try {\n for (const id in cluster.workers) {\n try {\n //@@this.LogInfoMessage(chalk.gray(`Sending message to worker PID: ${cluster.workers[id].process.pid}`));\n (cluster.workers[id] as Worker).process.send( { command: command, data: data } );\n } catch (error) {\n //@@this.LogInfoMessage(error);\n }\n }\n } catch (error) {\n //@@this.LogInfoMessage(error);\n }\n }\n\n /*\n #GetSystemInformation = async (): Promise<JSONObject> => {\n // https://systeminformation.io/\n const valueObject = {\n system: '*',\n osInfo: '*',\n cpu: '*',\n mem: '*',\n dockerInfo: '*',\n //dockerImages: '*',\n dockerContainers: '*',\n }\n \n const sysinfo = await si.get(valueObject);\n const numCPUs = await this.GetNumCPUs();\n const hostname = sysinfo.osInfo.hostname;\n \n const hostaddr = GetFirstNetworkInterface();\n \n const promArray: Promise<any>[] = [ ];\n \n sysinfo.dockerContainers.forEach((dc: { id: string; }) => {\n const dcs = promArray.push(si.dockerContainerStats(dc.id));\n console.log(dcs);\n });\n const dockerContainerStats = await Promise.all(promArray);\n \n const sysInfo = {\n serviceProcessContext: this.options.serviceProcessContext,\n hostname,\n numCPUs,\n hostaddr,\n system: sysinfo.system,\n osInfo: sysinfo.osInfo,\n cpu: sysinfo.cpu,\n mem: sysinfo.mem,\n dockerInfo: sysinfo.dockerInfo,\n //dockerImages: sysinfo.dockerImages,\n dockerContainers: sysinfo.dockerContainers,\n dockerContainerStats\n }\n\n return sysInfo;\n }\n */\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF\nimport chalk from 'chalk'; // Note: Do NOT upgrade beyond 4.1.2 as the ESM version (5.0.0+) breaks this entire codebase\nimport { Request, Response, NextFunction } from 'express'\nimport { Socket } from 'node:net'\nimport { TinyEmitter } from 'tiny-emitter';\n\nimport { ISTSLogger, STSOptionsBase } from '@nsshunt/stsutils';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport onHeaders from 'on-headers';\n\nexport enum ServerNetworkMiddlewareEventName {\n UpdateInstrument_SERVER_NET_VAL = 'UpdateInstrument_SERVER_NET_VAL' // request net stats\n}\n\nexport interface ISocketRecord {\n id: string\n socket: Socket,\n currentBytesRead: number\n currentBytesWritten: number\n lastBytesRead: number\n lastBytesWritten: number\n requestBytesRead: number\n requestBytesWritten: number\n originalUrl: string\n eventName: string\n}\n\nexport type ServerNetworkMiddlewareEventFunc = (data: ISocketRecord) => void;\n\nexport interface IServerNetworkMiddleware {\n name: string\n outputDebug: boolean\n logger: ISTSLogger\n}\n\nexport class ServerNetworkMiddleware extends STSOptionsBase\n{\n #tinyEmitter: TinyEmitter = new TinyEmitter();\n #socketCollection: Record<string, ISocketRecord> = { };\n #id: string = '';\n\n constructor(options: IServerNetworkMiddleware) {\n super(options);\n }\n\n #LogSillyMessage(message: any) {\n this.options?.logger.silly(message);\n }\n\n #LogErrorMessage(message: any) {\n this.options?.logger.error(message);\n }\n\n on(eventName: ServerNetworkMiddlewareEventName, callBackFn: ServerNetworkMiddlewareEventFunc) {\n this.#tinyEmitter.on(eventName, callBackFn);\n }\n\n GetSocketRecord = (socket: Socket): ISocketRecord | null => {\n for (const [, socketRecord] of Object.entries(this.#socketCollection)) {\n if (socketRecord.socket === socket) {\n return socketRecord;\n }\n }\n return null;\n }\n\n UpdateNetworkStats = (workingSocketRecord: ISocketRecord, eventName: string, req: Request) => {\n workingSocketRecord.originalUrl = req.originalUrl;\n workingSocketRecord.eventName = eventName;\n\n workingSocketRecord.currentBytesRead = req.socket.bytesRead;\n workingSocketRecord.currentBytesWritten = req.socket.bytesWritten;\n\n workingSocketRecord.requestBytesRead = workingSocketRecord.currentBytesRead - workingSocketRecord.lastBytesRead;\n workingSocketRecord.requestBytesWritten = workingSocketRecord.currentBytesWritten - workingSocketRecord.lastBytesWritten;\n\n //this.#LogDebugMessage(chalk.gray(`totalBytesRead: [${workingSocketRecord.id}] [${workingSocketRecord.originalUrl}] [${eventName}] [${workingSocketRecord.requestBytesRead}]`));\n //this.#LogDebugMessage(chalk.gray(`totalBytesWritten: [${workingSocketRecord.id}] [${workingSocketRecord.originalUrl}] [${eventName}] [${workingSocketRecord.requestBytesWritten}]`));\n\n const workingSocketEventRecord = { ...workingSocketRecord };\n delete (workingSocketEventRecord as any).socket;\n\n this.#LogSillyMessage(chalk.gray(`Sending event: [${JSON.stringify(workingSocketEventRecord)}]`));\n\n this.#tinyEmitter.emit(ServerNetworkMiddlewareEventName.UpdateInstrument_SERVER_NET_VAL, workingSocketEventRecord);\n\n workingSocketRecord.lastBytesRead = workingSocketRecord.currentBytesRead;\n workingSocketRecord.lastBytesWritten = workingSocketRecord.currentBytesWritten;\n }\n\n #GetRequestContentSize = (req: Request) => {\n try {\n let contentLength = 0;\n if ((req as any)['_contentLength']) {\n contentLength = (req as any)['_contentLength'];\n } else {\n if (req.headers['content-length']) {\n contentLength = parseInt(req.headers['content-length'])\n }\n }\n return contentLength;\n } catch (error) {\n this.#LogErrorMessage(chalk.red(`ServerNetworkMiddleware:#GetRequestContentSize(): Error: [${error}]`));\n return 0;\n }\n }\n\n Middleware = (req: Request, res: Response, next: NextFunction) => {\n let workingSocketRecord: ISocketRecord | null = null;\n \n workingSocketRecord = this.GetSocketRecord(req.socket);\n\n if (!workingSocketRecord) {\n this.#id = uuidv4();\n workingSocketRecord = {\n id: `${(this.options as IServerNetworkMiddleware).name}_${this.#id.toString()}`,\n socket: req.socket,\n currentBytesRead: 0,\n currentBytesWritten: 0,\n lastBytesRead: 0,\n lastBytesWritten: 0,\n requestBytesRead: 0,\n requestBytesWritten: 0,\n originalUrl: req.originalUrl,\n eventName: '',\n };\n\n this.#socketCollection[workingSocketRecord.id] = workingSocketRecord;\n\n this.#LogSillyMessage(chalk.gray(`Adding new socket to recordset: ID: [${workingSocketRecord.id}], originalUrl: [${workingSocketRecord.originalUrl}]`));\n\n workingSocketRecord.socket.on('data', () => {\n const socketRecord = this.GetSocketRecord((workingSocketRecord as ISocketRecord).socket);\n if (socketRecord) {\n this.#LogSillyMessage(chalk.gray(`Socket data event: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`));\n this.UpdateNetworkStats(socketRecord, 'socket_data', req);\n } else {\n this.#LogSillyMessage(chalk.magenta(`Socket data event: Could not find socket within recordset`));\n }\n });\n\n workingSocketRecord.socket.on('close', () => {\n const socketRecord = this.GetSocketRecord((workingSocketRecord as ISocketRecord).socket);\n if (socketRecord) {\n this.#LogSillyMessage(chalk.gray(`Socket close event: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`));\n this.UpdateNetworkStats(socketRecord, 'socket_close', req);\n delete this.#socketCollection[socketRecord.id];\n this.#LogSillyMessage(chalk.gray(`Socket removed from recordset: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`));\n } else {\n this.#LogSillyMessage(chalk.magenta(`Socket close event: Could not find socket within recordset`));\n }\n });\n\n workingSocketRecord.socket.on('end', () => {\n const socketRecord = this.GetSocketRecord((workingSocketRecord as ISocketRecord).socket);\n if (socketRecord) {\n this.#LogSillyMessage(chalk.gray(`Socket end event: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`));\n this.UpdateNetworkStats(socketRecord, 'socket_end', req);\n } else {\n this.#LogSillyMessage(chalk.magenta(`Socket end event: Could not find socket within recordset`));\n }\n });\n }\n\n // The following gets the payload size from adding _contentLength or content-length to the header size.\n // From brief observations, this appears to be about 80 bytes short from what is reported by the socket writtenBytes.\n onHeaders(res, () => {\n let contentLength = 0;\n if ((res as any)['_contentLength']) {\n contentLength = (res as any)['_contentLength'];\n } else {\n if (res.hasHeader('content-length')) {\n contentLength = parseInt(res.getHeader('content-length') as string);\n }\n }\n\n // Ensure that the client does NOT cache the response\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); // HTTP 1.1\n res.setHeader('Pragma', 'no-cache'); // HTTP 1.0\n res.setHeader('Expires', '0'); // Proxies\n\n const headerLength = JSON.stringify(res.getHeaders()).length;\n const totalSize = contentLength + headerLength;\n\n this.#LogSillyMessage(chalk.white.bgBlue(`contentLength: [${contentLength}], headerLength: [${headerLength}], total Size: [${totalSize}]`));\n });\n\n // This event is the one where bytesWritten is generally recorded\n req.on('end', () => {\n const socketRecord = this.GetSocketRecord(req.socket);\n if (socketRecord) {\n this.#LogSillyMessage(chalk.gray(`Request end event: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`))\n this.UpdateNetworkStats(socketRecord, 'req_end', req);\n } else {\n this.#LogSillyMessage(chalk.magenta(`Request end event: Could not find socket within recordset`));\n }\n });\n\n req.on('close', () => {\n const socketRecord = this.GetSocketRecord(req.socket);\n if (socketRecord) {\n this.#LogSillyMessage(chalk.gray(`Request close event: ID: [${socketRecord.id}], originalUrl: [${socketRecord.originalUrl}]`));\n this.UpdateNetworkStats(socketRecord, 'req_close', req);\n } else {\n this.#LogSillyMessage(chalk.magenta(`Request close event: Could not find socket within recordset`));\n }\n });\n\n /* These methods are also available but from testing they provide no specific value add, i.e. the calculated numbers are always 0.\n req.on('data', () => {\n workingSocketRecord = this.GetSocketRecord(req.socket);\n if (workingSocketRecord) {\n this.#LogDebugMessage(chalk.gray(`Request close event: ID: [${workingSocketRecord.id}], originalUrl: [${workingSocketRecord.originalUrl}]`));\n this.UpdateNetworkStats(workingSocketRecord, 'data', req);\n } else {\n this.#LogDebugMessage(chalk.magenta(`Request close event: Could not find socket within recordset`));\n }\n });\n\n req.on('readable', () => {\n workingSocketRecord = this.GetSocketRecord(req.socket);\n if (workingSocketRecord) {\n this.#LogDebugMessage(chalk.gray(`Request close event: ID: [${workingSocketRecord.id}], originalUrl: [${workingSocketRecord.originalUrl}]`));\n this.UpdateNetworkStats(workingSocketRecord, 'readable', req);\n } else {\n this.#LogDebugMessage(chalk.magenta(`Request close event: Could not find socket within recordset`));\n }\n });\n */\n\n const inHeadersLength = JSON.stringify(req.headers).length;\n const inContentLength = this.#GetRequestContentSize(req);\n const inTotal = inHeadersLength + inContentLength;\n\n this.#LogSillyMessage(chalk.white.bgGray(`inHeadersLength: [${inHeadersLength}], inContentLength: [${inContentLength}], inTotal: [${inTotal}]`));\n\n // This event is the one where bytesRead is generally recorded\n this.UpdateNetworkStats(workingSocketRecord, 'middleware', req);\n\n next();\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF\nimport express, { Express, Request, Response, NextFunction } from 'express';\n\nimport cors from 'cors';\nimport cookieParser from 'cookie-parser';\n\nimport { RequestLoggerMiddleware, RequestLoggerMiddlewareEventName } from '@nsshunt/stsobservability'\n\nimport { goptions } from '@nsshunt/stsconfig'\n\nimport { IProcessBase, ProcessOptions } from './commonTypes'\nimport { Gauge, InstrumentGaugeTelemetry, InstrumentHistogramTelemetry, InstrumentVelocityTelemetry } from '@nsshunt/stsobservability'\n\nimport { ISocketRecord, ServerNetworkMiddleware, ServerNetworkMiddlewareEventName } from './middleware/serverNetworkMiddleware'\n\nexport class STSExpressServer {\n #app: Express;\n\n constructor(options: ProcessOptions, stsApp: IProcessBase)\n {\n // Standard RequestLoggerMiddleware for all STS services\n const requestLoggerMiddleware = new RequestLoggerMiddleware({ \n ignoresocketio: goptions.ignoresocketio \n });\n\n const serverNetworkMiddleware = new ServerNetworkMiddleware({ \n name: (stsApp.options as ProcessOptions).serviceName,\n outputDebug: false,\n logger: stsApp.options?.logger\n });\n\n serverNetworkMiddleware.on(ServerNetworkMiddlewareEventName.UpdateInstrument_SERVER_NET_VAL, (data: ISocketRecord) => {\n //this.#LogInfoMessage(chalk.magenta(`serverNetworkMiddleware: [${JSON.stringify(data)}]`));\n stsApp.UpdateInstrument(Gauge.NETWORK_RX_GAUGE, {\n Inc: data.requestBytesRead\n } as InstrumentGaugeTelemetry);\n\n stsApp.UpdateInstrument(Gauge.NETWORK_TX_GAUGE, {\n Inc: data.requestBytesWritten\n } as InstrumentGaugeTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_AR_INC, () => {\n stsApp.UpdateInstrument(Gauge.ACTIVE_REQUEST_GAUGE, {\n Inc: 1\n } as InstrumentGaugeTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_AR_DEC, () => {\n stsApp.UpdateInstrument(Gauge.ACTIVE_REQUEST_GAUGE, {\n Dec: 1\n } as InstrumentGaugeTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_DH_VAL, (timeInMs) => {\n stsApp.UpdateInstrument(Gauge.DURATION_HISTOGRAM_GAUGE, {\n val: timeInMs\n } as InstrumentHistogramTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_D_VAL, (timeInMs) => {\n stsApp.UpdateInstrument(Gauge.DURATION_GAUGE, {\n val: timeInMs\n } as InstrumentHistogramTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_RC_INC, () => {\n stsApp.UpdateInstrument(Gauge.REQUEST_COUNT_GAUGE, {\n Inc: 1\n } as InstrumentGaugeTelemetry);\n });\n\n requestLoggerMiddleware.on(RequestLoggerMiddlewareEventName.UpdateInstrument_V_INC, () => {\n if (stsApp.InstrumentExists(Gauge.VELOCITY_GAUGE)) {\n stsApp.UpdateInstrument(Gauge.VELOCITY_GAUGE, {\n Inc: 1\n } as InstrumentVelocityTelemetry);\n }\n });\n\n const app = express();\n this.#app = app;\n\n // https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i\n // See answer from Christoph Hansen is thread above ...\n // https://expressjs.com/en/resources/middleware/cors.html\n const corsConfig = {\n credentials: true,\n origin: true,\n };\n\n app.use(cors(corsConfig));\n\n app.use(cookieParser())\n\n app.use(express.urlencoded({ extended: false, limit: goptions.maxPayloadSize }));\n\t\t\n app.use(express.json({limit: goptions.maxPayloadSize}));\n\n // Allow the static SPA to also be servered by this app\n //app.use('/static', express.static(path.join(__dirname, 'public')))\n if (options.expressServerRouteStaticFactory) {\n options.expressServerRouteStaticFactory(app, stsApp);\n }\n\n app.use(requestLoggerMiddleware.Middleware.bind(requestLoggerMiddleware));\n\n app.use(serverNetworkMiddleware.Middleware.bind(serverNetworkMiddleware));\n\n if (options.expressServerRouteFactory) {\n options.expressServerRouteFactory(app, stsApp);\n }\n\n // Express error handling fall-back\n app.use(function(err: any, req: Request, res: Response, next: NextFunction) {\n //@@ add to errors metric here - perhaps break down by type\n\n if (err) {\n //@@this.#LogInfoMessage(err);\n res.status(err.status).send(err);\n } else {\n next();\n }\n /*\n\t\t\tif(err.name === 'UnauthorizedError') {\n\t\t\t\tres.status(401).send(err);\n\t\t\t} else {\n\t\t\t\tnext();\n\t\t\t}\n\t\t\t*/\n });\n }\n\n get App(): Express {\n return this.#app;\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0, @typescript-eslint/no-unused-vars: 0 */ // --> OFF\nimport chalk from 'chalk';\n\nimport { goptions } from '@nsshunt/stsconfig'\n\nimport fs from 'node:fs'\n\nimport { JSONObject, Sleep } from '@nsshunt/stsutils'\n\nimport { ProcessOptions, IServerProcessBase } from './../commonTypes'\nimport { ProcessBase } from './processbase';\n\nimport { register, Counter, collectDefaultMetrics, AggregatorRegistry } from 'prom-client'\n\nimport { createServer as createServerHttps } from 'node:https'\nimport { createServer } from 'node:http'\nimport tls from 'node:tls'\nimport net from 'node:net'\n\nimport { Server, ServerOptions } from \"socket.io\";\nimport { STSExpressServer } from './../stsexpressserver'\nimport { Express } from 'express'\n\nimport { createAdapter as clusterCreateAdapter } from '@socket.io/cluster-adapter'\nimport { createAdapter } from \"@socket.io/redis-streams-adapter\";\n//import { ClusterAdapterWithHeartbeat } from 'socket.io-adaptor';\n\n//import { createAdapter } from \"@socket.io/redis-adapter\";\n\nimport { createClient, RedisClientType } from 'redis';\nimport { Redis } from 'ioredis';\n\nimport jayson from 'jayson'\n\nimport { STSTransportLoggerWinston } from './../logger/stsTransportLoggerWinston'\n\n/**\n * todo\n * @typedef {Object} options - todo\n * @property {boolean} [wssServer=false] - Create a web socket server on this worker instance\n */\nexport abstract class ServerProcessBase extends ProcessBase implements IServerProcessBase\n{\n #masterProcessExitTime = goptions.masterProcessExitTime;\n #io: Server | null = null;\n #redisClient: RedisClientType | Redis | null = null;\n #httpServer: any = null;\n #expressServer: STSExpressServer | null = null;\n #sockets: net.Socket[] = [ ];\n #shuttingDown = false;\n\n constructor(options: ProcessOptions) {\n super(options);\n }\n\n get httpServer() {\n return this.#httpServer;\n }\n\n get io() {\n return this.#io;\n }\n\n get expressServer(): STSExpressServer | null {\n return this.#expressServer;\n }\n set expressServer(val: STSExpressServer | null) {\n this.#expressServer = val;\n }\n\n // Setup server to Prometheus scrapes:\n #SetupPrometheusEndPoints = (expressServer: Express) => {\n // AggregatorRegistry is required here in the worker as well as the master in order for prom-client to work correctly.\n new AggregatorRegistry();\n\n const prefix = 'sts_';\n\n collectDefaultMetrics({\n labels: { NODE_APP_INSTANCE: process.pid },\n prefix: prefix\n });\n\n const c = new Counter({\n name: 'sts_test_counter',\n help: 'Example of a counter',\n labelNames: ['code'],\n });\n\n setInterval(() => {\n c.inc({ code: 200 });\n }, 1000).unref();\n\n setInterval(() => {\n c.inc({ code: 400 });\n c.inc({ code: 'worker_' + process.pid });\n }, 500).unref();\n\n expressServer.get('/metrics', async (req: any, res: any) => {\n try {\n res.set('Content-Type', register.contentType);\n res.end(await register.metrics());\n } catch (ex) {\n res.status(500).end(ex);\n }\n });\n\n expressServer.get('/metrics/counter', async (req: any, res: any) => {\n try {\n res.set('Content-Type', register.contentType);\n res.end(await register.getSingleMetricAsString('test_counter'));\n } catch (ex) {\n res.status(500).end(ex);\n }\n });\n }\n\n #SetupTLSServer = async (socket: net.Socket): Promise<void> => {\n // Add a 'close' event handler to this instance of socket\n this.LogInfoMessage('CONNECTED: ' + socket.remoteAddress + ':' + socket.remotePort + ' ' + process.pid);\n this.#sockets.push(socket);\n\n //const self = this;\n socket.on('close', (data: any) => {\n const index = this.#sockets.findIndex(function(o) {\n return o.remoteAddress === socket.remoteAddress && o.remotePort === socket.remotePort;\n })\n if (index !== -1) this.#sockets.splice(index, 1);\n this.LogInfoMessage('CLOSED: ' + socket.remoteAddress + ' ' + socket.remotePort + ' ' + process.pid);\n });\n\n socket.on('data', (data: any) => {\n this.LogInfoMessage('DATA ' + socket.remoteAddress + ': ' + socket.remotePort + ': ' + data);\n socket.write(socket.remoteAddress + ':' + socket.remotePort + \" said \" + data + '\\n');\n\n // Write the data back to all the connected, the client will receive it as data from the server\n /*\n self.#sockets.forEach(function(socket, index, array) {\n socket.write(socket.remoteAddress + ':' + socket.remotePort + \" said \" + data + '\\n');\n });\n\n */\n });\n }\n\n #SetupRPCServer = async (socket: net.Socket): Promise<void> => {\n this.LogInfoMessage('CONNECTED: ' + socket.remoteAddress + ':' + socket.remotePort + ' ' + process.pid);\n\n socket.on('close', (data: any) => {\n this.LogInfoMessage('CLOSED: ' + socket.remoteAddress + ' ' + socket.remotePort + ' ' + process.pid);\n });\n\n socket.on('data', (data: any) => {\n this.LogInfoMessage('DATA ' + socket.remoteAddress + ': ' + data);\n });\n }\n\n #SetupWSSServer = async (): Promise<void> => {\n // socket.io\n // WebSocket\n const options: Partial<ServerOptions> = {\n transports: [ \"websocket\" ] // or [ \"websocket\", \"polling\" ] (to use long-poolling. Note that the order matters)\n // The default path is /socket.io\n // This can be changed with the path option as shown below\n //,path: '/zzz'\n };\n\n //this.#io = require(\"socket.io\")(this.#httpServer, options);\n this.#io = new Server(this.#httpServer, options);\n\n if (this.options.useSocketIoRedisAdaptor) {\n this.LogInfoMessage(`Using Redis for socket.io cluster management (worker)`);\n if (this.options.socketIoRedisAdaptorUrl) {\n this.LogInfoMessage(`Redis url: [${this.options.socketIoRedisAdaptorUrl}]`);\n this.#redisClient = createClient({url: this.options.socketIoRedisAdaptorUrl});\n } else {\n this.LogInfoMessage(`Redis url: [localhost]`);\n this.#redisClient = createClient();\n }\n await this.#redisClient.connect();\n\n //this.#redisClient = new Redis(this.options.socketIoRedisAdaptorUrl as string);\n\n this.#io.adapter(createAdapter(this.#redisClient));\n\n this.LogInfoMessage(`Redis successfully connected.`);\n } else {\n if (this.options.clusterMode) {\n this.#io.adapter(clusterCreateAdapter() as any);\n this.LogInfoMessage(`Using nodejs cluster mode for socket.io cluster management`);\n } else {\n this.LogInfoMessage(`Not using any adaptors for socket.io cluster management.}`);\n }\n }\n\n // To use a seperate socket server, the code below can be applied.\n // this.#io = require(\"socket.io\")(options);\n // this.#io.adapter(createAdapter());\n // this.#io.listen(3006);\n\n this.#io.engine.on(\"connection_error\", (err) => {\n this.LogInfoMessage(err.req); // the request object\n this.LogInfoMessage(err.code); // the error code, for example 1\n this.LogInfoMessage(err.message); // the error message, for example \"Session ID unknown\"\n this.LogInfoMessage(err.context); // some additional error context\n });\n }\n\n #GetTLSOptions = (): JSONObject => {\n return {\n key: fs.readFileSync(this.options.httpsServerKeyPath),\n cert: fs.readFileSync(this.options.httpsServerCertificatePath)\n };\n }\n\n #SetupExpressServer = async (useTls: boolean): Promise<void> => {\n if (useTls) {\n this.#httpServer = createServerHttps(this.#GetTLSOptions(), (this.#expressServer as STSExpressServer).App);\n } else {\n this.#httpServer = createServer((this.#expressServer as STSExpressServer).App);\n }\n if (this.options.prometheusSupport === true) {\n this.#SetupPrometheusEndPoints((this.#expressServer as STSExpressServer).App);\n }\n if (this.options.wssServer === true) {\n await this.#SetupWSSServer();\n }\n // https://stackoverflow.com/questions/21342828/node-express-unix-domain-socket-permissions\n //@@httpServer.listen('/tmp/stsrest01.sock').on('listening', () =>\n //@@httpServer.listen('/var/run/sts/stsrest01.sock').on('listening', () =>\n this.#httpServer.listen(this.options.listenPort, () => { \n //@@chmodSync(this.options.port, 511);\n }).on('listening', () => {\n this.LogInfoMessage(`live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);\n });\n }\n\n #SetupTCPRawServer = async (): Promise<void> => {\n // The second parameter is the automatic listener for the secureConnection event from the tls.Server class\n this.#httpServer = tls.createServer(this.#GetTLSOptions(), this.#SetupTLSServer);\n this.#httpServer.listen(this.options.listenPort, 'stscore.stsmda.org', () => { \n this.LogInfoMessage('TCP Server is running on port ' + this.options.listenPort + '.');\n }).on('listening', () => {\n this.LogInfoMessage(`TCP live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);\n });\n }\n\n #SetupJSONRPCServer = async (): Promise<void> => {\n const jaysonServer = new jayson.server();\n // Supported methods here - move somewhere else ...\n jaysonServer.method(\"add\", function(args: any, callback: any) {\n callback(null, args[0] + args[1]);\n });\n this.#httpServer = jaysonServer.tls(this.#GetTLSOptions());\n (this.#httpServer as tls.Server).on('secureConnection', this.#SetupRPCServer);\n this.#httpServer.listen(this.options.listenPort, 'stscore.stsmda.org', () => { \n this.LogInfoMessage('JSON RPC 2.0 Server is running on port ' + this.options.listenPort + '.');\n }).on('listening', () => {\n this.LogInfoMessage(`JSON RPC 2.0 live on ${this.options.endpoint}:${this.options.listenPort}${this.options.apiRoot}`);\n });\n }\n\n override get shuttingDown(): boolean {\n return this.#shuttingDown;\n }\n\n TerminateSocketIO = async (): Promise<void> => {\n if (this.options.wssServer === true && this.#io !== null) {\n const logPrefix = `ServerProcessBase:TerminateSockets():${process.pid}:`;\n this.LogInfoMessage(`${logPrefix} Disconnect SocketIO Sockets.`);\n await Sleep(250);\n await this.#io?.of('/').adapter.close();\n if (this.socketIoServerHelper !== null) {\n await this.socketIoServerHelper.CloseAdaptors();\n await Sleep(50);\n if (this.#redisClient) {\n this.#redisClient.disconnect();\n await Sleep(50);\n }\n this.LogInfoMessage(`${logPrefix} this.socketIoServerHelper.DisconnectSockets()`);\n await this.socketIoServerHelper.DisconnectSockets();\n } else {\n this.LogInfoMessage(`${logPrefix} this.#io.disconnectSockets()`);\n if (this.#redisClient) {\n this.#redisClient.disconnect();\n await Sleep(50);\n }\n this.#io.disconnectSockets();\n }\n this.socketIoServerHelper = null;\n this.#io = null;\n }\n }\n\n TerminateHTTPServer = async (): Promise<void> => {\n const logPrefix = `ServerProcessBase:TerminateHTTPServer():${process.pid}:`;\n if (this.#httpServer !== null) {\n if (goptions.STSServerType.localeCompare('TCPRAW_TLS') === 0) {\n this.#sockets.forEach((socket: net.Socket, index, array) => {\n this.LogInfoMessage(chalk.yellow(`${logPrefix} TCP Socket destroy, remote address: [${socket.remoteAddress}], remote port: [${socket.remotePort}]`));\n socket.destroy();\n //socket.end();\n });\n }\n this.LogInfoMessage(`${logPrefix} Closing httpServer.`);\n await this.#httpServer.close();\n this.#httpServer = null;\n }\n }\n\n // Terminate in order;\n // forked worker threads (send signal)\n // De-Register service\n // systeminformation observers\n // instrument timers (gauge etc.)\n // publisher\n // terminate UI (if loaded)\n Terminate = async (clusterPerformExit: boolean, signal?: any): Promise<void> => {\n const logPrefix = `ServerProcessBase:Terminate():${process.pid}:`;\n if (this.#shuttingDown === false) {\n this.#shuttingDown = true;\n\n if (signal) {\n this.LogInfoMessage(this.GetSignalColour(signal)(`${logPrefix} Received signal: ${signal}`));\n } else {\n this.LogInfoMessage(this.GetSignalColour(null)(`${logPrefix} Received Terminate without signal.`));\n }\n\n await this.ProcessTerminate();\n\n this.TerminateUIController();\n\n await this.TerminateSocketIO();\n\n await this.TerminateHTTPServer();\n \n await this.TerminateDatabase();\n\n // Output final messages here (before TerminateInstrumentController)\n if (this.options.clusterMode) {\n this.LogInfoMessage(`${logPrefix} clusterPerformExit value: [${clusterPerformExit}]`);\n if (clusterPerformExit) {\n this.LogInfoMessage(`${logPrefix} Process will self terminate with process.exit(0).`);\n } else {\n this.LogInfoMessage(`${logPrefix} Child process will not self terminate. Terminate will be handled by master process.`);\n }\n }\n\n this.TerminateInstrumentController();\n\n //@@ always return here appears to always cleanly exit\n // and cleanly exit from socket.io cluster adaptor\n // without return here, socket.io cluster adaptor terminates in an error state\n // as the implementation relies on cluster.on to send messages to worker threads\n // but these have already been closed from the process.exit(0) below.\n\n await Sleep(1000); // Allow socket.io time to clean-up\n\n if (this.options.clusterMode === true) {\n if (clusterPerformExit === true) {\n setTimeout(() => {\n process.exit(0);\n }, 0);\n } \n } else {\n this.ProcessExit(this.#masterProcessExitTime);\n }\n } else {\n this.LogInfoMessage(`${logPrefix} Process already terminating.`);\n }\n }\n\n async SetupServer(): Promise<boolean> {\n return new Promise((resolve, reject) => {\n try {\n this.SetupInstrumentation();\n setTimeout(async () => {\n try {\n await this.SetupServerEx();\n resolve(true);\n } catch (error) {\n reject(error);\n }\n }, 100);\n } catch (error) {\n reject(error);\n }\n })\n }\n\n ProcessStarted() {\n const transport = new STSTransportLoggerWinston({\n stsApp: this\n });\n setTimeout(() => {\n (this.options.logger as any).add(transport);\n }, 0);\n }\n\n async SetupServerEx(): Promise<boolean> {\n this.LogInfoMessage(chalk.green(`ServerProcessBase:SetupServerEx(): Main Process:${process.pid} Starting ...`));\n\n this.ProcessStartup();\n\n if (this.options.expressServerRouteFactory || this.options.expressServerRouteStaticFactory) {\n this.expressServer = new STSExpressServer(this.options, this);\n }\n\n this.LogInfoMessage(`ServerProcessBase:SetupServerEx(): Worker instance starting. Service instance Id: [${this.options.serviceInstanceId}]`);\n\n // Signal Codes\n // https://en.wikipedia.org/wiki/Signal_(IPC)\n process.on('SIGTERM', async () => {\n this.LogInfoMessage(`ServerProcessBase:SetupServerEx(): SIGTERM signal received for worker: ${process.pid}`);\n await this.Terminate(true, true);\n });\n\n process.on('SIGINT', async () => {\n this.LogInfoMessage(`ServerProcessBase:SetupServerEx(): SIGINT signal received for worker: ${process.pid}`);\n await this.Terminate(true, true);\n });\n\n process.on('exit', (code) => {\n if (code === 0) {\n this.LogInfoMessage(chalk.green(`ServerProcessBase:SetupServerEx(): Process: ${process.pid} terminated gracefully with code: ${code}`));\n } else {\n this.LogInfoMessage(chalk.red(`ServerProcessBase:SetupServerEx(): Process: ${process.pid} terminated with code: ${code}`));\n }\n });\n\n await this.SetupSTSServer();\n \n this.ProcessStarted();\n\n this.LogInfoMessage(chalk.green(`ServerProcessBase:SetupServerEx(): Main Process:${process.pid} Started`));\n\n return true;\n };\n\n SetupSTSServer = async(): Promise<void> => {\n switch (goptions.STSServerType) {\n case 'EXPRESS' :\n await this.#SetupExpressServer(false);\n break;\n case 'EXPRESS_TLS' :\n await this.#SetupExpressServer(true);\n break;\n case 'TCPRAW_TLS' :\n await this.#SetupTCPRawServer();\n break;\n case 'JSONRPC2_TLS' :\n await this.#SetupJSONRPCServer();\n break;\n }\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport { goptions } from '@nsshunt/stsconfig'\n\nimport { Gauge, GaugeTypes, InstrumentGaugeOptions, InstrumentGaugeTelemetry } from '@nsshunt/stsobservability'\n\nimport { ISingleProcessBase, ProcessOptions } from './../commonTypes';\nimport { InstrumentDefinitions } from '@nsshunt/stsobservability'\nimport { ServerProcessBase } from './serverprocessbase'\n\nimport si from 'systeminformation' // https://systeminformation.io/\n\nexport type EventCb = (socket: any, data: any) => void\n\nexport class SingleProcessBase extends ServerProcessBase implements ISingleProcessBase\n{\n /**\n\t * \n\t * @param {SingleProcessBaseOptions} options \n\t */\n constructor(options: ProcessOptions) {\n super(options)\n }\n\n override CollectAdditionalTelemetry(): void {\n const siValueObject = {\n currentLoad: 'currentLoad'\n }\n si.get(siValueObject).then(data => {\n this.UpdateInstrument(Gauge.CPU_SYSTEM_LOAD_GAUGE, {\n val: data.currentLoad.currentLoad\n } as InstrumentGaugeTelemetry);\n });\n }\n\n override GetAdditionalInstruments(): InstrumentDefinitions {\n return [\n [ Gauge.CPU_SYSTEM_LOAD_GAUGE, GaugeTypes.INSTRUMENT_GAUGE, {\n interval: goptions.instrumentationObservationInterval, \n sampleSize: goptions.instrumentationTimeWindow\n } as InstrumentGaugeOptions]\n ]\n }\n\n /**\n\t * UIController (instance of UIController) to manage a console based user interface associated for this node application.\n\t * @returns UIController instance to manage a console based user interface associated for this node application. Null for no capability.\n\t */\n override GetUIController(): any {\n return null;\n }\n\n override SetupServerEx = async (): Promise<boolean> => {\n await super.SetupServerEx();\n\n this.LogSystemTelemetry();\n\n return true;\n }\n\n async TerminateApplication() {\n await this.Terminate(false, 'SIGINT');\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport chalk from 'chalk';\n\nimport { Gauge, InstrumentGaugeTelemetry } from '@nsshunt/stsobservability'\nimport { JSONObject } from '@nsshunt/stsutils'\nimport { IPCMessage, IPCMessages, IPCMessagePayload, IPCMessageCommand, IWorkerProcessBase, ProcessOptions } from './../commonTypes'\nimport { ServerProcessBase } from './serverprocessbase'\n\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { goptions } from '@nsshunt/stsconfig'\n\nimport si from 'systeminformation' // https://systeminformation.io/\nimport { GetFirstNetworkInterface } from './../network'\n\n/**\n * todo\n * @typedef {Object} options - todo\n * @property {boolean} [wssServer=false] - Create a web socket server on this worker instance\n */\nexport class WorkerProcessBase extends ServerProcessBase implements IWorkerProcessBase {\n #inFlightMessage: IPCMessages = { }\n #requestResponseMessageTimeout = 5000; //@@ config\n #pingTimeout: NodeJS.Timeout | null = null;\n\n constructor(options: ProcessOptions) {\n super(options);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ReceivedMessageFromMaster(msg: any) {\n // Override in subclass if required\n }\n\n override CollectAdditionalTelemetry(): void {\n this.httpServer.getConnections((error: any, count: any) => {\n //@@this.instruments[Gauge.CONNECTION_COUNT_GAUGE].val = count;\n this.UpdateInstrument(Gauge.CONNECTION_COUNT_GAUGE, {\n val: count\n } as InstrumentGaugeTelemetry);\n });\n }\n\n #SendMessageToParentProcess = (message: IPCMessagePayload): Promise<JSONObject> => {\n return new Promise((resolve, reject) => {\n if (this.#inFlightMessage[message.id]) {\n reject(`Message with id: [${message.id}] already exists within the Request/Response record structure`);\n } else {\n this.#inFlightMessage[message.id] = {\n iPCMessagePayload: { ...message },\n cb: () => {\n const detail: JSONObject = this.#inFlightMessage[message.id].iPCMessagePayload.responseDetail as JSONObject\n clearTimeout(this.#inFlightMessage[message.id].timeout);\n setTimeout(() => {\n delete this.#inFlightMessage[message.id];\n }, 0).unref();\n //this.#LogDebugMessage(chalk.green(`Resolving response message with id: [${message.id}] from parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));\n resolve(detail);\n },\n timeout: setTimeout(() => {\n setTimeout(() => {\n delete this.#inFlightMessage[message.id];\n }, 0).unref();\n //this.#LogDebugMessage(chalk.red(`Timeout has occurred after: [${this.#requestResponseMessageTimeout}]ms with message id: [${message.id}]. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));\n reject('Did not receive response form parent process.');\n }, this.#requestResponseMessageTimeout) // max message timeout allowed\n };\n //this.#LogDebugMessage(chalk.yellow(`Sending message with id: [${message.id}] to parent process via IPC. Details: [${JSON.stringify(this.#inFlightMessage[message.id].iPCMessagePayload)}]`));\n (process as any).send(message);\n }\n });\n }\n\n \n AddWorker = async (options: any): Promise<string> => {\n const workerResponse: JSONObject = await this.#SendMessageToParentProcess({\n requestResponse: true,\n id: uuidv4(),\n command: IPCMessageCommand.AddWorker,\n requestDetail: {\n options\n }\n });\n return workerResponse.workerId;\n }\n \n DeleteWorker = async (workerId: string, options: any): Promise<JSONObject> => {\n const workerResponse: JSONObject = await this.#SendMessageToParentProcess({\n requestResponse: true,\n id: uuidv4(),\n command: IPCMessageCommand.DeleteWorker,\n requestDetail: {\n options,\n workerId\n }\n });\n return workerResponse;\n }\n\n GetMasterProcessOptions = async (): Promise<JSONObject> => {\n const parentResponse: JSONObject = await this.#SendMessageToParentProcess({\n requestResponse: true,\n id: uuidv4(),\n command: IPCMessageCommand.GetConfig,\n requestDetail: { }\n });\n return parentResponse;\n }\n\n GetNumCPUs = async (): Promise<number> => {\n // https://systeminformation.io/\n const valueObject = {\n cpu: '*'\n }\n \n const sysinfo = await si.get(valueObject);\n let numCPUs = 2;\n if (goptions.useCPUs > 0) {\n if (goptions.useCPUs >= 1) {\n numCPUs = goptions.useCPUs;\n } else {\n numCPUs = Math.round(sysinfo.cpu.cores * goptions.useCPUs);\n }\n } else {\n numCPUs = sysinfo.cpu.physicalCores;\n }\n return numCPUs;\n }\n\n GetSystemTelemetry = async () => {\n // https://systeminformation.io/\n const valueObject = {\n system: '*',\n osInfo: '*',\n cpu: '*',\n mem: '*',\n dockerInfo: '*',\n //dockerImages: '*',\n dockerContainers: '*',\n }\n \n const sysinfo = await si.get(valueObject);\n const numCPUs = await this.GetNumCPUs();\n const hostname = sysinfo.osInfo.hostname;\n const hostaddr = GetFirstNetworkInterface();\n\n const promArray: Promise<any>[] = [ ];\n \n sysinfo.dockerContainers.forEach((dc: { id: string; }) => {\n const dcs = promArray.push(si.dockerContainerStats(dc.id));\n console.log(dcs);\n });\n const dockerContainerStats = await Promise.all(promArray);\n \n const sysInfo = {\n serviceInstanceId: this.options.serviceInstanceId,\n serviceProcessContext: this.options.serviceProcessContext,\n hostname,\n numCPUs,\n hostaddr,\n system: sysinfo.system,\n osInfo: sysinfo.osInfo,\n cpu: sysinfo.cpu,\n mem: sysinfo.mem,\n dockerInfo: sysinfo.dockerInfo,\n dockerContainers: sysinfo.dockerContainers,\n dockerContainerStats\n }\n\n return sysInfo;\n }\n\n override SetupServerEx = async (): Promise<boolean> => {\n await super.SetupServerEx();\n\n process.on('message', async (msg: any) => {\n if (msg.requestResponse) {\n const iPCMessagePayload: IPCMessagePayload = msg as IPCMessagePayload;\n if (iPCMessagePayload.id) {\n if (this.#inFlightMessage[iPCMessagePayload.id]) {\n const responseMessage: IPCMessage = this.#inFlightMessage[iPCMessagePayload.id];\n responseMessage.iPCMessagePayload.responseDetail = { ...iPCMessagePayload.responseDetail }\n responseMessage.cb();\n } else {\n throw new Error(`Could not find Request/Response message with id: [${iPCMessagePayload.id}]`);\n }\n } else {\n throw new Error(`Message does not have id attribute. [${JSON.stringify(iPCMessagePayload)}]`);\n }\n return;\n }\n if (msg.command) //@@ constants\n {\n switch (msg.command)\n {\n case 'Terminate' :\n this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Terminate`) + ` message from master thread`));\n await this.Terminate(true, false); // Don't kill the child process here, the master will take care of that ...\n break;\n case 'TerminateAndKill' :\n this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Terminate`) + ` message from master thread`));\n await this.Terminate(true, true);\n break;\n case 'Message' :\n //this.LogInfoMessage(chalk.grey(`Received ` + chalk.bold.italic(`Message`) + ` message from master thread`));\n this.ReceivedMessageFromMaster(msg.data);\n break;\n case 'Response' : // General response to a req/response interaction\n //msg.details\n }\n }\n });\n\n return true;\n };\n\n override ProcessTerminate(): Promise<void> {\n //this.#redisMessageHandler?.off()\n if (this.#pingTimeout) {\n clearTimeout(this.#pingTimeout);\n }\n return super.ProcessTerminate();\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport { IProcessBase } from './../commonTypes';\n\nexport abstract class STSControllerBase {\n #stsApp: any;\n\n constructor(stsApp: IProcessBase) {\n this.#stsApp = stsApp;\n }\n\n get stsApp(): IProcessBase {\n return this.#stsApp\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport { StatusCodes } from 'http-status-codes'\nimport { STSControllerBase } from './stscontrollerbase'\nimport { IProcessBase } from './../commonTypes'\n\nexport class STSLatencyController extends STSControllerBase {\n constructor(stsApp: IProcessBase) {\n super(stsApp);\n }\n\n // curl http://localhost:3000/api/v1/latency/latency\n async stslatency(req: any, res: any)\n {\n try {\n const retVal = { \n data: `Ping Completed At: ${Date.now()}`,\n pid: process.pid,\n ppid: process.ppid\n };\n return res.status(StatusCodes.OK).send(retVal);\n } catch (error) {\n this.stsApp.LogErrorMessage(error);\n return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( { status: StatusCodes.INTERNAL_SERVER_ERROR, error: 'Operation was not successful', detail: error } );\n }\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport { Router } from 'express';\nimport { IProcessBase } from './../commonTypes';\n\nexport abstract class STSRouterBase {\n #router: Router;\n #stsApp: any;\n\n constructor(stsApp: IProcessBase) {\n this.#stsApp = stsApp;\n this.#router = Router();\n }\n\n get router(): Router {\n return this.#router;\n }\n\n get stsApp(): IProcessBase {\n return this.#stsApp\n }\n}\n","import { STSRouterBase } from './stsrouterbase'\nimport { STSLatencyController } from './../controller/stslatencycontroller'\nimport { IProcessBase } from './../commonTypes'\n\nexport class STSLatencyRoute extends STSRouterBase {\n constructor(stsApp: IProcessBase)\n {\n super(stsApp);\n\n const latencyController = new STSLatencyController(stsApp);\n const { stslatency } = latencyController;\n\n this.router.get('/latency', stslatency.bind(latencyController)); // Create new test\n }\n}\n","import { ModelDelimeter } from '@nsshunt/stsutils'\nimport { IServiceProcessContext } from './../commonTypes'\n\nexport class PublishTransportUtils\n{\n static GetServiceContext(nid: string): IServiceProcessContext {\n // Return null if no context is required\n //return null;\n if (nid === ModelDelimeter.ROOT) {\n return { root: ModelDelimeter.ROOT };\n }\n const context: IServiceProcessContext = { nid };\n const idsplit = nid.split(ModelDelimeter.SEPERATOR);\n\n const serviceId = idsplit[0];\n const serviceInstanceId = idsplit[1].split(ModelDelimeter.NID_SEPERATOR)[0];\n const serviceInstanceProcessId = idsplit[1].split(ModelDelimeter.NID_SEPERATOR)[1];\n\n const serviceIdSplit = serviceId.split(ModelDelimeter.COMPONENT_SEPERATOR);\n const serviceName =serviceIdSplit[0]; // Defined in .env or environment variable\n const serviceVersion = serviceIdSplit[1]; // Defined in .env or environment variable\n\n context.serviceId = serviceId; // Service name and the service version\n\n if (typeof serviceInstanceId != 'undefined') {\n const serviceInstanceIdSplit = serviceInstanceId.split(ModelDelimeter.COMPONENT_SEPERATOR);\n const sid = serviceInstanceIdSplit[0];\n const hostName = serviceInstanceIdSplit[1];\n\n context.serviceInstanceId = serviceInstanceId; // Service unique id and the host name\n context.sid = sid; // Service unique id only, does not include host\n context.hostName = hostName; // Service Instance Host Name\n\n if (typeof serviceInstanceProcessId != 'undefined') {\n const serviceInstanceProcessIdSplit = serviceInstanceProcessId.split(ModelDelimeter.COMPONENT_SEPERATOR);\n const pid = parseInt(serviceInstanceProcessIdSplit[0]);\n const ppid = parseInt(serviceInstanceProcessIdSplit[1]);\n const isMaster = (pid === ppid ? true : false);\n\n context.serviceInstanceProcessId = serviceInstanceProcessId; // Service Instance OS Process ID (parent process id)\n context.pid = pid; // Service Instance OS Process ID (parent process id)\n context.ppid = ppid; // Service Instance OS Parent Process ID if worker. Will be pid if parent process.\n context.isMaster = isMaster; // True if is Master Process\n context.isWorker = !isMaster; // True if is Worker Process\n context.serviceName = serviceName; // Defined in .env or environment variable\n context.serviceVersion = serviceVersion; // Defined in .env or environment variable\n context.serviceInstanceId = serviceInstanceId; // unique service id with host\n }\n }\n\n return context;\n }\n}\n","/* eslint @typescript-eslint/no-explicit-any: 0 */ // --> OFF\nimport Transport, { TransportStreamOptions } from 'winston-transport'\n\nimport debugModule from 'debug'\n\nexport interface ISTSTransportWinstonOptions extends TransportStreamOptions {\n stsContext: string\n debugger?: debugModule.Debugger\n}\n\nexport function UpdateSTSTransportWithDebugger(logger: any, newDebugger: any): void {\n const stsTransport: Transport | undefined = logger.transports.find((transport: any) => {\n return transport instanceof STSTransportWinston\n });\n if (stsTransport) {\n (stsTransport as STSTransportWinston).debugger = newDebugger\n }\n}\n\nexport class STSTransportWinston extends Transport {\n\n #options: ISTSTransportWinstonOptions;\n\n constructor(opts: ISTSTransportWinstonOptions) {\n super(opts);\n this.#options = opts;\n }\n\n get debugger() : debugModule.Debugger | undefined {\n return this.#options.debugger;\n }\n\n set debugger(newDebugger: debugModule.Debugger) {\n this.#options.debugger = newDebugger;\n }\n \n log(info: any, callback: any) {\n //setImmediate(() => {\n if (info[Symbol.for('level')] == 'debug') {\n if (this.#options.debugger) {\n this.#options.debugger(info.message);\n }\n }\n this.emit('logged', info);\n callback();\n //});\n }\n}\n"],"names":["IPCMessageCommand","_options","worker","createServerHttps","ServerNetworkMiddlewareEventName","LogErrorMessage_fn","uuidv4","_masterProcessExitTime","_httpServer","_shuttingDown","clusterCreateAdapter","_stsApp"],"mappings":"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"}