@uns-kit/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/dist/app-config.d.ts +177 -0
  4. package/dist/app-config.js +1 -0
  5. package/dist/base-path.d.ts +1 -0
  6. package/dist/base-path.js +5 -0
  7. package/dist/config/project.config.extension.d.ts +3 -0
  8. package/dist/config/project.config.extension.js +3 -0
  9. package/dist/config-file.d.ts +12 -0
  10. package/dist/config-file.js +44 -0
  11. package/dist/examples/data-example.d.ts +1 -0
  12. package/dist/examples/data-example.js +44 -0
  13. package/dist/examples/load-test-data.d.ts +1 -0
  14. package/dist/examples/load-test-data.js +72 -0
  15. package/dist/examples/table-example.d.ts +4 -0
  16. package/dist/examples/table-example.js +52 -0
  17. package/dist/examples/uns-gateway.d.ts +1 -0
  18. package/dist/examples/uns-gateway.js +5 -0
  19. package/dist/graphql/schema.d.ts +377 -0
  20. package/dist/graphql/schema.js +13 -0
  21. package/dist/index.d.ts +5 -0
  22. package/dist/index.js +4 -0
  23. package/dist/logger.d.ts +2 -0
  24. package/dist/logger.js +18 -0
  25. package/dist/tools/auth/auth-client.d.ts +23 -0
  26. package/dist/tools/auth/auth-client.js +172 -0
  27. package/dist/tools/auth/index.d.ts +1 -0
  28. package/dist/tools/auth/index.js +1 -0
  29. package/dist/tools/auth/secure-store.d.ts +17 -0
  30. package/dist/tools/auth/secure-store.js +110 -0
  31. package/dist/tools/base-path.d.ts +1 -0
  32. package/dist/tools/base-path.js +5 -0
  33. package/dist/tools/generate-config-schema.d.ts +1 -0
  34. package/dist/tools/generate-config-schema.js +23 -0
  35. package/dist/tools/initialize.d.ts +1 -0
  36. package/dist/tools/initialize.js +103 -0
  37. package/dist/tools/make.d.ts +1 -0
  38. package/dist/tools/make.js +27 -0
  39. package/dist/tools/pull-request.d.ts +1 -0
  40. package/dist/tools/pull-request.js +157 -0
  41. package/dist/tools/refresh-uns.d.ts +1 -0
  42. package/dist/tools/refresh-uns.js +109 -0
  43. package/dist/tools/schema.d.ts +208 -0
  44. package/dist/tools/schema.js +1 -0
  45. package/dist/tools/update-rtt.d.ts +1 -0
  46. package/dist/tools/update-rtt.js +169 -0
  47. package/dist/tools/update-tools.d.ts +1 -0
  48. package/dist/tools/update-tools.js +72 -0
  49. package/dist/uns/handover-manager-event-emitter.d.ts +6 -0
  50. package/dist/uns/handover-manager-event-emitter.js +19 -0
  51. package/dist/uns/handover-manager.d.ts +34 -0
  52. package/dist/uns/handover-manager.js +227 -0
  53. package/dist/uns/process-config.d.ts +10 -0
  54. package/dist/uns/process-config.js +12 -0
  55. package/dist/uns/process-name-service.d.ts +7 -0
  56. package/dist/uns/process-name-service.js +28 -0
  57. package/dist/uns/status-monitor.d.ts +35 -0
  58. package/dist/uns/status-monitor.js +82 -0
  59. package/dist/uns/uns-event-emitter.d.ts +6 -0
  60. package/dist/uns/uns-event-emitter.js +19 -0
  61. package/dist/uns/uns-interfaces.d.ts +156 -0
  62. package/dist/uns/uns-interfaces.js +5 -0
  63. package/dist/uns/uns-measurements.d.ts +95 -0
  64. package/dist/uns/uns-measurements.js +146 -0
  65. package/dist/uns/uns-packet.d.ts +28 -0
  66. package/dist/uns/uns-packet.js +223 -0
  67. package/dist/uns/uns-proxy-process.d.ts +56 -0
  68. package/dist/uns/uns-proxy-process.js +179 -0
  69. package/dist/uns/uns-proxy.d.ts +31 -0
  70. package/dist/uns/uns-proxy.js +120 -0
  71. package/dist/uns/uns-tags.d.ts +1 -0
  72. package/dist/uns/uns-tags.js +1 -0
  73. package/dist/uns/uns-topic-matcher.d.ts +9 -0
  74. package/dist/uns/uns-topic-matcher.js +34 -0
  75. package/dist/uns/uns-topics.d.ts +1 -0
  76. package/dist/uns/uns-topics.js +1 -0
  77. package/dist/uns-config/config-schema.d.ts +7 -0
  78. package/dist/uns-config/config-schema.js +5 -0
  79. package/dist/uns-config/host-placeholders.d.ts +139 -0
  80. package/dist/uns-config/host-placeholders.js +70 -0
  81. package/dist/uns-config/schema-tolls.d.ts +2 -0
  82. package/dist/uns-config/schema-tolls.js +4 -0
  83. package/dist/uns-config/schema-tools.d.ts +2 -0
  84. package/dist/uns-config/schema-tools.js +18 -0
  85. package/dist/uns-config/secret-placeholders.d.ts +128 -0
  86. package/dist/uns-config/secret-placeholders.js +64 -0
  87. package/dist/uns-config/secret-resolver.d.ts +77 -0
  88. package/dist/uns-config/secret-resolver.js +285 -0
  89. package/dist/uns-config/uns-core-schema.d.ts +705 -0
  90. package/dist/uns-config/uns-core-schema.js +25 -0
  91. package/dist/uns-grpc/uns-gateway-cli.d.ts +2 -0
  92. package/dist/uns-grpc/uns-gateway-cli.js +32 -0
  93. package/dist/uns-grpc/uns-gateway-server.d.ts +47 -0
  94. package/dist/uns-grpc/uns-gateway-server.js +424 -0
  95. package/dist/uns-mqtt/mqtt-interfaces.d.ts +22 -0
  96. package/dist/uns-mqtt/mqtt-interfaces.js +1 -0
  97. package/dist/uns-mqtt/mqtt-proxy.d.ts +34 -0
  98. package/dist/uns-mqtt/mqtt-proxy.js +245 -0
  99. package/dist/uns-mqtt/mqtt-topic-builder.d.ts +51 -0
  100. package/dist/uns-mqtt/mqtt-topic-builder.js +70 -0
  101. package/dist/uns-mqtt/mqtt-worker-init.d.ts +1 -0
  102. package/dist/uns-mqtt/mqtt-worker-init.js +5 -0
  103. package/dist/uns-mqtt/mqtt-worker.d.ts +20 -0
  104. package/dist/uns-mqtt/mqtt-worker.js +120 -0
  105. package/dist/uns-mqtt/throttled-queue.d.ts +166 -0
  106. package/dist/uns-mqtt/throttled-queue.js +388 -0
  107. package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +107 -0
  108. package/dist/uns-mqtt/uns-mqtt-proxy.js +349 -0
  109. package/dist/uns-mqtt/ws-proxy.d.ts +38 -0
  110. package/dist/uns-mqtt/ws-proxy.js +86 -0
  111. package/package.json +48 -0
@@ -0,0 +1,227 @@
1
+ import logger from "../logger.js";
2
+ import { HandoverManagerEventEmitter } from "./handover-manager-event-emitter.js";
3
+ import { MqttTopicBuilder } from "../uns-mqtt/mqtt-topic-builder.js";
4
+ import { ACTIVE_TIMEOUT, PACKAGE_INFO } from "./process-config.js";
5
+ /**
6
+ * HandoverManager is responsible for all handover-related logic,
7
+ * including handling incoming MQTT messages, issuing handover requests,
8
+ * and processing handover responses.
9
+ */
10
+ export class HandoverManager {
11
+ event = new HandoverManagerEventEmitter();
12
+ processName;
13
+ mqttProxy;
14
+ unsMqttProxies;
15
+ requestingHandover = false;
16
+ handoverInProgress = false;
17
+ topicBuilder;
18
+ activeTimeout;
19
+ active = false;
20
+ handoverRequestEnabled = false;
21
+ handoverEnabled = true;
22
+ forceStartEnabled = false;
23
+ constructor(processName, mqttProxy, unsMqttProxies, handoverRequestEnabled, handoverEnabled, forceStartEnabled) {
24
+ this.processName = processName;
25
+ this.mqttProxy = mqttProxy;
26
+ this.unsMqttProxies = unsMqttProxies;
27
+ this.handoverRequestEnabled = handoverRequestEnabled;
28
+ this.handoverEnabled = handoverEnabled;
29
+ this.forceStartEnabled = forceStartEnabled;
30
+ // Instantiate the topic builder.
31
+ this.topicBuilder = new MqttTopicBuilder(`uns-infra/${PACKAGE_INFO.name}/${PACKAGE_INFO.version}/${processName}/`);
32
+ // Set status as active after a timeout if no other active process are detected.
33
+ this.activeTimeout = setTimeout(() => {
34
+ logger.info(`${this.processName} - No active message received within timeout. Assuming no other process is running.`);
35
+ this.active = true;
36
+ this.event.emit("handoverManager", { active: this.active });
37
+ // Activate all UNS proxy instance publishers and subscribers.
38
+ this.unsMqttProxies.forEach((unsProxy) => {
39
+ unsProxy.setPublisherActive();
40
+ unsProxy.setSubscriberActive();
41
+ });
42
+ }, ACTIVE_TIMEOUT);
43
+ }
44
+ /**
45
+ * Main entry point for handling incoming MQTT messages.
46
+ * It checks the topic and delegates to the corresponding handler.
47
+ */
48
+ async handleMqttMessage(event) {
49
+ try {
50
+ // Check if the packet is active messages from other processes and this process is not active.
51
+ if (this.requestingHandover === false &&
52
+ this.topicBuilder.getActiveTopic() !== event.topic &&
53
+ this.active === false &&
54
+ this.handoverInProgress === false) {
55
+ logger.info(`${this.processName} - Another process is active on ${event.topic}.`);
56
+ if (this.handoverRequestEnabled) {
57
+ // Requester process
58
+ // Publish a handover request message after 10 seconds to the handover topic.
59
+ clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.
60
+ this.activeTimeout = undefined;
61
+ this.event.emit("handoverManager", { active: this.active });
62
+ this.requestingHandover = true;
63
+ logger.info(`${this.processName} - Requesting handover in 10 seconds.`);
64
+ setTimeout(async () => {
65
+ const eventHandoverTopic = new MqttTopicBuilder(MqttTopicBuilder.extractBaseTopic(event.topic)).getHandoverTopic();
66
+ logger.info(`${this.processName} - Requesting handover ${eventHandoverTopic}.`);
67
+ this.handoverInProgress = true;
68
+ await this.mqttProxy.publish(eventHandoverTopic, JSON.stringify({ type: "handover_request" }), {
69
+ retain: false,
70
+ properties: {
71
+ responseTopic: this.topicBuilder.getHandoverTopic(),
72
+ userProperties: {
73
+ processName: this.processName,
74
+ },
75
+ },
76
+ });
77
+ }, 10000);
78
+ }
79
+ else {
80
+ if (this.forceStartEnabled) {
81
+ // Force start the process even if another process is active.
82
+ logger.info(`${this.processName} - Force starting the process.`);
83
+ logger.warn(`${this.processName} - Warning: Source and destination being the same may lead to duplicate messages.`);
84
+ clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.
85
+ this.activeTimeout = undefined;
86
+ this.active = true;
87
+ this.event.emit("handoverManager", { active: this.active });
88
+ // Activate all UNS proxy instance publishers and subscribers.
89
+ this.unsMqttProxies.forEach((unsProxy) => {
90
+ unsProxy.setPublisherActive();
91
+ unsProxy.setSubscriberActive();
92
+ });
93
+ }
94
+ else {
95
+ logger.info(`${this.processName} - Waiting for the other process on topic ${event.topic} to become passive.`);
96
+ this.activeTimeout.refresh();
97
+ }
98
+ }
99
+ }
100
+ // Check if the packet is an handover message, sent to a handover topic.
101
+ if (event.topic === this.topicBuilder.getHandoverTopic() && this.handoverEnabled) {
102
+ if (event.packet?.properties?.userProperties?.processName && event.packet.properties.userProperties.processName !== this.processName) {
103
+ await this.handleHandover(event);
104
+ }
105
+ }
106
+ }
107
+ catch (error) {
108
+ logger.error(`${this.processName} - Error processing MQTT message: ${error.message}`);
109
+ return;
110
+ }
111
+ }
112
+ /**
113
+ * Handles handovers.
114
+ */
115
+ async handleHandover(event) {
116
+ try {
117
+ const response = JSON.parse(event.message.toString());
118
+ // Responder process
119
+ // Check if the message is a handover request and publish MULTIPLE handover_subscriber messages
120
+ if (response.type === "handover_request") {
121
+ logger.info(`${this.processName} - Received handover request from ${event.packet?.properties?.userProperties?.processName}. Accepting handover.`);
122
+ // Set all UNS proxy instance subscribers to passive and drain the queue.
123
+ const mqttWorkerData = [];
124
+ for (let i = 0; i < this.unsMqttProxies.length; i++) {
125
+ const unsProxy = this.unsMqttProxies[i];
126
+ const workerData = await unsProxy.setSubscriberPassiveAndDrainQueue();
127
+ mqttWorkerData.push(workerData);
128
+ }
129
+ logger.info(`${this.processName} - Handover request accepted. Sending handover_subscriber messages.`);
130
+ // Publish handover_subscriber messages for each instance that has processed some data.
131
+ for (let i = 0; i < mqttWorkerData.length; i++) {
132
+ const workerData = mqttWorkerData[i];
133
+ if (workerData.batchSize > 0) {
134
+ await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? "", JSON.stringify({
135
+ type: "handover_subscriber",
136
+ batchSize: workerData.batchSize,
137
+ referenceHash: workerData.referenceHash,
138
+ instanceName: workerData.instanceName,
139
+ }), {
140
+ retain: false,
141
+ properties: {
142
+ responseTopic: this.topicBuilder.getHandoverTopic(),
143
+ userProperties: {
144
+ processName: this.processName,
145
+ },
146
+ },
147
+ });
148
+ }
149
+ }
150
+ logger.info(`${this.processName} - Handover subscriber messages sent.`);
151
+ // Publish a single handover acknowledgment only when all
152
+ // handover_subscriber messages have been sent
153
+ this.active = false;
154
+ this.event.emit("handoverManager", { active: this.active });
155
+ await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? "", JSON.stringify({
156
+ type: "handover_fin",
157
+ }), {
158
+ retain: false,
159
+ properties: {
160
+ responseTopic: this.topicBuilder.getHandoverTopic(),
161
+ userProperties: {
162
+ processName: this.processName,
163
+ },
164
+ },
165
+ });
166
+ logger.info(`${this.processName} - Handover fin message sent.`);
167
+ this.handoverInProgress = false;
168
+ this.requestingHandover = false;
169
+ this.unsMqttProxies.forEach((unsProxy) => {
170
+ unsProxy.stop();
171
+ });
172
+ }
173
+ // Requestor process
174
+ // Check if the message is one of the handover_subscriber message in response to handover_request
175
+ // and publish a handover_ack message
176
+ if (response.type === "handover_subscriber") {
177
+ // Find correct unsProxy instance for handover_subscriber and set it active
178
+ this.unsMqttProxies.forEach((unsProxy) => {
179
+ if (unsProxy.instanceName === response.instanceName) {
180
+ unsProxy.setSubscriberActive(response.batchSize, response.referenceHash);
181
+ }
182
+ });
183
+ }
184
+ // Requestor process
185
+ // Check if the message is a handover_fin at the end of handover_subscriber messages
186
+ if (response.type === "handover_fin") {
187
+ logger.info(`${this.processName} - Received handover fin from ${event.packet?.properties?.userProperties?.processName}.`);
188
+ // Maybe we should count the number of requests that were allrady made TODO
189
+ // this.handoverInProgress = false;
190
+ // this.requestingHandover = false;
191
+ this.active = true;
192
+ this.event.emit("handoverManager", { active: this.active });
193
+ logger.info(`${this.processName} - Handover completed.`);
194
+ // Activate all UNS proxy instance publishers and subscribers.
195
+ this.unsMqttProxies.forEach((unsProxy) => {
196
+ unsProxy.setPublisherActive();
197
+ unsProxy.setSubscriberActive();
198
+ });
199
+ // Maybe we should reply with handover_ack.
200
+ await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? "", JSON.stringify({
201
+ type: "handover_ack",
202
+ }), {
203
+ retain: false,
204
+ properties: {
205
+ responseTopic: this.topicBuilder.getHandoverTopic(),
206
+ userProperties: {
207
+ processName: this.processName,
208
+ },
209
+ },
210
+ });
211
+ logger.info(`${this.processName} - Handover ack message sent.`);
212
+ }
213
+ // Responder process
214
+ // Check if the message is a handover_ack at the end of handover_fin messages
215
+ if (response.type === "handover_ack") {
216
+ logger.info(`${this.processName} - Received handover ack from ${event.packet?.properties?.userProperties?.processName}.`);
217
+ this.handoverInProgress = false;
218
+ this.requestingHandover = false;
219
+ logger.info(`${this.processName} - Handover completed. Exiting process.`);
220
+ process.exit(0);
221
+ }
222
+ }
223
+ catch (error) {
224
+ logger.error(`${this.processName} - Error processing handover response: ${error.message}`);
225
+ }
226
+ }
227
+ }
@@ -0,0 +1,10 @@
1
+ export declare const PROCESS_NAME_FILE: string;
2
+ export declare const PACKAGE_JSON_PATH: string;
3
+ interface PackageInfo {
4
+ name: string;
5
+ version: string;
6
+ }
7
+ export declare const PACKAGE_INFO: PackageInfo;
8
+ export declare const MQTT_UPDATE_INTERVAL = 10000;
9
+ export declare const ACTIVE_TIMEOUT = 10000;
10
+ export {};
@@ -0,0 +1,12 @@
1
+ // process-config.ts
2
+ import * as path from "path";
3
+ import { readFileSync } from "fs";
4
+ import { basePath } from "../base-path.js";
5
+ // Path to the process name file
6
+ export const PROCESS_NAME_FILE = path.join(basePath, "uns-process-name.conf");
7
+ // Path to package.json to retrieve package name and version
8
+ export const PACKAGE_JSON_PATH = path.join(basePath, "package.json");
9
+ export const PACKAGE_INFO = JSON.parse(readFileSync(PACKAGE_JSON_PATH, "utf8"));
10
+ // Other configuration values (update intervals, timeouts, etc.)
11
+ export const MQTT_UPDATE_INTERVAL = 10000; // in milliseconds
12
+ export const ACTIVE_TIMEOUT = 10000; // in milliseconds
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Retrieves a persistent process name.
3
+ * - Checks if a process name is provided via command-line args.
4
+ * - Otherwise, reads the process name from a file.
5
+ * - If the file does not exist, generates a new name and stores it.
6
+ */
7
+ export declare function getProcessName(): string;
@@ -0,0 +1,28 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+ import { PROCESS_NAME_FILE } from "./process-config.js";
3
+ import logger from "../logger.js";
4
+ /**
5
+ * Retrieves a persistent process name.
6
+ * - Checks if a process name is provided via command-line args.
7
+ * - Otherwise, reads the process name from a file.
8
+ * - If the file does not exist, generates a new name and stores it.
9
+ */
10
+ export function getProcessName() {
11
+ // Try to read the process name from the configuration file.
12
+ try {
13
+ return readFileSync(PROCESS_NAME_FILE, "utf8").trim();
14
+ }
15
+ catch {
16
+ // Generate a new process name if reading fails
17
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
18
+ const newProcessName = Array.from({ length: 6 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join("");
19
+ // Write the new process name to the file for persistence
20
+ try {
21
+ writeFileSync(PROCESS_NAME_FILE, newProcessName, "utf8");
22
+ }
23
+ catch (err) {
24
+ logger.error("Failed to write process name file:", err);
25
+ }
26
+ return newProcessName;
27
+ }
28
+ }
@@ -0,0 +1,35 @@
1
+ import type MqttProxy from "../uns-mqtt/mqtt-proxy.js";
2
+ export declare class StatusMonitor {
3
+ private mqttProxy;
4
+ private processStatusTopic;
5
+ private activeSupplier;
6
+ private memoryIntervalMs;
7
+ private statusIntervalMs;
8
+ private memoryInterval?;
9
+ private statusInterval?;
10
+ /**
11
+ * @param mqttProxy The MQTT proxy used to publish messages.
12
+ * @param processStatusTopic The base topic for the process (ending with a slash).
13
+ * @param activeSupplier A function returning the current active state (boolean).
14
+ * @param memoryIntervalMs Interval in milliseconds for publishing memory status.
15
+ * @param statusIntervalMs Interval in milliseconds for publishing active status.
16
+ */
17
+ constructor(mqttProxy: MqttProxy, processStatusTopic: string, activeSupplier: () => boolean, memoryIntervalMs: number, statusIntervalMs: number);
18
+ /**
19
+ * Starts the periodic memory and status updates.
20
+ */
21
+ start(): void;
22
+ /**
23
+ * Stops the periodic updates.
24
+ */
25
+ stop(): void;
26
+ /**
27
+ * Publishes memory usage updates via MQTT.
28
+ * In this example, only the `heapUsed` metric is published.
29
+ */
30
+ private publishMemoryUpdates;
31
+ /**
32
+ * Publishes the process active status via MQTT.
33
+ */
34
+ private publishStatusUpdates;
35
+ }
@@ -0,0 +1,82 @@
1
+ // status-monitor.ts
2
+ import logger from "../logger.js";
3
+ import { DataSizeMeasurements } from "./uns-measurements.js";
4
+ import { UnsPacket } from "./uns-packet.js";
5
+ export class StatusMonitor {
6
+ mqttProxy;
7
+ processStatusTopic;
8
+ activeSupplier;
9
+ memoryIntervalMs;
10
+ statusIntervalMs;
11
+ memoryInterval;
12
+ statusInterval;
13
+ /**
14
+ * @param mqttProxy The MQTT proxy used to publish messages.
15
+ * @param processStatusTopic The base topic for the process (ending with a slash).
16
+ * @param activeSupplier A function returning the current active state (boolean).
17
+ * @param memoryIntervalMs Interval in milliseconds for publishing memory status.
18
+ * @param statusIntervalMs Interval in milliseconds for publishing active status.
19
+ */
20
+ constructor(mqttProxy, processStatusTopic, activeSupplier, memoryIntervalMs, statusIntervalMs) {
21
+ this.mqttProxy = mqttProxy;
22
+ this.processStatusTopic = processStatusTopic;
23
+ this.activeSupplier = activeSupplier;
24
+ this.memoryIntervalMs = memoryIntervalMs;
25
+ this.statusIntervalMs = statusIntervalMs;
26
+ }
27
+ /**
28
+ * Starts the periodic memory and status updates.
29
+ */
30
+ start() {
31
+ this.memoryInterval = setInterval(() => this.publishMemoryUpdates(), this.memoryIntervalMs);
32
+ this.statusInterval = setInterval(() => this.publishStatusUpdates(), this.statusIntervalMs);
33
+ }
34
+ /**
35
+ * Stops the periodic updates.
36
+ */
37
+ stop() {
38
+ if (this.memoryInterval) {
39
+ clearInterval(this.memoryInterval);
40
+ this.memoryInterval = undefined;
41
+ }
42
+ if (this.statusInterval) {
43
+ clearInterval(this.statusInterval);
44
+ this.statusInterval = undefined;
45
+ }
46
+ }
47
+ /**
48
+ * Publishes memory usage updates via MQTT.
49
+ * In this example, only the `heapUsed` metric is published.
50
+ */
51
+ async publishMemoryUpdates() {
52
+ try {
53
+ const time = UnsPacket.formatToISO8601(new Date());
54
+ const memoryUsage = process.memoryUsage();
55
+ const heapUsedMessage = { data: { time, value: Math.round(memoryUsage.heapUsed / 1048576), uom: DataSizeMeasurements.MegaByte } };
56
+ let packet = await UnsPacket.unsPacketFromUnsMessage(heapUsedMessage);
57
+ this.mqttProxy.publish(`${this.processStatusTopic}heap-used`, JSON.stringify(packet));
58
+ const heapTotalMessage = { data: { time, value: Math.round(memoryUsage.heapTotal / 1048576), uom: DataSizeMeasurements.MegaByte } };
59
+ packet = await UnsPacket.unsPacketFromUnsMessage(heapTotalMessage);
60
+ this.mqttProxy.publish(`${this.processStatusTopic}heap-total`, JSON.stringify(packet));
61
+ }
62
+ catch (error) {
63
+ logger.error(`StatusMonitor - Error publishing memory updates: ${error.message}`);
64
+ }
65
+ }
66
+ /**
67
+ * Publishes the process active status via MQTT.
68
+ */
69
+ async publishStatusUpdates() {
70
+ try {
71
+ const time = UnsPacket.formatToISO8601(new Date());
72
+ const activeMessage = {
73
+ data: { time, value: Number(this.activeSupplier()) },
74
+ };
75
+ const packet = await UnsPacket.unsPacketFromUnsMessage(activeMessage);
76
+ this.mqttProxy.publish(`${this.processStatusTopic}active`, JSON.stringify(packet), { retain: false, });
77
+ }
78
+ catch (error) {
79
+ logger.error(`StatusMonitor - Error publishing status updates: ${error.message}`);
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,6 @@
1
+ export declare class UnsEventEmitter<Events extends Record<string, any>> {
2
+ private listeners;
3
+ on<K extends keyof Events>(eventName: K, listener: (event: Events[K]) => void): void;
4
+ off<K extends keyof Events>(eventName: K, listener: (event: Events[K]) => void): void;
5
+ emit<K extends keyof Events>(eventName: K, event: Events[K]): void;
6
+ }
@@ -0,0 +1,19 @@
1
+ export class UnsEventEmitter {
2
+ listeners = {};
3
+ on(eventName, listener) {
4
+ if (!this.listeners[eventName]) {
5
+ this.listeners[eventName] = [];
6
+ }
7
+ this.listeners[eventName].push(listener);
8
+ }
9
+ off(eventName, listener) {
10
+ if (!this.listeners[eventName])
11
+ return;
12
+ this.listeners[eventName] = this.listeners[eventName].filter((l) => l !== listener);
13
+ }
14
+ emit(eventName, event) {
15
+ if (!this.listeners[eventName])
16
+ return;
17
+ this.listeners[eventName].forEach((listener) => listener(event));
18
+ }
19
+ }
@@ -0,0 +1,156 @@
1
+ import { UnsAttributeType } from "../graphql/schema";
2
+ import { MeasurementUnit } from "./uns-measurements";
3
+ import { UnsTags } from "./uns-tags";
4
+ import { UnsTopics } from "./uns-topics";
5
+ export type ISO8601 = `${number}-${string}-${string}T${string}:${string}:${string}.${string}Z`;
6
+ export declare function isIOS8601Type(value: string): value is ISO8601;
7
+ export type UnsAttribute = string;
8
+ export declare const valueTypes: string[];
9
+ export type ValueTypeString = typeof valueTypes[number];
10
+ export type ValueType = string | number;
11
+ export interface IUnsParameters {
12
+ mqttSubToTopics?: string | string[];
13
+ username?: string;
14
+ password?: string;
15
+ mqttSSL?: boolean;
16
+ publishThrottlingDelay?: number;
17
+ subscribeThrottlingDelay?: number;
18
+ }
19
+ export interface IUnsProcessParameters {
20
+ processName?: string | undefined;
21
+ mqttSubToTopics?: string | string[];
22
+ username?: string;
23
+ password?: string;
24
+ mqttSSL?: boolean;
25
+ }
26
+ export interface UnsEvents {
27
+ input: {
28
+ topic: string;
29
+ message: string;
30
+ packet: any;
31
+ };
32
+ mqttProxyStatus: {
33
+ event: string;
34
+ value: number;
35
+ uom: MeasurementUnit;
36
+ statusTopic: string;
37
+ };
38
+ error: {
39
+ code: number;
40
+ message: string;
41
+ };
42
+ mqttWorker: {
43
+ command: string;
44
+ instanceName: string;
45
+ batchSize: number;
46
+ referenceHash: string;
47
+ };
48
+ cronEvent: {};
49
+ apiGetEvent: {
50
+ req: any;
51
+ res: any;
52
+ };
53
+ unsProxyProducedTopics: {
54
+ producedTopics: ITopicObject[];
55
+ statusTopic: string;
56
+ };
57
+ unsProxyProducedApiEndpoints: {
58
+ producedApiEndpoints: IApiObject[];
59
+ statusTopic: string;
60
+ };
61
+ }
62
+ export interface IUnsExtendedData extends IUnsData {
63
+ valueType: ValueTypeString;
64
+ }
65
+ export interface IUnsData {
66
+ time: ISO8601;
67
+ value: ValueType;
68
+ dataGroup?: string;
69
+ uom?: MeasurementUnit;
70
+ foreignEventKey?: string;
71
+ }
72
+ export interface IUnsEvent {
73
+ time: ISO8601;
74
+ dataGroup?: string;
75
+ details?: string;
76
+ uniqueEventId?: string;
77
+ }
78
+ export interface IUnsTable {
79
+ time: ISO8601;
80
+ values: Record<string, string | number | undefined | null>;
81
+ dataGroup?: string;
82
+ }
83
+ export interface IUnsCommand {
84
+ time: ISO8601;
85
+ details?: string;
86
+ }
87
+ export interface IMqttMessage {
88
+ topic: UnsTopics;
89
+ attribute: UnsAttribute;
90
+ description?: string;
91
+ tags?: UnsTags[];
92
+ packet: IUnsPacket;
93
+ attributeNeedsPersistence?: boolean | null;
94
+ }
95
+ export interface IUnsPacket {
96
+ message: IUnsExtendedMessage;
97
+ messageSignature?: string;
98
+ interval?: number;
99
+ readonly version: string;
100
+ sequenceId?: number;
101
+ }
102
+ export interface IUnsPackatParameters {
103
+ }
104
+ export interface IUnsMessage {
105
+ command?: IUnsCommand;
106
+ data?: IUnsData;
107
+ event?: IUnsEvent;
108
+ table?: IUnsTable;
109
+ expiresAt?: ISO8601;
110
+ createdAt?: ISO8601;
111
+ }
112
+ export interface IUnsExtendedMessage extends IUnsMessage {
113
+ data?: IUnsExtendedData;
114
+ }
115
+ export interface ITopicObject {
116
+ timestamp: string;
117
+ attribute: string;
118
+ attributeType: UnsAttributeType;
119
+ topic: string;
120
+ description: string;
121
+ dataGroup: string;
122
+ tags: string[] | null;
123
+ attributeNeedsPersistence: boolean | null;
124
+ }
125
+ export interface IApiObject {
126
+ timestamp: string;
127
+ attribute: string;
128
+ topic: string;
129
+ attributeType: UnsAttributeType;
130
+ apiDescription?: string;
131
+ apiHost: string;
132
+ apiEndpoint: string;
133
+ apiSwaggerEndpoint: string;
134
+ apiMethod: "GET" | "POST" | "PUT" | "DELETE";
135
+ apiQueryParams: QueryParamDef[];
136
+ }
137
+ export interface QueryParamDef {
138
+ name: string;
139
+ type: "string" | "number" | "boolean";
140
+ required?: boolean;
141
+ description?: string;
142
+ }
143
+ export interface IApiProxyOptions {
144
+ jwtSecret?: string;
145
+ jwks?: {
146
+ wellKnownJwksUrl: string;
147
+ activeKidUrl?: string;
148
+ cacheTtlMs?: number;
149
+ algorithms?: ("RS256" | "RS384" | "RS512")[];
150
+ };
151
+ }
152
+ export interface IGetEndpointOptions {
153
+ apiDescription?: string;
154
+ tags?: string[];
155
+ queryParams?: QueryParamDef[];
156
+ }
@@ -0,0 +1,5 @@
1
+ export function isIOS8601Type(value) {
2
+ const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
3
+ return iso8601Regex.test(value);
4
+ }
5
+ export const valueTypes = ["string", "number"];