@uns-kit/api 3.0.36 → 3.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts +6 -0
- package/dist/app.js +38 -0
- package/dist/uns-api-plugin.js +28 -7
- package/dist/uns-api-proxy.d.ts +2 -0
- package/dist/uns-api-proxy.js +3 -0
- package/package.json +2 -2
package/dist/app.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ type MountConfig = {
|
|
|
10
10
|
};
|
|
11
11
|
export default class App {
|
|
12
12
|
private expressApplication;
|
|
13
|
+
private ownershipGate;
|
|
14
|
+
private readonly acceptedRequests;
|
|
15
|
+
private requestFailed;
|
|
16
|
+
setOwnershipGate(gate: () => boolean): void;
|
|
17
|
+
drainRequests(): Promise<void>;
|
|
18
|
+
stop(): Promise<void>;
|
|
13
19
|
server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
14
20
|
private port;
|
|
15
21
|
router: Router;
|
package/dist/app.js
CHANGED
|
@@ -28,6 +28,24 @@ const buildSwaggerPath = (base, processName, instanceName) => {
|
|
|
28
28
|
};
|
|
29
29
|
export default class App {
|
|
30
30
|
expressApplication;
|
|
31
|
+
ownershipGate;
|
|
32
|
+
acceptedRequests = new Set();
|
|
33
|
+
requestFailed = false;
|
|
34
|
+
setOwnershipGate(gate) { this.ownershipGate = gate; }
|
|
35
|
+
async drainRequests() {
|
|
36
|
+
while (this.acceptedRequests.size)
|
|
37
|
+
await Promise.all([...this.acceptedRequests]);
|
|
38
|
+
if (this.requestFailed)
|
|
39
|
+
throw new Error("An accepted HTTP request ended without confirmation");
|
|
40
|
+
}
|
|
41
|
+
async stop() {
|
|
42
|
+
await this.drainRequests();
|
|
43
|
+
if (this.server.listening)
|
|
44
|
+
await new Promise((resolve, reject) => {
|
|
45
|
+
this.server.close(error => error ? reject(error) : resolve());
|
|
46
|
+
this.server.closeIdleConnections?.();
|
|
47
|
+
});
|
|
48
|
+
}
|
|
31
49
|
server;
|
|
32
50
|
port;
|
|
33
51
|
router;
|
|
@@ -42,6 +60,26 @@ export default class App {
|
|
|
42
60
|
this.port = port;
|
|
43
61
|
this.expressApplication = express();
|
|
44
62
|
this.server = http.createServer(this.expressApplication);
|
|
63
|
+
this.expressApplication.use((_req, res, next) => {
|
|
64
|
+
if (!this.ownershipGate)
|
|
65
|
+
return next();
|
|
66
|
+
if (!this.ownershipGate()) {
|
|
67
|
+
res.setHeader("Retry-After", "1");
|
|
68
|
+
res.status(503).json({ error: "RUNTIME_PASSIVE", message: "Runtime ownership is being transferred. Retry the request." });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let finish;
|
|
72
|
+
const accepted = new Promise(resolve => { finish = resolve; });
|
|
73
|
+
this.acceptedRequests.add(accepted);
|
|
74
|
+
res.once("finish", () => { this.acceptedRequests.delete(accepted); finish(); });
|
|
75
|
+
res.once("close", () => {
|
|
76
|
+
if (!res.writableFinished)
|
|
77
|
+
this.requestFailed = true;
|
|
78
|
+
this.acceptedRequests.delete(accepted);
|
|
79
|
+
finish();
|
|
80
|
+
});
|
|
81
|
+
next();
|
|
82
|
+
});
|
|
45
83
|
this.processName = processName;
|
|
46
84
|
this.instanceName = instanceName;
|
|
47
85
|
this.apiBasePrefix =
|
package/dist/uns-api-plugin.js
CHANGED
|
@@ -16,29 +16,50 @@ const unsApiPlugin = ({ define }) => {
|
|
|
16
16
|
await this.waitForProcessConnection();
|
|
17
17
|
const internals = this;
|
|
18
18
|
const unsApiProxy = new UnsApiProxy(internals.processName, instanceName, options);
|
|
19
|
+
let owned = !this.usesStatefulHandover() || this.isActive();
|
|
20
|
+
const deferredMetadata = new Map();
|
|
21
|
+
const publishMetadata = (topic, payload) => {
|
|
22
|
+
if (!owned) {
|
|
23
|
+
deferredMetadata.set(topic, payload);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
return internals.processMqttProxy.publish(topic, payload);
|
|
27
|
+
};
|
|
28
|
+
if (this.usesStatefulHandover())
|
|
29
|
+
unsApiProxy.setOwnershipGate(() => owned);
|
|
30
|
+
this.registerLifecycleParticipant({
|
|
31
|
+
onRelease: () => { owned = false; },
|
|
32
|
+
drain: () => unsApiProxy.drainRequests(),
|
|
33
|
+
onActivate: async () => {
|
|
34
|
+
owned = true;
|
|
35
|
+
for (const [topic, payload] of deferredMetadata)
|
|
36
|
+
await publishMetadata(topic, payload);
|
|
37
|
+
deferredMetadata.clear();
|
|
38
|
+
},
|
|
39
|
+
});
|
|
19
40
|
unsApiProxy.event.on("unsProxyProducedTopics", (event) => {
|
|
20
|
-
|
|
41
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedTopics));
|
|
21
42
|
});
|
|
22
43
|
unsApiProxy.event.on("unsProxyProducedApiEndpoints", (event) => {
|
|
23
|
-
|
|
44
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedApiEndpoints));
|
|
24
45
|
});
|
|
25
46
|
unsApiProxy.event.on("unsProxyProducedServiceEndpoints", (event) => {
|
|
26
|
-
|
|
47
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedServiceEndpoints));
|
|
27
48
|
});
|
|
28
49
|
unsApiProxy.event.on("unsProxyProducedDataOfferEndpoints", (event) => {
|
|
29
|
-
|
|
50
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedDataOfferEndpoints));
|
|
30
51
|
});
|
|
31
52
|
unsApiProxy.event.on("unsProxyProducedApiCatchAll", (event) => {
|
|
32
|
-
|
|
53
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedCatchall));
|
|
33
54
|
});
|
|
34
55
|
unsApiProxy.event.on("unsProxyProducedDataCatalogOffers", (event) => {
|
|
35
|
-
|
|
56
|
+
publishMetadata(event.statusTopic, JSON.stringify(event.producedDataCatalogOffers));
|
|
36
57
|
});
|
|
37
58
|
unsApiProxy.event.on("mqttProxyStatus", (event) => {
|
|
38
59
|
const time = UnsPacket.formatToISO8601(new Date());
|
|
39
60
|
const unsMessage = { data: { time, value: event.value, uom: event.uom } };
|
|
40
61
|
UnsPacket.unsPacketFromUnsMessage(unsMessage).then((packet) => {
|
|
41
|
-
|
|
62
|
+
publishMetadata(event.statusTopic, JSON.stringify(packet));
|
|
42
63
|
});
|
|
43
64
|
});
|
|
44
65
|
internals.unsApiProxies.push(unsApiProxy);
|
package/dist/uns-api-proxy.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
21
21
|
private readonly statusIntervalMs;
|
|
22
22
|
private readonly dataCatalogOffers;
|
|
23
23
|
constructor(processName: string, instanceName: string, options: IApiProxyOptions);
|
|
24
|
+
setOwnershipGate(gate: () => boolean): void;
|
|
25
|
+
drainRequests(): Promise<void>;
|
|
24
26
|
getProcessName(): string;
|
|
25
27
|
private getPublishedApiHost;
|
|
26
28
|
/**
|
package/dist/uns-api-proxy.js
CHANGED
|
@@ -92,6 +92,8 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
92
92
|
setTimeout(() => this.emitStatusMetrics(), 0);
|
|
93
93
|
this.statusInterval = setInterval(() => this.emitStatusMetrics(), this.statusIntervalMs);
|
|
94
94
|
}
|
|
95
|
+
setOwnershipGate(gate) { this.app.setOwnershipGate(gate); }
|
|
96
|
+
async drainRequests() { await this.app.drainRequests(); }
|
|
95
97
|
getProcessName() {
|
|
96
98
|
return this.processName;
|
|
97
99
|
}
|
|
@@ -728,6 +730,7 @@ export default class UnsApiProxy extends UnsProxy {
|
|
|
728
730
|
clearInterval(this.statusInterval);
|
|
729
731
|
this.statusInterval = null;
|
|
730
732
|
}
|
|
733
|
+
await this.app.stop();
|
|
731
734
|
await super.stop();
|
|
732
735
|
}
|
|
733
736
|
publishDataCatalogOffer(offer) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uns-kit/api",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.37",
|
|
4
4
|
"description": "Express-powered API gateway plugin for UnsProxyProcess with JWT/JWKS support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"multer": "^2.2.0",
|
|
38
38
|
"hyparquet-writer": "^0.16.5",
|
|
39
39
|
"uuid": "^14.0.1",
|
|
40
|
-
"@uns-kit/core": "3.0.
|
|
40
|
+
"@uns-kit/core": "3.0.37"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/cookie-parser": "^1.4.10",
|