@interopio/bridge 0.0.1-alpha → 0.0.3-beta
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/bin/bridge.js +1 -1
- package/dist/main.js +2139 -0
- package/dist/main.js.map +7 -0
- package/package.json +9 -6
- package/gen/instance/GeneratedBuildInfo.ts +0 -4
- package/src/cluster/Address.ts +0 -57
- package/src/cluster/Cluster.ts +0 -13
- package/src/cluster/Endpoint.ts +0 -5
- package/src/cluster/Member.ts +0 -9
- package/src/cluster/MembershipListener.ts +0 -6
- package/src/config/Config.ts +0 -100
- package/src/config/DiscoveryConfig.ts +0 -21
- package/src/config/Duration.ts +0 -168
- package/src/config/KubernetesConfig.ts +0 -7
- package/src/config/NamedDiscoveryConfig.ts +0 -17
- package/src/config/Properties.ts +0 -49
- package/src/config/index.ts +0 -1
- package/src/discovery/SimpleDiscoveryNode.ts +0 -14
- package/src/discovery/index.ts +0 -207
- package/src/discovery/multicast/MulticastDiscoveryStrategy.ts +0 -141
- package/src/discovery/multicast/MulticastDiscoveryStrategyFactory.ts +0 -30
- package/src/discovery/multicast/MulticastProperties.ts +0 -4
- package/src/discovery/settings.ts +0 -37
- package/src/error/RequestFailure.ts +0 -48
- package/src/gossip/ApplicationState.ts +0 -48
- package/src/gossip/EndpointState.ts +0 -141
- package/src/gossip/FailureDetector.ts +0 -235
- package/src/gossip/Gossiper.ts +0 -1133
- package/src/gossip/HeartbeatState.ts +0 -66
- package/src/gossip/Messenger.ts +0 -130
- package/src/gossip/VersionedValue.ts +0 -59
- package/src/index.ts +0 -3
- package/src/instance/AddressPicker.ts +0 -245
- package/src/instance/BridgeNode.ts +0 -141
- package/src/instance/ClusterTopologyIntentTracker.ts +0 -4
- package/src/io/VersionedSerializer.ts +0 -230
- package/src/io/util.ts +0 -117
- package/src/kubernetes/DnsEndpointResolver.ts +0 -70
- package/src/kubernetes/KubernetesApiEndpointResolver.ts +0 -111
- package/src/kubernetes/KubernetesApiProvider.ts +0 -75
- package/src/kubernetes/KubernetesClient.ts +0 -264
- package/src/kubernetes/KubernetesConfig.ts +0 -130
- package/src/kubernetes/KubernetesDiscoveryStrategy.ts +0 -30
- package/src/kubernetes/KubernetesDiscoveryStrategyFactory.ts +0 -71
- package/src/kubernetes/KubernetesEndpointResolver.ts +0 -43
- package/src/kubernetes/KubernetesProperties.ts +0 -22
- package/src/license/BridgeLicenseValidator.ts +0 -19
- package/src/license/LicenseValidator.ts +0 -114
- package/src/license/types.ts +0 -40
- package/src/logging.ts +0 -22
- package/src/main.mts +0 -53
- package/src/net/Action.ts +0 -143
- package/src/net/AddressSerializer.ts +0 -44
- package/src/net/ByteBufferAllocator.ts +0 -27
- package/src/net/FrameDecoder.ts +0 -314
- package/src/net/FrameEncoder.ts +0 -138
- package/src/net/HandshakeProtocol.ts +0 -143
- package/src/net/InboundConnection.ts +0 -108
- package/src/net/InboundConnectionInitiator.ts +0 -150
- package/src/net/InboundMessageHandler.ts +0 -377
- package/src/net/InboundSink.ts +0 -38
- package/src/net/Message.ts +0 -428
- package/src/net/OutboundConnection.ts +0 -1141
- package/src/net/OutboundConnectionInitiator.ts +0 -76
- package/src/net/RequestCallbacks.ts +0 -148
- package/src/net/ResponseHandler.ts +0 -30
- package/src/net/ShareableBytes.ts +0 -125
- package/src/net/internal/AsyncResourceExecutor.ts +0 -464
- package/src/net/internal/AsyncSocketPromise.ts +0 -37
- package/src/net/internal/channel/ChannelHandlerAdapter.ts +0 -99
- package/src/net/internal/channel/types.ts +0 -188
- package/src/utils/bigint.ts +0 -23
- package/src/utils/buffer.ts +0 -434
- package/src/utils/clock.ts +0 -148
- package/src/utils/collections.ts +0 -283
- package/src/utils/crc.ts +0 -39
- package/src/utils/internal/IpAddressUtil.ts +0 -161
- package/src/utils/memory/BufferPools.ts +0 -40
- package/src/utils/network.ts +0 -130
- package/src/utils/promise.ts +0 -38
- package/src/utils/uuid.ts +0 -5
- package/src/utils/vint.ts +0 -238
- package/src/version/MemberVersion.ts +0 -42
- package/src/version/Version.ts +0 -12
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type {DataInput, DataOutput, VersionedSerializer} from '../io/VersionedSerializer.ts';
|
|
2
|
-
import {getNextVersion} from './VersionedValue.ts';
|
|
3
|
-
|
|
4
|
-
export const EMPTY_VERSION = -1;
|
|
5
|
-
|
|
6
|
-
export class HeartbeatState {
|
|
7
|
-
private _generation: number;
|
|
8
|
-
private _version: number;
|
|
9
|
-
|
|
10
|
-
constructor(generation: number, version?: number) {
|
|
11
|
-
this._generation = generation;
|
|
12
|
-
this._version = version ?? 0;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
copy(): HeartbeatState {
|
|
16
|
-
return new HeartbeatState(this._generation, this._version);
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public static empty(): HeartbeatState {
|
|
21
|
-
return new HeartbeatState(-1);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public isEmpty(): boolean {
|
|
25
|
-
return this.generation === EMPTY_VERSION;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public get generation(): number {
|
|
29
|
-
return this._generation;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
updateHeartbeatVersion(): void {
|
|
33
|
-
this._version = getNextVersion();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public get version(): number {
|
|
37
|
-
return this._version;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/*unsafe*/ forceNewerGeneration(): void {
|
|
41
|
-
this._generation += 1;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/*testing*/ forceHighestPossibleVersion(): void {
|
|
45
|
-
this._version = Number.MAX_SAFE_INTEGER;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
toString(): string {
|
|
49
|
-
return `Heartbeat: {generation: ${this.generation}, version: ${this.version}}`;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const HeartbeatStateSerializer = new (class implements VersionedSerializer<HeartbeatState> {
|
|
54
|
-
serialize(value: HeartbeatState, output: DataOutput, version: number): void {
|
|
55
|
-
output.writeInt32(value.generation);
|
|
56
|
-
output.writeInt32(value.version);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
deserialize(input: DataInput, version: number): HeartbeatState {
|
|
60
|
-
return new HeartbeatState(input.readInt32(), input.readInt32());
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
serializedSize(value: HeartbeatState, version: number): number {
|
|
64
|
-
return 8;
|
|
65
|
-
}
|
|
66
|
-
});
|
package/src/gossip/Messenger.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {type Address, addressAsString} from '../cluster/Address.ts';
|
|
2
|
-
import {ObjectMap, ObjectSet} from '../utils/collections.ts';
|
|
3
|
-
import {OutboundConnection, OutboundConnectionSettings} from '../net/OutboundConnection.ts';
|
|
4
|
-
import {InboundSocket} from '../net/InboundConnection.ts';
|
|
5
|
-
import {getInbound, InboundMessageHandlers} from '../net/InboundMessageHandler.ts';
|
|
6
|
-
import {type Message, MessageFactory} from '../net/Message.ts';
|
|
7
|
-
import {RequestCallbacks, type RequestCallback} from '../net/RequestCallbacks.ts';
|
|
8
|
-
import {InboundSink} from '../net/InboundSink.ts';
|
|
9
|
-
import getLogger from '../logging.ts';
|
|
10
|
-
import {fromId} from '../net/Action.ts';
|
|
11
|
-
|
|
12
|
-
const logger = getLogger('messaging');
|
|
13
|
-
|
|
14
|
-
export interface MessageDelivery {
|
|
15
|
-
send<T>(message: Message<T>, to: Address): void
|
|
16
|
-
sendWithCallback<T, R>(message: Message<T>, to: Address, callback: RequestCallback<R>): void
|
|
17
|
-
readonly callbacks: RequestCallbacks;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Messenger extends MessageDelivery {
|
|
21
|
-
listen(): Promise<void>
|
|
22
|
-
//
|
|
23
|
-
markExpiredCallback(address: Address): void;
|
|
24
|
-
|
|
25
|
-
closeOutbound(endpoint: Address): void;
|
|
26
|
-
|
|
27
|
-
removeInbound(from: Address): void;
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
class OutboundSink {
|
|
32
|
-
private readonly sink: (message: Message<unknown>, to: Address) => void;
|
|
33
|
-
|
|
34
|
-
constructor(sink: (message: Message<unknown>, to: Address) => void) {
|
|
35
|
-
this.sink = sink;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
accept(message: Message<unknown>, to: Address): void {
|
|
39
|
-
this.sink(message, to);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class MessagingService implements Messenger {
|
|
44
|
-
public static CURRENT_VERSION = 12;
|
|
45
|
-
public readonly callbacks: RequestCallbacks = new RequestCallbacks(this);
|
|
46
|
-
public readonly inboundSink: InboundSink;
|
|
47
|
-
public readonly outboundSink = new OutboundSink(this.doSend.bind(this));
|
|
48
|
-
private sockets: Map<Address, OutboundConnection> = new ObjectMap<Address, OutboundConnection>();
|
|
49
|
-
private handlers: Map<Address, InboundMessageHandlers> = new ObjectMap<Address, InboundMessageHandlers>();
|
|
50
|
-
private readonly inboundSocket: InboundSocket;
|
|
51
|
-
private shuttingDown: boolean;
|
|
52
|
-
private readonly messageFactory: MessageFactory;
|
|
53
|
-
|
|
54
|
-
constructor(bindAddress: Address, context: {messageFactory: () => MessageFactory}) {
|
|
55
|
-
this.inboundSink = new InboundSink({...context, messaging: () => this});
|
|
56
|
-
this.inboundSocket = new InboundSocket({bindAddress: bindAddress, handlers: this.getInbound.bind(this), handshakeTimeout: 30000, acceptVersions: {min: MessagingService.CURRENT_VERSION, max: 13}});
|
|
57
|
-
this.messageFactory = context.messageFactory();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
send<T>(message: Message<T>, to: Address): void {
|
|
61
|
-
if (this.shuttingDown) {
|
|
62
|
-
logger.warn(`Messenger is shutting down, cannot send message ${message} to ${to}`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (logger.enabledFor('trace')) {
|
|
67
|
-
const from = this.inboundSocket.settings.bindAddress;
|
|
68
|
-
|
|
69
|
-
logger.debug(`${addressAsString(from)} sending ${fromId(message.header.verb().id)}@${message.header.seq} to ${addressAsString(to)}`);
|
|
70
|
-
if (new ObjectSet<Address>([from]).has(to)) {
|
|
71
|
-
logger.debug(`Message is sent to self, ${message}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
this.outboundSink.accept(message, to);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
private doSend(message: Message<unknown>, to: Address) {
|
|
79
|
-
const connection = this.getOutbound(to);
|
|
80
|
-
connection.enqueue(message);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private getOutbound(to: Address): OutboundConnection {
|
|
84
|
-
let connection = this.sockets.get(to);
|
|
85
|
-
if (!connection) {
|
|
86
|
-
connection = new OutboundConnection(new OutboundConnectionSettings(this.messageFactory.from, to, this.callbacks));
|
|
87
|
-
this.sockets.set(to, connection);
|
|
88
|
-
}
|
|
89
|
-
return connection;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
closeOutbound(to: Address) {
|
|
93
|
-
const connection = this.sockets.get(to);
|
|
94
|
-
if (connection !== undefined) {
|
|
95
|
-
connection.scheduleClose(5, 'minutes', true).promise.then(() => {
|
|
96
|
-
const e = this.sockets.get(to);
|
|
97
|
-
if (e === connection) {
|
|
98
|
-
this.sockets.delete(to);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
removeInbound(from: Address) {
|
|
105
|
-
const handlers = this.handlers.get(from);
|
|
106
|
-
if (handlers) {
|
|
107
|
-
this.handlers.delete(from);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/*private */getInbound(from: Address) {
|
|
112
|
-
return getInbound(from, this.handlers, this.inboundSink, this.inboundSocket.settings);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
sendWithCallback<T, R>(message: Message<T>, to: Address, callback: RequestCallback<R>) {
|
|
116
|
-
this.callbacks.addWithExpiration(callback, message, to);
|
|
117
|
-
if (callback.onFailure !== undefined && !message.callbackOnFailure) {
|
|
118
|
-
message = message.withCallbackOnFailure();
|
|
119
|
-
}
|
|
120
|
-
this.send(message, to);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
markExpiredCallback(address: Address) {
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async listen() {
|
|
128
|
-
await this.inboundSocket.open()
|
|
129
|
-
}
|
|
130
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type {DataInput, DataOutput, VersionedSerializer} from '../io/VersionedSerializer.ts';
|
|
2
|
-
import {encodedUtfLength} from '../io/util.ts';
|
|
3
|
-
|
|
4
|
-
let version = 0;
|
|
5
|
-
|
|
6
|
-
export function getNextVersion(): number {
|
|
7
|
-
return ++version;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const VersionedValueDelimiter = ',';
|
|
11
|
-
|
|
12
|
-
class VersionedValue {
|
|
13
|
-
public readonly version: number
|
|
14
|
-
public readonly value: string
|
|
15
|
-
|
|
16
|
-
constructor(value: string, version?: number) {
|
|
17
|
-
this.value = value;
|
|
18
|
-
this.version = version ?? getNextVersion();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public withVersion(version: number) {
|
|
22
|
-
return new VersionedValue(this.value, version);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
export type {VersionedValue};
|
|
26
|
-
|
|
27
|
-
class VersionedValueFactory {
|
|
28
|
-
private readonly nextVersion: () => number
|
|
29
|
-
|
|
30
|
-
constructor(version: () => number) {
|
|
31
|
-
this.nextVersion = version ?? getNextVersion;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public uuid(uuid: string): VersionedValue {
|
|
35
|
-
return new VersionedValue(uuid, this.nextVersion());
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const VersionedValueSerializer = new (class implements VersionedSerializer<VersionedValue> {
|
|
40
|
-
serialize(value: VersionedValue, output: DataOutput, version: number) {
|
|
41
|
-
output.writeUtf8String(this.outValue(value, version));
|
|
42
|
-
output.writeInt32(value.version);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
deserialize(input: DataInput, version: number): VersionedValue {
|
|
46
|
-
const value = input.readUtf8String();
|
|
47
|
-
const valueVersion = input.readInt32();
|
|
48
|
-
return new VersionedValue(value, valueVersion);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
serializedSize(value: VersionedValue, version: number): number {
|
|
52
|
-
return 2 + encodedUtfLength(this.outValue(value, version)) + 4;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
outValue(value: VersionedValue, version: number): string {
|
|
57
|
-
return value.value;
|
|
58
|
-
}
|
|
59
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import {type Address} from '../cluster/Address.ts';
|
|
2
|
-
import {getByName, getNetworkInterfaces, type IpAddress} from '../utils/network.ts';
|
|
3
|
-
import { type AddressInfo, Server, createServer} from 'node:net';
|
|
4
|
-
import { type Logger } from '../logging.ts';
|
|
5
|
-
import { type Config} from '../config/Config.ts';
|
|
6
|
-
|
|
7
|
-
export interface AddressPicker {
|
|
8
|
-
pickAddress(): Promise<void>;
|
|
9
|
-
getPublicAddressFor(endpoint: 'member' | 'client'): Address ;
|
|
10
|
-
getServers(): ReadonlyMap<string, Server>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async function createAddress(addressDef:AddressDef, port: number): Promise<Address> {
|
|
14
|
-
if (addressDef.host) {
|
|
15
|
-
return {type: addressDef.ipAddress.family, host: addressDef.host, port};
|
|
16
|
-
}
|
|
17
|
-
return {type: addressDef.ipAddress.family, host: await addressDef.ipAddress.getHost(), port}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function createNetServer(logger: Logger, host: string, range: number | string): Promise<Server> {
|
|
21
|
-
const ports = portRange(range);
|
|
22
|
-
return new Promise((resolve, reject) => {
|
|
23
|
-
let server = createServer({}, () => {});
|
|
24
|
-
server.on('error', (err: Error) => {
|
|
25
|
-
if (err['code'] === 'EADDRINUSE') {
|
|
26
|
-
logger.debug(`port ${err['port']} already in use on address ${err['address']}`);
|
|
27
|
-
const {value: port} = ports.next();
|
|
28
|
-
if (port) {
|
|
29
|
-
logger.info(`retry starting server on port ${port} and host ${host ?? '<unspecified>'}`);
|
|
30
|
-
server.close();
|
|
31
|
-
server.listen(port, host);
|
|
32
|
-
} else {
|
|
33
|
-
logger.warn(`all configured port(s) ${range} are in use. closing...`);
|
|
34
|
-
server.close();
|
|
35
|
-
reject(err);
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
logger.error(`server error: ${err.message}`, err);
|
|
39
|
-
reject(err);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
server.on('listening', () => {
|
|
43
|
-
const info = server.address() as AddressInfo;
|
|
44
|
-
logger.info(`listening on ${info.address}:${info.port}`);
|
|
45
|
-
resolve(server);
|
|
46
|
-
});
|
|
47
|
-
try {
|
|
48
|
-
const {value: port} = ports.next();
|
|
49
|
-
server.listen(port, host);
|
|
50
|
-
} catch (e) {
|
|
51
|
-
logger.error(`error starting socket server`, e);
|
|
52
|
-
reject(e instanceof Error ? e : new Error(`listen failed: ${e}`));
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
class InterfaceAddress {
|
|
58
|
-
readonly address: string;
|
|
59
|
-
readonly host?: string;
|
|
60
|
-
constructor(address: string, host?: string) {
|
|
61
|
-
this.address = address;
|
|
62
|
-
this.host = host;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
class AddressDef extends InterfaceAddress {
|
|
67
|
-
|
|
68
|
-
readonly ipAddress: IpAddress;
|
|
69
|
-
readonly port: number;
|
|
70
|
-
constructor(ipAddress: IpAddress, host?: string, port?: number) {
|
|
71
|
-
super(ipAddress.address, host);
|
|
72
|
-
this.ipAddress = ipAddress;
|
|
73
|
-
this.port = port ?? 0;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export class DefaultAddressPicker implements AddressPicker {
|
|
78
|
-
|
|
79
|
-
private readonly logger: Logger;
|
|
80
|
-
private readonly config: Config;
|
|
81
|
-
private readonly publicAddressConfig?: string;
|
|
82
|
-
private publicAddress: Address;
|
|
83
|
-
private bindAddress: Address;
|
|
84
|
-
private server: Server;
|
|
85
|
-
private readonly port: string | number;
|
|
86
|
-
constructor(config: Config,
|
|
87
|
-
logger: Logger)
|
|
88
|
-
{
|
|
89
|
-
this.logger = logger;
|
|
90
|
-
this.config = config;
|
|
91
|
-
this.port = config.network.port;
|
|
92
|
-
this.publicAddressConfig = config.network.publicAddress;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async pickAddress(): Promise<void> {
|
|
96
|
-
if (this.publicAddress || this.bindAddress)
|
|
97
|
-
{
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const publicAddressDef = await this.getPublicAddressByPortSearch();
|
|
101
|
-
this.publicAddress = this.bindAddress;
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
getPublicAddressFor(endpoint: 'member' | 'client'): Address {
|
|
106
|
-
return this.publicAddress;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
getServers(): ReadonlyMap<string, Server> {
|
|
110
|
-
return new Map([['member', this.server]]);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private async getPublicAddressByPortSearch() {
|
|
114
|
-
const bindAddressDef = await this.pickAddressDef();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.server = await createNetServer(this.logger, '0.0.0.0', bindAddressDef.port === 0 ? this.port: bindAddressDef.port);
|
|
118
|
-
|
|
119
|
-
const port = (this.server.address() as AddressInfo).port;
|
|
120
|
-
this.bindAddress = await createAddress(bindAddressDef, port);
|
|
121
|
-
|
|
122
|
-
return this.getPublicAddress(port);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private async getPublicAddress(port: number) {
|
|
126
|
-
let address = this.publicAddressConfig;
|
|
127
|
-
if (address) {
|
|
128
|
-
address = address.trim();
|
|
129
|
-
if (!address) {
|
|
130
|
-
throw new Error('Public address is empty');
|
|
131
|
-
} else if ('127.0.0.1' === address) {
|
|
132
|
-
return this.pickLoopbackAddressDef(address, port);
|
|
133
|
-
}
|
|
134
|
-
else
|
|
135
|
-
{
|
|
136
|
-
const ipAddress = await getByName(address);
|
|
137
|
-
return new AddressDef(ipAddress, address, port);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private async pickAddressDef() {
|
|
143
|
-
let addressDef = this.pickInterfaceAddressDef();
|
|
144
|
-
if (addressDef) {
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
if (!addressDef) {
|
|
148
|
-
addressDef = await this.pickLoopbackAddressDef();
|
|
149
|
-
}
|
|
150
|
-
return addressDef;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
private pickInterfaceAddressDef(): AddressDef {
|
|
154
|
-
const interfaces = this.getInterfaces();
|
|
155
|
-
if (interfaces) {
|
|
156
|
-
const address = this.pickMatchingAddress(interfaces);
|
|
157
|
-
if (address) {
|
|
158
|
-
return address;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return this.pickMatchingAddress();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private getInterfaces(): InterfaceAddress[] | undefined {
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private async pickLoopbackAddressDef(host?: string, defaultPort?: number) {
|
|
169
|
-
const address = await getByName('127.0.0.1');
|
|
170
|
-
return new AddressDef(address, host, defaultPort);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private match(ipAddress: IpAddress, interfaces: InterfaceAddress[]) {
|
|
174
|
-
for (const iface of interfaces) {
|
|
175
|
-
if (ipAddress.address === iface.address) {
|
|
176
|
-
return iface;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return undefined;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private getMatchingAddress(ipAddress: IpAddress, interfaces?: InterfaceAddress[]) {
|
|
183
|
-
if (interfaces) {
|
|
184
|
-
return this.match(ipAddress, interfaces);
|
|
185
|
-
} else {
|
|
186
|
-
return ipAddress;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private pickMatchingAddress(interfaces?: InterfaceAddress[]): AddressDef | undefined {
|
|
191
|
-
const preferIPv4 = true;
|
|
192
|
-
const networkInterfaces = getNetworkInterfaces();
|
|
193
|
-
let matchingAddress;
|
|
194
|
-
for (const ni of networkInterfaces) {
|
|
195
|
-
if (!interfaces && ni.loopback) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
for (const ipAddress of ni.addresses) {
|
|
199
|
-
if (preferIPv4 && ipAddress.family === 6) {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
const address = this.getMatchingAddress(ipAddress, interfaces);
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return matchingAddress;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// stolen from gateway-server
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const PORT_RANGE_MATCHER = /^(\d+|(0x[\da-f]+))(-(\d+|(0x[\da-f]+)))?$/i;
|
|
216
|
-
function validPort(port: number) {
|
|
217
|
-
if (port > 0xFFFF) throw new Error(`bad port ${port}`);
|
|
218
|
-
return port;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* parse port range. port can be number or string representing comma separated
|
|
223
|
-
* list of port ranges for e.g. "3434,8380-8385"
|
|
224
|
-
* @param port
|
|
225
|
-
*/
|
|
226
|
-
function* portRange(port: number | string): Generator<number> {
|
|
227
|
-
if (typeof port === 'string') {
|
|
228
|
-
for (const portRange of port.split(',')) {
|
|
229
|
-
const trimmed = portRange.trim();
|
|
230
|
-
const matchResult = PORT_RANGE_MATCHER.exec(trimmed);
|
|
231
|
-
if (matchResult) {
|
|
232
|
-
const start = parseInt(matchResult[1]);
|
|
233
|
-
const end = parseInt(matchResult[4] ?? matchResult[1]);
|
|
234
|
-
for (let i = validPort(start); i < validPort(end) + 1; i++) {
|
|
235
|
-
yield i;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
throw new Error(`'${portRange}' is not a valid port or range.`);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
} else {
|
|
243
|
-
yield validPort(port);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import {newUUID} from '../utils/uuid.ts';
|
|
2
|
-
import {DefaultDiscoveryServiceFactory, type DiscoveryService, type DiscoveryServiceSettings} from '../discovery/index.ts';
|
|
3
|
-
import {SimpleDiscoveryNode} from '../discovery/SimpleDiscoveryNode.ts';
|
|
4
|
-
import {type Member} from '../cluster/Member.ts';
|
|
5
|
-
import {type MemberVersion, parseVersion} from '../version/MemberVersion.ts';
|
|
6
|
-
import {type DiscoveryConfig} from '../config/DiscoveryConfig.ts';
|
|
7
|
-
import {VERSION} from '../../gen/instance/GeneratedBuildInfo.ts';
|
|
8
|
-
import {type AddressPicker, DefaultAddressPicker} from './AddressPicker.ts';
|
|
9
|
-
import getLogger, {type Logger} from '../logging.ts';
|
|
10
|
-
import gatewayServer, {GatewayServer} from '@interopio/gateway-server';
|
|
11
|
-
import {Config} from '../config/Config.ts';
|
|
12
|
-
import {BridgeLicenseValidator} from "../license/BridgeLicenseValidator.ts";
|
|
13
|
-
import { type LicenseValidator} from "../license/LicenseValidator.ts";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
function createDiscoveryService(logger: Logger,
|
|
17
|
-
conf: DiscoveryConfig,
|
|
18
|
-
isAutoDetectionEnabled: boolean,
|
|
19
|
-
localMember: Promise<Member>): DiscoveryService {
|
|
20
|
-
const factory = new DefaultDiscoveryServiceFactory();
|
|
21
|
-
|
|
22
|
-
const node = localMember.then(member => new SimpleDiscoveryNode(member.address)) ;
|
|
23
|
-
|
|
24
|
-
const settings: DiscoveryServiceSettings = {
|
|
25
|
-
mode: 'member',
|
|
26
|
-
node: node,
|
|
27
|
-
conf: conf,
|
|
28
|
-
auto: isAutoDetectionEnabled,
|
|
29
|
-
logger: logger,
|
|
30
|
-
};
|
|
31
|
-
return factory.newDiscoveryService(settings);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function createAddressPicker(node: BridgeNode): AddressPicker {
|
|
35
|
-
const config = node.config;
|
|
36
|
-
const logger = node.getLogger('address-picker');
|
|
37
|
-
return new DefaultAddressPicker(config, logger);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export class BridgeNode {
|
|
41
|
-
readonly config: Config;
|
|
42
|
-
private readonly uuid: string;
|
|
43
|
-
private readonly discoveryService: DiscoveryService;
|
|
44
|
-
private readonly version: MemberVersion;
|
|
45
|
-
private server?: GatewayServer.Server;
|
|
46
|
-
private readonly licenseValidator: LicenseValidator;
|
|
47
|
-
|
|
48
|
-
constructor(config: Config) {
|
|
49
|
-
this.config = config;
|
|
50
|
-
|
|
51
|
-
this.licenseValidator = BridgeLicenseValidator(this.getLogger('license-validator'));
|
|
52
|
-
this.licenseValidator.validate(config.license);
|
|
53
|
-
|
|
54
|
-
this.uuid = newUUID();
|
|
55
|
-
this.version = parseVersion(VERSION);
|
|
56
|
-
const addressPicker = createAddressPicker(this);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const localMemberPromise: Promise<Member> = addressPicker.pickAddress()
|
|
60
|
-
.then(() => addressPicker.getPublicAddressFor('member'))
|
|
61
|
-
.then((publicAddress) => {
|
|
62
|
-
return {
|
|
63
|
-
local: true,
|
|
64
|
-
address: publicAddress,
|
|
65
|
-
uuid: this.uuid,
|
|
66
|
-
version: this.version,
|
|
67
|
-
};
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const joinConfig = config.network.join;
|
|
71
|
-
|
|
72
|
-
const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
|
|
73
|
-
|
|
74
|
-
const discoveryConfig: DiscoveryConfig = joinConfig.discovery;
|
|
75
|
-
|
|
76
|
-
this.discoveryService = createDiscoveryService(getLogger("discovery-service"), discoveryConfig, isAutoDetectionEnabled, localMemberPromise);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
getLogger(name: string) {
|
|
80
|
-
return getLogger(name);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private async scheduleLicenseCheck() {
|
|
84
|
-
const task = async () => {
|
|
85
|
-
try {
|
|
86
|
-
this.licenseValidator.validate(this.config.license, {
|
|
87
|
-
logSuccessMessages: false,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
// this.logger.error(error);
|
|
92
|
-
await this.stop();
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const licenseCheckInterval = 1000 * 60 * 60 * 24; // 1 day
|
|
97
|
-
return setInterval(task, licenseCheckInterval);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async start() {
|
|
101
|
-
const config: GatewayServer.ServerConfig = {
|
|
102
|
-
port: this.config.server.port,
|
|
103
|
-
host: this.config.server.host,
|
|
104
|
-
mesh: this.config.server.mesh,
|
|
105
|
-
};
|
|
106
|
-
if (this.config.server.gateway.enabled) {
|
|
107
|
-
config.gateway = {
|
|
108
|
-
clients: {
|
|
109
|
-
inactive_seconds: 0,
|
|
110
|
-
},
|
|
111
|
-
contexts: {
|
|
112
|
-
lifetime: this.config.server.gateway.contexts.lifetime,
|
|
113
|
-
visibility: [{restrictions: 'cluster'}]
|
|
114
|
-
},
|
|
115
|
-
peers: {
|
|
116
|
-
visibility: [{
|
|
117
|
-
domain: 'interop',
|
|
118
|
-
restrictions: 'local'
|
|
119
|
-
}]
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
this.server = await gatewayServer(config);
|
|
124
|
-
if (false) {
|
|
125
|
-
await this.discoveryService.start();
|
|
126
|
-
}
|
|
127
|
-
await this.scheduleLicenseCheck();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async stop() {
|
|
131
|
-
if (this.server)
|
|
132
|
-
{
|
|
133
|
-
await this.server.close()
|
|
134
|
-
}
|
|
135
|
-
try {
|
|
136
|
-
await this.discoveryService.close();
|
|
137
|
-
} catch (e) {
|
|
138
|
-
// ignore
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|