kubernetes-fluent-client 3.1.0 → 3.1.2
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/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +68 -0
- package/dist/fetch.d.ts +22 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +82 -0
- package/dist/fetch.test.d.ts +2 -0
- package/dist/fetch.test.d.ts.map +1 -0
- package/dist/fetch.test.js +97 -0
- package/dist/fileSystem.d.ts +11 -0
- package/dist/fileSystem.d.ts.map +1 -0
- package/dist/fileSystem.js +42 -0
- package/dist/fileSystem.test.d.ts +2 -0
- package/dist/fileSystem.test.d.ts.map +1 -0
- package/dist/fileSystem.test.js +75 -0
- package/dist/fluent/http2-watch.spec.d.ts +2 -0
- package/dist/fluent/http2-watch.spec.d.ts.map +1 -0
- package/dist/fluent/http2-watch.spec.js +284 -0
- package/dist/fluent/index.d.ts +12 -0
- package/dist/fluent/index.d.ts.map +1 -0
- package/dist/fluent/index.js +228 -0
- package/dist/fluent/index.test.d.ts +2 -0
- package/dist/fluent/index.test.d.ts.map +1 -0
- package/dist/fluent/index.test.js +193 -0
- package/dist/fluent/types.d.ts +201 -0
- package/dist/fluent/types.d.ts.map +1 -0
- package/dist/fluent/types.js +16 -0
- package/dist/fluent/utils.d.ts +41 -0
- package/dist/fluent/utils.d.ts.map +1 -0
- package/dist/fluent/utils.js +153 -0
- package/dist/fluent/utils.test.d.ts +2 -0
- package/dist/fluent/utils.test.d.ts.map +1 -0
- package/dist/fluent/utils.test.js +215 -0
- package/dist/fluent/watch.d.ts +88 -0
- package/dist/fluent/watch.d.ts.map +1 -0
- package/dist/fluent/watch.js +595 -0
- package/dist/fluent/watch.spec.d.ts +2 -0
- package/dist/fluent/watch.spec.d.ts.map +1 -0
- package/dist/fluent/watch.spec.js +261 -0
- package/dist/generate.d.ts +84 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +208 -0
- package/dist/generate.test.d.ts +2 -0
- package/dist/generate.test.d.ts.map +1 -0
- package/dist/generate.test.js +320 -0
- package/dist/helpers.d.ts +33 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +103 -0
- package/dist/helpers.test.d.ts +2 -0
- package/dist/helpers.test.d.ts.map +1 -0
- package/dist/helpers.test.js +37 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/kinds.d.ts +16 -0
- package/dist/kinds.d.ts.map +1 -0
- package/dist/kinds.js +570 -0
- package/dist/kinds.test.d.ts +2 -0
- package/dist/kinds.test.d.ts.map +1 -0
- package/dist/kinds.test.js +155 -0
- package/dist/patch.d.ts +7 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +2 -0
- package/dist/postProcessing.d.ts +246 -0
- package/dist/postProcessing.d.ts.map +1 -0
- package/dist/postProcessing.js +497 -0
- package/dist/postProcessing.test.d.ts +2 -0
- package/dist/postProcessing.test.d.ts.map +1 -0
- package/dist/postProcessing.test.js +550 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/upstream.d.ts +4 -0
- package/dist/upstream.d.ts.map +1 -0
- package/dist/upstream.js +56 -0
- package/package.json +1 -1
- package/src/fluent/types.ts +16 -0
- package/src/fluent/watch.ts +134 -81
package/dist/upstream.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.GenericKind = exports.Endpoint = exports.VolumeAttachment = exports.ValidatingWebhookConfiguration = exports.TokenReview = exports.SubjectAccessReview = exports.StorageClass = exports.StatefulSet = exports.ServiceAccount = exports.Service = exports.SelfSubjectRulesReview = exports.SelfSubjectAccessReview = exports.Secret = exports.RuntimeClass = exports.RoleBinding = exports.Role = exports.ResourceQuota = exports.ReplicationController = exports.ReplicaSet = exports.PodTemplate = exports.PodDisruptionBudget = exports.Pod = exports.PersistentVolumeClaim = exports.PersistentVolume = exports.Node = exports.NetworkPolicy = exports.Namespace = exports.MutatingWebhookConfiguration = exports.LocalSubjectAccessReview = exports.LimitRange = exports.Job = exports.IngressClass = exports.Ingress = exports.HorizontalPodAutoscaler = exports.EndpointSlice = exports.Deployment = exports.DaemonSet = exports.CustomResourceDefinition = exports.CSIDriver = exports.CronJob = exports.ControllerRevision = exports.ConfigMap = exports.ClusterRoleBinding = exports.ClusterRole = exports.CertificateSigningRequest = exports.APIService = exports.Event = exports.CoreEvent = void 0;
|
|
6
|
+
/** a is a collection of K8s types to be used within an action: `When(a.Configmap)` */
|
|
7
|
+
var client_node_1 = require("@kubernetes/client-node");
|
|
8
|
+
Object.defineProperty(exports, "CoreEvent", { enumerable: true, get: function () { return client_node_1.CoreV1Event; } });
|
|
9
|
+
Object.defineProperty(exports, "Event", { enumerable: true, get: function () { return client_node_1.EventsV1Event; } });
|
|
10
|
+
Object.defineProperty(exports, "APIService", { enumerable: true, get: function () { return client_node_1.V1APIService; } });
|
|
11
|
+
Object.defineProperty(exports, "CertificateSigningRequest", { enumerable: true, get: function () { return client_node_1.V1CertificateSigningRequest; } });
|
|
12
|
+
Object.defineProperty(exports, "ClusterRole", { enumerable: true, get: function () { return client_node_1.V1ClusterRole; } });
|
|
13
|
+
Object.defineProperty(exports, "ClusterRoleBinding", { enumerable: true, get: function () { return client_node_1.V1ClusterRoleBinding; } });
|
|
14
|
+
Object.defineProperty(exports, "ConfigMap", { enumerable: true, get: function () { return client_node_1.V1ConfigMap; } });
|
|
15
|
+
Object.defineProperty(exports, "ControllerRevision", { enumerable: true, get: function () { return client_node_1.V1ControllerRevision; } });
|
|
16
|
+
Object.defineProperty(exports, "CronJob", { enumerable: true, get: function () { return client_node_1.V1CronJob; } });
|
|
17
|
+
Object.defineProperty(exports, "CSIDriver", { enumerable: true, get: function () { return client_node_1.V1CSIDriver; } });
|
|
18
|
+
Object.defineProperty(exports, "CustomResourceDefinition", { enumerable: true, get: function () { return client_node_1.V1CustomResourceDefinition; } });
|
|
19
|
+
Object.defineProperty(exports, "DaemonSet", { enumerable: true, get: function () { return client_node_1.V1DaemonSet; } });
|
|
20
|
+
Object.defineProperty(exports, "Deployment", { enumerable: true, get: function () { return client_node_1.V1Deployment; } });
|
|
21
|
+
Object.defineProperty(exports, "EndpointSlice", { enumerable: true, get: function () { return client_node_1.V1EndpointSlice; } });
|
|
22
|
+
Object.defineProperty(exports, "HorizontalPodAutoscaler", { enumerable: true, get: function () { return client_node_1.V1HorizontalPodAutoscaler; } });
|
|
23
|
+
Object.defineProperty(exports, "Ingress", { enumerable: true, get: function () { return client_node_1.V1Ingress; } });
|
|
24
|
+
Object.defineProperty(exports, "IngressClass", { enumerable: true, get: function () { return client_node_1.V1IngressClass; } });
|
|
25
|
+
Object.defineProperty(exports, "Job", { enumerable: true, get: function () { return client_node_1.V1Job; } });
|
|
26
|
+
Object.defineProperty(exports, "LimitRange", { enumerable: true, get: function () { return client_node_1.V1LimitRange; } });
|
|
27
|
+
Object.defineProperty(exports, "LocalSubjectAccessReview", { enumerable: true, get: function () { return client_node_1.V1LocalSubjectAccessReview; } });
|
|
28
|
+
Object.defineProperty(exports, "MutatingWebhookConfiguration", { enumerable: true, get: function () { return client_node_1.V1MutatingWebhookConfiguration; } });
|
|
29
|
+
Object.defineProperty(exports, "Namespace", { enumerable: true, get: function () { return client_node_1.V1Namespace; } });
|
|
30
|
+
Object.defineProperty(exports, "NetworkPolicy", { enumerable: true, get: function () { return client_node_1.V1NetworkPolicy; } });
|
|
31
|
+
Object.defineProperty(exports, "Node", { enumerable: true, get: function () { return client_node_1.V1Node; } });
|
|
32
|
+
Object.defineProperty(exports, "PersistentVolume", { enumerable: true, get: function () { return client_node_1.V1PersistentVolume; } });
|
|
33
|
+
Object.defineProperty(exports, "PersistentVolumeClaim", { enumerable: true, get: function () { return client_node_1.V1PersistentVolumeClaim; } });
|
|
34
|
+
Object.defineProperty(exports, "Pod", { enumerable: true, get: function () { return client_node_1.V1Pod; } });
|
|
35
|
+
Object.defineProperty(exports, "PodDisruptionBudget", { enumerable: true, get: function () { return client_node_1.V1PodDisruptionBudget; } });
|
|
36
|
+
Object.defineProperty(exports, "PodTemplate", { enumerable: true, get: function () { return client_node_1.V1PodTemplate; } });
|
|
37
|
+
Object.defineProperty(exports, "ReplicaSet", { enumerable: true, get: function () { return client_node_1.V1ReplicaSet; } });
|
|
38
|
+
Object.defineProperty(exports, "ReplicationController", { enumerable: true, get: function () { return client_node_1.V1ReplicationController; } });
|
|
39
|
+
Object.defineProperty(exports, "ResourceQuota", { enumerable: true, get: function () { return client_node_1.V1ResourceQuota; } });
|
|
40
|
+
Object.defineProperty(exports, "Role", { enumerable: true, get: function () { return client_node_1.V1Role; } });
|
|
41
|
+
Object.defineProperty(exports, "RoleBinding", { enumerable: true, get: function () { return client_node_1.V1RoleBinding; } });
|
|
42
|
+
Object.defineProperty(exports, "RuntimeClass", { enumerable: true, get: function () { return client_node_1.V1RuntimeClass; } });
|
|
43
|
+
Object.defineProperty(exports, "Secret", { enumerable: true, get: function () { return client_node_1.V1Secret; } });
|
|
44
|
+
Object.defineProperty(exports, "SelfSubjectAccessReview", { enumerable: true, get: function () { return client_node_1.V1SelfSubjectAccessReview; } });
|
|
45
|
+
Object.defineProperty(exports, "SelfSubjectRulesReview", { enumerable: true, get: function () { return client_node_1.V1SelfSubjectRulesReview; } });
|
|
46
|
+
Object.defineProperty(exports, "Service", { enumerable: true, get: function () { return client_node_1.V1Service; } });
|
|
47
|
+
Object.defineProperty(exports, "ServiceAccount", { enumerable: true, get: function () { return client_node_1.V1ServiceAccount; } });
|
|
48
|
+
Object.defineProperty(exports, "StatefulSet", { enumerable: true, get: function () { return client_node_1.V1StatefulSet; } });
|
|
49
|
+
Object.defineProperty(exports, "StorageClass", { enumerable: true, get: function () { return client_node_1.V1StorageClass; } });
|
|
50
|
+
Object.defineProperty(exports, "SubjectAccessReview", { enumerable: true, get: function () { return client_node_1.V1SubjectAccessReview; } });
|
|
51
|
+
Object.defineProperty(exports, "TokenReview", { enumerable: true, get: function () { return client_node_1.V1TokenReview; } });
|
|
52
|
+
Object.defineProperty(exports, "ValidatingWebhookConfiguration", { enumerable: true, get: function () { return client_node_1.V1ValidatingWebhookConfiguration; } });
|
|
53
|
+
Object.defineProperty(exports, "VolumeAttachment", { enumerable: true, get: function () { return client_node_1.V1VolumeAttachment; } });
|
|
54
|
+
Object.defineProperty(exports, "Endpoint", { enumerable: true, get: function () { return client_node_1.V1Endpoint; } });
|
|
55
|
+
var types_1 = require("./types");
|
|
56
|
+
Object.defineProperty(exports, "GenericKind", { enumerable: true, get: function () { return types_1.GenericKind; } });
|
package/package.json
CHANGED
package/src/fluent/types.ts
CHANGED
|
@@ -7,6 +7,22 @@ import type { PartialDeep } from "type-fest";
|
|
|
7
7
|
|
|
8
8
|
import { GenericClass, GroupVersionKind } from "../types";
|
|
9
9
|
import { WatchCfg, Watcher } from "./watch";
|
|
10
|
+
import https from "https";
|
|
11
|
+
import { SecureClientSessionOptions } from "http2";
|
|
12
|
+
/**
|
|
13
|
+
* Agent options for the the http2Watch
|
|
14
|
+
*/
|
|
15
|
+
export type AgentOptions = Pick<
|
|
16
|
+
SecureClientSessionOptions,
|
|
17
|
+
"ca" | "cert" | "key" | "rejectUnauthorized"
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for the http2Watch
|
|
22
|
+
*/
|
|
23
|
+
export interface Options {
|
|
24
|
+
agent?: https.Agent & { options?: AgentOptions };
|
|
25
|
+
}
|
|
10
26
|
|
|
11
27
|
/**
|
|
12
28
|
* The Phase matched when using the K8s Watch API.
|
package/src/fluent/watch.ts
CHANGED
|
@@ -9,7 +9,7 @@ import http2 from "http2";
|
|
|
9
9
|
import fetch from "node-fetch";
|
|
10
10
|
import { fetch as wrappedFetch } from "../fetch";
|
|
11
11
|
import { GenericClass, KubernetesListObject } from "../types";
|
|
12
|
-
import { Filters, WatchAction, WatchPhase } from "./types";
|
|
12
|
+
import { Filters, WatchAction, WatchPhase, Options, AgentOptions } from "./types";
|
|
13
13
|
import { k8sCfg, pathBuilder } from "./utils";
|
|
14
14
|
import fs from "fs";
|
|
15
15
|
|
|
@@ -469,6 +469,44 @@ export class Watcher<T extends GenericClass> {
|
|
|
469
469
|
}
|
|
470
470
|
};
|
|
471
471
|
|
|
472
|
+
// Configure the agent options for the HTTP/2 client
|
|
473
|
+
static #getAgentOptions(opts: Options) {
|
|
474
|
+
if (opts.agent && opts.agent instanceof https.Agent) {
|
|
475
|
+
return {
|
|
476
|
+
key: opts.agent.options.key,
|
|
477
|
+
cert: opts.agent.options.cert,
|
|
478
|
+
ca: opts.agent.options.ca,
|
|
479
|
+
rejectUnauthorized: false,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return undefined;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Create an HTTP/2 client
|
|
486
|
+
static #createHttp2Client(origin: string, agentOptions?: AgentOptions) {
|
|
487
|
+
return http2.connect(origin, {
|
|
488
|
+
ca: agentOptions?.ca,
|
|
489
|
+
cert: agentOptions?.cert,
|
|
490
|
+
key: agentOptions?.key,
|
|
491
|
+
rejectUnauthorized: agentOptions?.rejectUnauthorized,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Generate the request headers for the HTTP/2 request
|
|
496
|
+
#generateRequestHeaders = async (url: URL) => {
|
|
497
|
+
const token = await this.#getToken();
|
|
498
|
+
const headers: Record<string, string> = {
|
|
499
|
+
":method": "GET",
|
|
500
|
+
":path": url.pathname + url.search,
|
|
501
|
+
"content-type": "application/json",
|
|
502
|
+
"user-agent": "kubernetes-fluent-client",
|
|
503
|
+
};
|
|
504
|
+
if (token) {
|
|
505
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
506
|
+
}
|
|
507
|
+
return headers;
|
|
508
|
+
};
|
|
509
|
+
|
|
472
510
|
/**
|
|
473
511
|
* Watch for changes to the resource.
|
|
474
512
|
*/
|
|
@@ -479,92 +517,31 @@ export class Watcher<T extends GenericClass> {
|
|
|
479
517
|
|
|
480
518
|
// Build the URL and request options
|
|
481
519
|
const { opts, url } = await this.#buildURL(true, this.#resourceVersion);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (opts.agent && opts.agent instanceof https.Agent) {
|
|
485
|
-
agentOptions = {
|
|
486
|
-
key: opts.agent.options.key,
|
|
487
|
-
cert: opts.agent.options.cert,
|
|
488
|
-
ca: opts.agent.options.ca,
|
|
489
|
-
rejectUnauthorized: false,
|
|
490
|
-
};
|
|
491
|
-
}
|
|
520
|
+
const agentOptions = Watcher.#getAgentOptions(opts as Options);
|
|
492
521
|
|
|
493
522
|
// HTTP/2 client connection setup
|
|
494
|
-
const client =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
523
|
+
const client = Watcher.#createHttp2Client(url.origin, agentOptions);
|
|
524
|
+
|
|
525
|
+
// Handle client connection errors
|
|
526
|
+
client.on("error", err => {
|
|
527
|
+
this.#events.emit(WatchEvent.NETWORK_ERROR, err);
|
|
528
|
+
this.#streamCleanup(client);
|
|
529
|
+
this.#scheduleReconnect();
|
|
499
530
|
});
|
|
500
531
|
|
|
501
532
|
// Set up headers for the HTTP/2 request
|
|
502
|
-
const
|
|
503
|
-
const headers: Record<string, string> = {
|
|
504
|
-
":method": "GET",
|
|
505
|
-
":path": url.pathname + url.search,
|
|
506
|
-
"content-type": "application/json",
|
|
507
|
-
"user-agent": "kubernetes-fluent-client",
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
if (token) {
|
|
511
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
512
|
-
}
|
|
533
|
+
const headers = await this.#generateRequestHeaders(url);
|
|
513
534
|
|
|
514
535
|
// Make the HTTP/2 request
|
|
515
536
|
const req = client.request(headers);
|
|
516
|
-
|
|
517
537
|
req.setEncoding("utf8");
|
|
518
538
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
526
|
-
this.#pendingReconnect = false;
|
|
527
|
-
this.#events.emit(WatchEvent.CONNECT, url.pathname);
|
|
528
|
-
|
|
529
|
-
// Reset the retry count
|
|
530
|
-
this.#resyncFailureCount = 0;
|
|
531
|
-
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
532
|
-
|
|
533
|
-
req.on("data", async chunk => {
|
|
534
|
-
try {
|
|
535
|
-
buffer += chunk;
|
|
536
|
-
const lines = buffer.split("\n");
|
|
537
|
-
// Avoid Watch event data_error received. Unexpected end of JSON input.
|
|
538
|
-
buffer = lines.pop()!;
|
|
539
|
-
|
|
540
|
-
for (const line of lines) {
|
|
541
|
-
await this.#processLine(line, this.#process);
|
|
542
|
-
}
|
|
543
|
-
} catch (err) {
|
|
544
|
-
void this.#errHandler(err);
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
req.on("end", () => {
|
|
549
|
-
client.close();
|
|
550
|
-
this.#streamCleanup();
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
req.on("close", () => {
|
|
554
|
-
client.close();
|
|
555
|
-
this.#streamCleanup();
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
req.on("error", err => {
|
|
559
|
-
void this.#errHandler(err);
|
|
560
|
-
});
|
|
561
|
-
} else {
|
|
562
|
-
const statusMessage = headers[":status-text"] || "Unknown";
|
|
563
|
-
throw new Error(`watch connect failed: ${statusCode} ${statusMessage}`);
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
req.on("error", err => {
|
|
567
|
-
void this.#errHandler(err);
|
|
539
|
+
// Handler events for the HTTP/2 request
|
|
540
|
+
this.#handleHttp2Request(req, client);
|
|
541
|
+
|
|
542
|
+
// Handle abort signal
|
|
543
|
+
this.#abortController.signal.addEventListener("abort", () => {
|
|
544
|
+
this.#streamCleanup(client);
|
|
568
545
|
});
|
|
569
546
|
} catch (e) {
|
|
570
547
|
void this.#errHandler(e);
|
|
@@ -628,6 +605,7 @@ export class Watcher<T extends GenericClass> {
|
|
|
628
605
|
clearInterval(this.$relistTimer);
|
|
629
606
|
clearInterval(this.#resyncTimer);
|
|
630
607
|
this.#streamCleanup();
|
|
608
|
+
this.#scheduleReconnect();
|
|
631
609
|
this.#events.emit(WatchEvent.ABORT, err);
|
|
632
610
|
return;
|
|
633
611
|
|
|
@@ -645,15 +623,90 @@ export class Watcher<T extends GenericClass> {
|
|
|
645
623
|
// Force a resync
|
|
646
624
|
this.#lastSeenTime = OVERRIDE;
|
|
647
625
|
};
|
|
626
|
+
/**
|
|
627
|
+
*
|
|
628
|
+
* @param req - the request stream
|
|
629
|
+
* @param client - the client session
|
|
630
|
+
*/
|
|
631
|
+
#handleHttp2Request(req: http2.ClientHttp2Stream, client: http2.ClientHttp2Session) {
|
|
632
|
+
let buffer = "";
|
|
633
|
+
|
|
634
|
+
req.on("response", headers => {
|
|
635
|
+
const statusCode = headers[":status"];
|
|
636
|
+
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
637
|
+
this.#onWatchConnected();
|
|
638
|
+
} else {
|
|
639
|
+
this.#cleanupAndReconnect(client, new Error(`watch connect failed: ${statusCode}`));
|
|
640
|
+
}
|
|
641
|
+
});
|
|
648
642
|
|
|
649
|
-
|
|
650
|
-
|
|
643
|
+
req.on("data", chunk => {
|
|
644
|
+
buffer += chunk;
|
|
645
|
+
const lines = buffer.split("\n");
|
|
646
|
+
buffer = lines.pop() || ""; // Keep any incomplete line for the next chunk
|
|
647
|
+
|
|
648
|
+
lines.forEach(line => {
|
|
649
|
+
void this.#processLine(line, this.#process);
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
req.on("end", () => this.#cleanupAndReconnect(client));
|
|
654
|
+
req.on("close", () => this.#cleanupAndReconnect(client));
|
|
655
|
+
req.on("error", error => this.#errHandler(error));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** Schedules a reconnect with a delay to prevent rapid reconnections. */
|
|
659
|
+
#scheduleReconnect() {
|
|
660
|
+
const jitter = Math.floor(Math.random() * 1000);
|
|
661
|
+
const delay = (this.#watchCfg.resyncDelaySec ?? 5) * 1000 + jitter;
|
|
662
|
+
|
|
663
|
+
setTimeout(() => {
|
|
664
|
+
this.#events.emit(WatchEvent.RECONNECT, this.#resyncFailureCount);
|
|
665
|
+
void this.#http2Watch();
|
|
666
|
+
}, delay);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Handle a successful connection to the watch.
|
|
671
|
+
*/
|
|
672
|
+
#onWatchConnected() {
|
|
673
|
+
this.#pendingReconnect = false;
|
|
674
|
+
this.#events.emit(WatchEvent.CONNECT);
|
|
675
|
+
|
|
676
|
+
// Reset the retry count
|
|
677
|
+
this.#resyncFailureCount = 0;
|
|
678
|
+
this.#events.emit(WatchEvent.INC_RESYNC_FAILURE_COUNT, this.#resyncFailureCount);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Cleanup the stream and listeners.
|
|
683
|
+
*
|
|
684
|
+
* @param client - the client session
|
|
685
|
+
*/
|
|
686
|
+
#streamCleanup = (client?: http2.ClientHttp2Session) => {
|
|
651
687
|
if (this.#stream) {
|
|
652
688
|
this.#stream.removeAllListeners();
|
|
653
689
|
this.#stream.destroy();
|
|
654
690
|
}
|
|
655
|
-
if (
|
|
656
|
-
|
|
691
|
+
if (client) {
|
|
692
|
+
client.close();
|
|
657
693
|
}
|
|
658
694
|
};
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Cleanup the stream and listeners and reconnect.
|
|
698
|
+
*
|
|
699
|
+
* @param client - the client session
|
|
700
|
+
* @param error - the error that occurred
|
|
701
|
+
*/
|
|
702
|
+
#cleanupAndReconnect(client: http2.ClientHttp2Session, error?: Error) {
|
|
703
|
+
this.#streamCleanup(client);
|
|
704
|
+
|
|
705
|
+
if (error) {
|
|
706
|
+
this.#events.emit(WatchEvent.NETWORK_ERROR, error);
|
|
707
|
+
void this.#errHandler(error);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
this.#scheduleReconnect();
|
|
711
|
+
}
|
|
659
712
|
}
|