@interopio/bridge 0.0.1-alpha

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 (84) hide show
  1. package/bin/bridge.js +9 -0
  2. package/gen/instance/GeneratedBuildInfo.ts +4 -0
  3. package/license.md +5 -0
  4. package/package.json +40 -0
  5. package/readme.md +10 -0
  6. package/src/cluster/Address.ts +57 -0
  7. package/src/cluster/Cluster.ts +13 -0
  8. package/src/cluster/Endpoint.ts +5 -0
  9. package/src/cluster/Member.ts +9 -0
  10. package/src/cluster/MembershipListener.ts +6 -0
  11. package/src/config/Config.ts +100 -0
  12. package/src/config/DiscoveryConfig.ts +21 -0
  13. package/src/config/Duration.ts +168 -0
  14. package/src/config/KubernetesConfig.ts +7 -0
  15. package/src/config/NamedDiscoveryConfig.ts +17 -0
  16. package/src/config/Properties.ts +49 -0
  17. package/src/config/index.ts +1 -0
  18. package/src/discovery/SimpleDiscoveryNode.ts +14 -0
  19. package/src/discovery/index.ts +207 -0
  20. package/src/discovery/multicast/MulticastDiscoveryStrategy.ts +141 -0
  21. package/src/discovery/multicast/MulticastDiscoveryStrategyFactory.ts +30 -0
  22. package/src/discovery/multicast/MulticastProperties.ts +4 -0
  23. package/src/discovery/settings.ts +37 -0
  24. package/src/error/RequestFailure.ts +48 -0
  25. package/src/gossip/ApplicationState.ts +48 -0
  26. package/src/gossip/EndpointState.ts +141 -0
  27. package/src/gossip/FailureDetector.ts +235 -0
  28. package/src/gossip/Gossiper.ts +1133 -0
  29. package/src/gossip/HeartbeatState.ts +66 -0
  30. package/src/gossip/Messenger.ts +130 -0
  31. package/src/gossip/VersionedValue.ts +59 -0
  32. package/src/index.ts +3 -0
  33. package/src/instance/AddressPicker.ts +245 -0
  34. package/src/instance/BridgeNode.ts +141 -0
  35. package/src/instance/ClusterTopologyIntentTracker.ts +4 -0
  36. package/src/io/VersionedSerializer.ts +230 -0
  37. package/src/io/util.ts +117 -0
  38. package/src/kubernetes/DnsEndpointResolver.ts +70 -0
  39. package/src/kubernetes/KubernetesApiEndpointResolver.ts +111 -0
  40. package/src/kubernetes/KubernetesApiProvider.ts +75 -0
  41. package/src/kubernetes/KubernetesClient.ts +264 -0
  42. package/src/kubernetes/KubernetesConfig.ts +130 -0
  43. package/src/kubernetes/KubernetesDiscoveryStrategy.ts +30 -0
  44. package/src/kubernetes/KubernetesDiscoveryStrategyFactory.ts +71 -0
  45. package/src/kubernetes/KubernetesEndpointResolver.ts +43 -0
  46. package/src/kubernetes/KubernetesProperties.ts +22 -0
  47. package/src/license/BridgeLicenseValidator.ts +19 -0
  48. package/src/license/LicenseValidator.ts +114 -0
  49. package/src/license/types.ts +40 -0
  50. package/src/logging.ts +22 -0
  51. package/src/main.mts +53 -0
  52. package/src/net/Action.ts +143 -0
  53. package/src/net/AddressSerializer.ts +44 -0
  54. package/src/net/ByteBufferAllocator.ts +27 -0
  55. package/src/net/FrameDecoder.ts +314 -0
  56. package/src/net/FrameEncoder.ts +138 -0
  57. package/src/net/HandshakeProtocol.ts +143 -0
  58. package/src/net/InboundConnection.ts +108 -0
  59. package/src/net/InboundConnectionInitiator.ts +150 -0
  60. package/src/net/InboundMessageHandler.ts +377 -0
  61. package/src/net/InboundSink.ts +38 -0
  62. package/src/net/Message.ts +428 -0
  63. package/src/net/OutboundConnection.ts +1141 -0
  64. package/src/net/OutboundConnectionInitiator.ts +76 -0
  65. package/src/net/RequestCallbacks.ts +148 -0
  66. package/src/net/ResponseHandler.ts +30 -0
  67. package/src/net/ShareableBytes.ts +125 -0
  68. package/src/net/internal/AsyncResourceExecutor.ts +464 -0
  69. package/src/net/internal/AsyncSocketPromise.ts +37 -0
  70. package/src/net/internal/channel/ChannelHandlerAdapter.ts +99 -0
  71. package/src/net/internal/channel/types.ts +188 -0
  72. package/src/utils/bigint.ts +23 -0
  73. package/src/utils/buffer.ts +434 -0
  74. package/src/utils/clock.ts +148 -0
  75. package/src/utils/collections.ts +283 -0
  76. package/src/utils/crc.ts +39 -0
  77. package/src/utils/internal/IpAddressUtil.ts +161 -0
  78. package/src/utils/memory/BufferPools.ts +40 -0
  79. package/src/utils/network.ts +130 -0
  80. package/src/utils/promise.ts +38 -0
  81. package/src/utils/uuid.ts +5 -0
  82. package/src/utils/vint.ts +238 -0
  83. package/src/version/MemberVersion.ts +42 -0
  84. package/src/version/Version.ts +12 -0
@@ -0,0 +1,230 @@
1
+ import type {ByteBuffer} from '../utils/buffer.ts';
2
+ import {readUtf, writeUtf} from './util.ts';
3
+ import {readUnsignedVInt32, setUnsignedVInt, setUnsignedVInt32} from '../utils/vint.ts';
4
+
5
+ export interface DataOutput {
6
+ writeInt8(value: number): void
7
+ writeUint8(value: number): void
8
+ writeInt16(value: number): void
9
+ writeUint16(value: number): void
10
+ writeInt32(value: number): void
11
+ writeUint32(value: number): void
12
+ writeUtf8String(value: string): void
13
+ writeUint8Array(value: Uint8Array, offset?: number, length?: number): void
14
+ writeBoolean(value: boolean): void
15
+ writeUnsignedVInt(value: bigint | number): void
16
+ writeUnsignedVInt32(value: number): void
17
+ }
18
+
19
+ export interface DataInput {
20
+ readInt8(): number
21
+ readUint8(): number
22
+ readInt16(): number
23
+ readUint16(): number
24
+ readInt32(): number
25
+ // readUint32(): number
26
+ readUtf8String(): string
27
+ readUint8Array(b: Uint8Array): void
28
+ readUint8Array(b: Uint8Array, offset:number, length: number): void
29
+ // readBoolean(): boolean
30
+ readUnsignedVInt32(): number
31
+
32
+ skipBytes(n: number): number;
33
+ skipBytesFully(n: number): void;
34
+ }
35
+
36
+ export interface VersionedSerializer<T> {
37
+ serialize(value: T, output: DataOutput, version: number): void
38
+
39
+ deserialize(input: DataInput, version: number): T
40
+
41
+ serializedSize(value: T, version: number): number
42
+ }
43
+
44
+
45
+ export class ByteBufferOutput implements DataOutput {
46
+ private readonly _buffer: ByteBuffer;
47
+
48
+ constructor(buffer: ByteBuffer) {
49
+ this._buffer = buffer;
50
+ }
51
+
52
+ get buffer() {
53
+ return this._buffer.duplicate().flip();
54
+ }
55
+
56
+ writeUtf8String(value: string) {
57
+ writeUtf(value, this);
58
+ }
59
+
60
+ writeBoolean(value: boolean) {
61
+ this._buffer.setUint8(value ? 1 : 0);
62
+ }
63
+
64
+ writeUint8(value: number) {
65
+ this._buffer.setUint8(value);
66
+ }
67
+
68
+ writeInt8(value: number) {
69
+ this._buffer.setInt8(value);
70
+ }
71
+
72
+ writeInt16(value: number) {
73
+ this._buffer.setInt16(value);
74
+ }
75
+
76
+ writeUint16(value: number) {
77
+ this._buffer.setUint16(value);
78
+ }
79
+
80
+ writeInt32(value: number) {
81
+ this._buffer.setInt32(value);
82
+ }
83
+
84
+ writeUint32(value: number) {
85
+ this._buffer.setUint32(value);
86
+ }
87
+
88
+ writeUint8Array(value: Uint8Array, offset: number = 0, length?: number) {
89
+ length ??= value.length - offset;
90
+
91
+ if (offset < 0 || offset > value.length || length < 0 || length > value.length - offset) {
92
+ throw new Error(`index out of bounds: ${offset} + ${length} > ${value.length}`);
93
+ }
94
+
95
+ if (length === 0) {
96
+ return;
97
+ }
98
+
99
+ let copied = 0;
100
+ while (copied < length) {
101
+ if (this._buffer.hasRemaining) {
102
+ const chunkSize = Math.min(length - copied, this._buffer.remaining);
103
+ this._buffer.setUint8Array(value, offset + copied, chunkSize);
104
+ copied += chunkSize;
105
+ }
106
+ else {
107
+ throw new Error(`Buffer overflow: ${this._buffer.remaining} remaining, ${length - copied} to copy`);
108
+ }
109
+ }
110
+ }
111
+
112
+ writeUnsignedVInt(value: bigint | number) {
113
+ setUnsignedVInt(value, this._buffer);
114
+ }
115
+
116
+ writeUnsignedVInt32(value: number) {
117
+ setUnsignedVInt32(value, this._buffer);
118
+ }
119
+ }
120
+
121
+ export class ByteBufferInput implements DataInput {
122
+
123
+ private readonly buffer: ByteBuffer;
124
+
125
+ constructor(buffer: ByteBuffer, duplicate: boolean) {
126
+ this.buffer = duplicate ? buffer.duplicate() : buffer;
127
+ }
128
+
129
+ readInt8(): number {
130
+ if (this.buffer.hasRemaining) {
131
+ return this.buffer.getInt8();
132
+ }
133
+ throw new Error('Buffer underflow');
134
+ }
135
+
136
+ readUint8(): number {
137
+ if (this.buffer.hasRemaining) {
138
+ return this.buffer.getUint8();
139
+ }
140
+ throw new Error('Buffer underflow');
141
+ }
142
+
143
+ readUint16(): number {
144
+ if (this.buffer.remaining >= 2) {
145
+ return this.buffer.getUint16();
146
+ }
147
+ throw new Error('Buffer underflow');
148
+ }
149
+
150
+ readInt16(): number {
151
+ if (this.buffer.remaining > 1) {
152
+ return this.buffer.getInt16();
153
+ }
154
+ throw new Error('Buffer underflow');
155
+ }
156
+
157
+ readInt32(): number {
158
+ if (this.buffer.remaining >= 4) {
159
+ return this.buffer.getInt32();
160
+ }
161
+ throw new Error('Buffer underflow');
162
+ }
163
+
164
+ readUtf8String(): string {
165
+ return readUtf(this);
166
+ }
167
+
168
+ readUint8Array(b: Uint8Array, offset: number = 0, length?: number): void {
169
+ length ??= b.length - offset;
170
+
171
+ if (offset < 0 || offset > b.length || length < 0 || length > b.length - offset) {
172
+ throw new Error(`index out of bounds: ${offset} + ${length} > ${b.length}`);
173
+ }
174
+
175
+ if (length === 0) {
176
+ return;
177
+ }
178
+
179
+ let copied = 0;
180
+ while (copied < length) {
181
+ if (this.buffer.hasRemaining) {
182
+ const chunkSize = Math.min(length - copied, this.buffer.remaining);
183
+ this.buffer.getUint8Array(b, offset + copied, chunkSize);
184
+ copied += chunkSize;
185
+ }
186
+ else {
187
+ throw new Error(`Buffer underflow: ${this.buffer.remaining} remaining, ${length - copied} to copy`);
188
+ }
189
+ }
190
+ }
191
+ readUnsignedVInt32(): number {
192
+ return readUnsignedVInt32(this);
193
+ }
194
+
195
+ skipBytesFully(n: number) {
196
+ const skipped = this.skipBytes(n);
197
+ if (skipped !== n) {
198
+ throw new Error(`Buffer underflow: ${n} bytes requested, ${skipped} bytes skipped`);
199
+ }
200
+ }
201
+
202
+ skipBytes(n: number): number {
203
+ if (n <= 0) {
204
+ return 0;
205
+ }
206
+
207
+ const requested = n;
208
+ let position = this.buffer.position;
209
+ let limit = this.buffer.limit;
210
+ let remaining: number;
211
+
212
+ while ((remaining = limit - position) < n) {
213
+ n -= remaining;
214
+ this.buffer.position = limit;
215
+ position = this.buffer.position;
216
+ limit = this.buffer.limit;
217
+ if (position == limit) {
218
+ return requested - n;
219
+ }
220
+ }
221
+ this.buffer.position = position + n;
222
+
223
+
224
+ return requested;
225
+ }
226
+
227
+ available(): number {
228
+ return this.buffer.remaining;
229
+ }
230
+ }
package/src/io/util.ts ADDED
@@ -0,0 +1,117 @@
1
+ import type {DataInput, DataOutput} from './VersionedSerializer.ts';
2
+
3
+ const MAX_BUFFER_SIZE = 8192;
4
+ let tmpBuffer: Uint8Array = new Uint8Array(16);
5
+
6
+ function retrieveTemporaryBuffer(minSize: number): Uint8Array {
7
+ let array = tmpBuffer;
8
+ if (array.length < Math.min(minSize, MAX_BUFFER_SIZE)) {
9
+ array = new Uint8Array(Math.min(MAX_BUFFER_SIZE, Math.pow(minSize, 2)));
10
+ tmpBuffer = array;
11
+ }
12
+ return array;
13
+ }
14
+
15
+ export function encodedUtfLength(value: string): number {
16
+ const strlen = value.length;
17
+ let utflen = 0;
18
+ for (let i = 0; i < strlen; i++)
19
+ {
20
+ const c = value.charCodeAt(i);
21
+ if ((c >= 0x0001) && (c <= 0x007F))
22
+ utflen++;
23
+ else if (c > 0x07FF)
24
+ utflen += 3;
25
+ else
26
+ utflen += 2;
27
+ }
28
+ return utflen;
29
+ }
30
+
31
+ export function writeUtf(value: string, out: DataOutput): void {
32
+ let length = value.length;
33
+ if (length === 0) {
34
+ out.writeUint8(0);
35
+ out.writeUint8(0);
36
+ return;
37
+ }
38
+ let utfCount = 0;
39
+ let maxSize = 2;
40
+
41
+ for (let i = 0; i < length; i++) {
42
+ const ch = value.charCodeAt(i);
43
+ if ((ch > 0) && (ch < 128)) {
44
+ utfCount++;
45
+ } else if (ch < 2047) {
46
+ utfCount += 2;
47
+ } else {
48
+ utfCount += maxSize = 3;
49
+ }
50
+ }
51
+ if (utfCount > 65535) {
52
+ throw new Error(`String too long: ${value}`);
53
+ }
54
+
55
+ const utfBytes = retrieveTemporaryBuffer(utfCount);
56
+
57
+ const bufferLength = utfBytes.length;
58
+ if (utfCount == length) {
59
+ utfBytes[0] = (utfCount >> 8);
60
+ utfBytes[1] = (utfCount);
61
+ let firstIndex = 2;
62
+ for (let offset = 0; offset < length; offset += bufferLength) {
63
+ const runLength = Math.min(bufferLength - firstIndex, length - offset) + firstIndex;
64
+ offset -= firstIndex;
65
+ for (let i = firstIndex; i < runLength; i++) {
66
+ utfBytes[i] = value.charCodeAt(offset + i);
67
+ }
68
+ out.writeUint8Array(utfBytes, 0, runLength);
69
+ firstIndex = 0;
70
+ }
71
+ } else {
72
+ let utfIndex = 2;
73
+ let offset = 0;
74
+
75
+ utfBytes[0] = (utfCount >> 8);
76
+ utfBytes[1] = (utfCount);
77
+
78
+ while (length > 0) {
79
+ let charRunLength = Math.floor((utfBytes.length - utfIndex) / maxSize);
80
+
81
+ if (charRunLength < 128 && charRunLength < length) {
82
+ out.writeUint8Array(utfBytes, 0, utfIndex);
83
+ utfIndex = 0;
84
+ }
85
+ if (charRunLength > length) {
86
+ charRunLength = length;
87
+ }
88
+
89
+ for (let i = 0; i < charRunLength; i++) {
90
+ const ch = value.charCodeAt(offset + i);
91
+ if (ch > 0 && ch < 128) {
92
+ utfBytes[utfIndex++] = ch;
93
+ } else if (ch < 2048) {
94
+ utfBytes[utfIndex++] = (0xc0 | (0x1f & (ch >> 6)));
95
+ utfBytes[utfIndex++] = (0x80 | (0x3f & (ch & 0x3f)));
96
+ } else {
97
+ utfBytes[utfIndex++] = (0xe0 | (0x0f & (ch >> 12)));
98
+ utfBytes[utfIndex++] = (0x80 | (0x3f & (ch >> 6)));
99
+ utfBytes[utfIndex++] = (0x80 | (0x3f & ch));
100
+ }
101
+ }
102
+
103
+ offset += charRunLength;
104
+ length -= charRunLength;
105
+ }
106
+ out.writeUint8Array(utfBytes, 0, utfIndex);
107
+ }
108
+ }
109
+
110
+ const decoder = new TextDecoder('utf-8');
111
+ export function readUtf(input: DataInput): string {
112
+ const length = input.readUint16();
113
+
114
+ const utfBytes = new Uint8Array(length);
115
+ input.readUint8Array(utfBytes);
116
+ return decoder.decode(utfBytes);
117
+ }
@@ -0,0 +1,70 @@
1
+ import {type DiscoveryNode} from '../discovery/index.ts';
2
+ import {getAllByName, type IpAddress} from '../utils/network.ts';
3
+ import {KubernetesEndpointResolver} from './KubernetesEndpointResolver.ts';
4
+ import {KubernetesConfig} from './KubernetesConfig.ts';
5
+ import {NetworkConfig} from '../config/Config.ts';
6
+ import type {Logger} from '../logging.ts';
7
+ import {SimpleDiscoveryNode} from "../discovery/SimpleDiscoveryNode";
8
+ import {fromHostname} from "../cluster/Address";
9
+
10
+ export type LookupProvider = (host: string) => Promise<IpAddress[]>;
11
+
12
+ export class DnsEndpointResolver extends KubernetesEndpointResolver {
13
+ private readonly lookupProvider: LookupProvider;
14
+ private readonly serviceDns: string;
15
+ private readonly port: number;
16
+
17
+ static of(logger: Logger, config: KubernetesConfig): DnsEndpointResolver {
18
+ return new DnsEndpointResolver(logger, getAllByName, config.serviceDns, config.servicePort);
19
+ }
20
+
21
+ /*testing*/ constructor(logger: Logger, lookupProvider: LookupProvider, serviceDns?: string, port: number = 0) {
22
+ super(logger);
23
+ this.lookupProvider = lookupProvider;
24
+ this.serviceDns = serviceDns;
25
+ this.port = port;
26
+ }
27
+
28
+ async resolve(): Promise<DiscoveryNode[]> {
29
+ try {
30
+ return await this.lookup();
31
+ } catch (e) {
32
+ return [];
33
+ }
34
+ }
35
+
36
+ private async lookup() {
37
+
38
+ const addresses = new Set<string>();
39
+
40
+ for (const ipAddress of await this.lookupProvider(this.serviceDns)) {
41
+ const address = ipAddress.address;
42
+ if (addresses.has(address)) {
43
+ continue;
44
+ }
45
+ if (this.logger.enabledFor('debug')) {
46
+ this.logger.debug(`Found node service with address: ${ipAddress}`);
47
+ }
48
+ addresses.add(address);
49
+ }
50
+ if (addresses.size === 0) {
51
+ this.logger.warn(`No nodes found for service: ${this.serviceDns}`);
52
+ return [];
53
+ }
54
+
55
+ const result: Array<DiscoveryNode> = [];
56
+ for (const address of addresses) {
57
+ const privateAddress = await fromHostname(address, DnsEndpointResolver.getBridgePort(this.port));
58
+ const node = new SimpleDiscoveryNode(privateAddress);
59
+ result.push(node);
60
+ }
61
+ return result;
62
+ }
63
+
64
+ private static getBridgePort(port: number): number {
65
+ if (port > 0) {
66
+ return port;
67
+ }
68
+ return NetworkConfig.DEFAULT_PORT;
69
+ }
70
+ }
@@ -0,0 +1,111 @@
1
+ import {Endpoint, EndpointAddress, KubernetesClient} from './KubernetesClient.ts';
2
+ import {type DiscoveryNode} from '../discovery/index.ts';
3
+ import {type Address, fromIpAddress} from '../cluster/Address.ts';
4
+ import {type Logger} from '../logging.ts';
5
+ import {KubernetesEndpointResolver} from './KubernetesEndpointResolver.ts';
6
+ import {KubernetesConfig} from './KubernetesConfig.ts';
7
+ import {NetworkConfig} from '../config/Config.ts';
8
+ import {type ClusterTopologyIntentTracker} from '../instance/ClusterTopologyIntentTracker.ts';
9
+ import {SimpleDiscoveryNode} from '../discovery/SimpleDiscoveryNode.ts';
10
+
11
+ function buildKubernetesClient(config: KubernetesConfig, clusterTopologyIntentTracker?: ClusterTopologyIntentTracker): KubernetesClient {
12
+ return new KubernetesClient(config.namespace, config.kubernetesMasterUrl, config.exposeExternallyMode, config.tokenProvider, config.servicePerPodLabelName, config.servicePerPodLabelValue, clusterTopologyIntentTracker);
13
+ }
14
+
15
+ export class KubernetesApiEndpointResolver extends KubernetesEndpointResolver {
16
+
17
+ private readonly client: KubernetesClient;
18
+ private readonly serviceName?: string;
19
+ private readonly port: number = 0;
20
+ private readonly serviceLabel?: string;
21
+ private readonly serviceLabelValue?: string;
22
+ private readonly podLabel?: string;
23
+ private readonly podLabelValue?: string;
24
+ private readonly resolveNotReadyAddresses?: boolean;
25
+
26
+ static of(logger: Logger, config: KubernetesConfig, tracker?: ClusterTopologyIntentTracker): KubernetesApiEndpointResolver {
27
+ return new KubernetesApiEndpointResolver(logger, buildKubernetesClient(config, tracker),
28
+ config.serviceName, config.servicePort, config.serviceLabelName,
29
+ config.serviceLabelValue, config.podLabelName, config.podLabelValue, config.resolveNotReadyAddresses);
30
+ }
31
+
32
+ /*testing*/ constructor(logger: Logger,
33
+ client: KubernetesClient,
34
+ serviceName?: string,
35
+ port: number = 0,
36
+ serviceLabel?: string,
37
+ serviceLabelValue?: string,
38
+ podLabel?: string,
39
+ podLabelValue?: string,
40
+ resolveNotReadyAddresses?: boolean) {
41
+ super(logger);
42
+ this.client = client;
43
+ this.serviceName = serviceName;
44
+ this.port = port;
45
+ this.serviceLabel = serviceLabel;
46
+ this.serviceLabelValue = serviceLabelValue;
47
+ this.podLabel = podLabel;
48
+ this.podLabelValue = podLabelValue;
49
+ this.resolveNotReadyAddresses = resolveNotReadyAddresses;
50
+ }
51
+
52
+ async resolve(): Promise<DiscoveryNode[]> {
53
+ if (this.serviceName) {
54
+ return await this.getSimpleDiscoveryNodes(await this.client.endpointsByName(this.serviceName));
55
+ }
56
+ else if (this.serviceLabel) {
57
+ return await this.getSimpleDiscoveryNodes(await this.client.endpointsByServiceLabel(this.serviceLabel, this.serviceLabelValue));
58
+ }
59
+ else if (this.podLabel) {
60
+ return await this.getSimpleDiscoveryNodes(await this.client.endpointsByPodLabel(this.podLabel, this.podLabelValue));
61
+ }
62
+ return await this.getSimpleDiscoveryNodes(await this.client.endpoints());
63
+ }
64
+
65
+ private async getSimpleDiscoveryNodes(endpoints: readonly Endpoint[]): Promise<DiscoveryNode[]> {
66
+ const discoveredNodes = new Array<DiscoveryNode>();
67
+ for (const endpoint of endpoints) {
68
+ await this.addAddress(discoveredNodes, endpoint);
69
+ }
70
+ return discoveredNodes;
71
+ }
72
+
73
+ private async addAddress(discoveredNodes: Array<DiscoveryNode>, endpoint: Endpoint): Promise<void> {
74
+ if (this.resolveNotReadyAddresses === true || endpoint.ready) {
75
+ const privateAddress = await this.createAddress(endpoint.privateAddress, this.resolvePort.bind(this));
76
+ const publicAddress = await this.createAddress(endpoint.publicAddress, this.resolvePortPublic.bind(this));
77
+ discoveredNodes.push(new SimpleDiscoveryNode(privateAddress, publicAddress, new Map<string, string>()));
78
+ }
79
+ }
80
+
81
+ private async createAddress(address: EndpointAddress | undefined, portResolver: (address: EndpointAddress) => number): Promise<Address> {
82
+ if (address === undefined) {
83
+ return undefined;
84
+ }
85
+ const ip = address.ip;
86
+ const ipAddress = await this.mapAddress(ip);
87
+ const port = portResolver(address);
88
+ return fromIpAddress(ipAddress, port);
89
+ }
90
+
91
+ private resolvePort(address: EndpointAddress) {
92
+ if (this.port > 0) {
93
+ return this.port;
94
+ }
95
+ if (address.port) {
96
+
97
+ return address.port;
98
+ }
99
+ return NetworkConfig.DEFAULT_PORT;
100
+ }
101
+
102
+ private resolvePortPublic(address: EndpointAddress) {
103
+ if (address.port) {
104
+ return address.port;
105
+ }
106
+ if (this.port > 0) {
107
+ return this.port;
108
+ }
109
+ return NetworkConfig.DEFAULT_PORT;
110
+ }
111
+ }
@@ -0,0 +1,75 @@
1
+ import {Endpoint, EndpointAddress} from './KubernetesClient.ts';
2
+
3
+ export interface KubernetesApiProvider {
4
+ getEndpointsByNameUrlString(kubernetesMaster: string, namespace: string, endpointName: string): string;
5
+
6
+ getEndpointsByServiceLabelUrlString(kubernetesMaster: string, namespace: string, serviceLabel: string): string;
7
+
8
+ parseEndpoints(param: any): Endpoint[];
9
+ }
10
+
11
+ export class KubernetesApiEndpointSlicesProvider implements KubernetesApiProvider {
12
+ getEndpointsByServiceLabelUrlString(kubernetesMaster: string, namespace: string, param: string): string {
13
+ return `${kubernetesMaster}/apis/discovery.k8s.io/v1/namespaces/${namespace}/endpointslices?${param}`;
14
+ }
15
+
16
+ getEndpointsByNameUrlString(kubernetesMaster: string, namespace: string, endpointName: string): string {
17
+ return `${kubernetesMaster}/apis/discovery.k8s.io/v1/namespaces/${namespace}/endpointslices?labelSelector=kubernetes.io/service-name=${endpointName}`;
18
+ }
19
+
20
+ parseEndpoints(param: {
21
+ items: Array<{ endpoints: Array<{ conditions: { ready: boolean }, addresses: Array<string> }>, ports: Array<{}> }>
22
+ }): Endpoint[] {
23
+ const endpoints = new Array<Endpoint>();
24
+ for (const item of param.items) {
25
+ endpoints.push(...this.parseEndpointSlices(item));
26
+ }
27
+ return endpoints;
28
+ }
29
+
30
+ private parseEndpointSlices(item: {
31
+ endpoints: Array<{
32
+ conditions: {
33
+ ready: boolean
34
+ },
35
+ addresses: Array<string>
36
+ }>,
37
+ ports: Array<{name?: string, port?: number}>
38
+ }): Endpoint[] {
39
+ const addresses = new Array<Endpoint>();
40
+ const endpointPort = this.extractPort(item);
41
+ for (const endpoint of item.endpoints) {
42
+ const ready = endpoint.conditions.ready;
43
+ for (const address of endpoint.addresses) {
44
+ addresses.push(new Endpoint(new EndpointAddress({ip: address, port: endpointPort}), undefined, ready))
45
+ }
46
+
47
+ }
48
+ return addresses;
49
+ }
50
+
51
+ private extractPort(item: {
52
+ ports: Array<{
53
+ name?: string,
54
+ port?: number
55
+
56
+ }>
57
+ }): number | undefined {
58
+ for (const port of item.ports) {
59
+ const bridgeServicePort = port.name;
60
+ if (bridgeServicePort && bridgeServicePort === 'io-bridge') {
61
+ const servicePort = port.port;
62
+ if (servicePort !== undefined) {
63
+ return servicePort;
64
+ }
65
+ }
66
+ }
67
+ if (item.ports.length === 1) {
68
+ const port = item.ports[0];
69
+ const servicePort = port.port;
70
+ if (servicePort !== undefined) {
71
+ return servicePort;
72
+ }
73
+ }
74
+ }
75
+ }