@interopio/bridge 0.0.1-alpha → 0.0.4-beta.0

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 (85) hide show
  1. package/bin/bridge.js +1 -1
  2. package/changelog.md +24 -0
  3. package/dist/main.js +2201 -0
  4. package/dist/main.js.map +7 -0
  5. package/package.json +9 -6
  6. package/gen/instance/GeneratedBuildInfo.ts +0 -4
  7. package/src/cluster/Address.ts +0 -57
  8. package/src/cluster/Cluster.ts +0 -13
  9. package/src/cluster/Endpoint.ts +0 -5
  10. package/src/cluster/Member.ts +0 -9
  11. package/src/cluster/MembershipListener.ts +0 -6
  12. package/src/config/Config.ts +0 -100
  13. package/src/config/DiscoveryConfig.ts +0 -21
  14. package/src/config/Duration.ts +0 -168
  15. package/src/config/KubernetesConfig.ts +0 -7
  16. package/src/config/NamedDiscoveryConfig.ts +0 -17
  17. package/src/config/Properties.ts +0 -49
  18. package/src/config/index.ts +0 -1
  19. package/src/discovery/SimpleDiscoveryNode.ts +0 -14
  20. package/src/discovery/index.ts +0 -207
  21. package/src/discovery/multicast/MulticastDiscoveryStrategy.ts +0 -141
  22. package/src/discovery/multicast/MulticastDiscoveryStrategyFactory.ts +0 -30
  23. package/src/discovery/multicast/MulticastProperties.ts +0 -4
  24. package/src/discovery/settings.ts +0 -37
  25. package/src/error/RequestFailure.ts +0 -48
  26. package/src/gossip/ApplicationState.ts +0 -48
  27. package/src/gossip/EndpointState.ts +0 -141
  28. package/src/gossip/FailureDetector.ts +0 -235
  29. package/src/gossip/Gossiper.ts +0 -1133
  30. package/src/gossip/HeartbeatState.ts +0 -66
  31. package/src/gossip/Messenger.ts +0 -130
  32. package/src/gossip/VersionedValue.ts +0 -59
  33. package/src/index.ts +0 -3
  34. package/src/instance/AddressPicker.ts +0 -245
  35. package/src/instance/BridgeNode.ts +0 -141
  36. package/src/instance/ClusterTopologyIntentTracker.ts +0 -4
  37. package/src/io/VersionedSerializer.ts +0 -230
  38. package/src/io/util.ts +0 -117
  39. package/src/kubernetes/DnsEndpointResolver.ts +0 -70
  40. package/src/kubernetes/KubernetesApiEndpointResolver.ts +0 -111
  41. package/src/kubernetes/KubernetesApiProvider.ts +0 -75
  42. package/src/kubernetes/KubernetesClient.ts +0 -264
  43. package/src/kubernetes/KubernetesConfig.ts +0 -130
  44. package/src/kubernetes/KubernetesDiscoveryStrategy.ts +0 -30
  45. package/src/kubernetes/KubernetesDiscoveryStrategyFactory.ts +0 -71
  46. package/src/kubernetes/KubernetesEndpointResolver.ts +0 -43
  47. package/src/kubernetes/KubernetesProperties.ts +0 -22
  48. package/src/license/BridgeLicenseValidator.ts +0 -19
  49. package/src/license/LicenseValidator.ts +0 -114
  50. package/src/license/types.ts +0 -40
  51. package/src/logging.ts +0 -22
  52. package/src/main.mts +0 -53
  53. package/src/net/Action.ts +0 -143
  54. package/src/net/AddressSerializer.ts +0 -44
  55. package/src/net/ByteBufferAllocator.ts +0 -27
  56. package/src/net/FrameDecoder.ts +0 -314
  57. package/src/net/FrameEncoder.ts +0 -138
  58. package/src/net/HandshakeProtocol.ts +0 -143
  59. package/src/net/InboundConnection.ts +0 -108
  60. package/src/net/InboundConnectionInitiator.ts +0 -150
  61. package/src/net/InboundMessageHandler.ts +0 -377
  62. package/src/net/InboundSink.ts +0 -38
  63. package/src/net/Message.ts +0 -428
  64. package/src/net/OutboundConnection.ts +0 -1141
  65. package/src/net/OutboundConnectionInitiator.ts +0 -76
  66. package/src/net/RequestCallbacks.ts +0 -148
  67. package/src/net/ResponseHandler.ts +0 -30
  68. package/src/net/ShareableBytes.ts +0 -125
  69. package/src/net/internal/AsyncResourceExecutor.ts +0 -464
  70. package/src/net/internal/AsyncSocketPromise.ts +0 -37
  71. package/src/net/internal/channel/ChannelHandlerAdapter.ts +0 -99
  72. package/src/net/internal/channel/types.ts +0 -188
  73. package/src/utils/bigint.ts +0 -23
  74. package/src/utils/buffer.ts +0 -434
  75. package/src/utils/clock.ts +0 -148
  76. package/src/utils/collections.ts +0 -283
  77. package/src/utils/crc.ts +0 -39
  78. package/src/utils/internal/IpAddressUtil.ts +0 -161
  79. package/src/utils/memory/BufferPools.ts +0 -40
  80. package/src/utils/network.ts +0 -130
  81. package/src/utils/promise.ts +0 -38
  82. package/src/utils/uuid.ts +0 -5
  83. package/src/utils/vint.ts +0 -238
  84. package/src/version/MemberVersion.ts +0 -42
  85. package/src/version/Version.ts +0 -12
@@ -1,114 +0,0 @@
1
- import getLogger, {type Logger} from "../logging.ts";
2
- import {
3
- type LicensePayload,
4
- type LicenseEvaluationResult,
5
- type LicenseValidatorOptions,
6
- licenseValidationResults, type LicenseValidationOptions
7
- } from "./types.ts";
8
- import {KJUR} from 'jsrsasign';
9
-
10
- export class LicenseError extends Error {
11
- public readonly licensePayload: LicensePayload | string;
12
-
13
- constructor(message: string, licensePayload: string | LicensePayload) {
14
- super(message);
15
- this.licensePayload = licensePayload;
16
- }
17
- }
18
-
19
- export class LicenseEvaluator {
20
- private readonly tokenResultMap = {
21
- 'trial-false': licenseValidationResults.TRIAL_LICENSE_VALID,
22
- 'trial-true': licenseValidationResults.TRIAL_LICENSE_EXPIRED,
23
- 'paid-false': licenseValidationResults.PAID_LICENSE_VALID,
24
- 'paid-true': licenseValidationResults.PAID_LICENSE_EXPIRED,
25
- };
26
-
27
- private readonly validationKey: string;
28
-
29
- constructor(validationKey: string) {
30
- if (!validationKey || typeof validationKey !== 'string') {
31
- throw new Error(`Validation key must be a non-empty string`);
32
- }
33
- this.validationKey = validationKey;
34
- }
35
-
36
- private decrypt(token: string): object {
37
- if (KJUR.jws.JWS.verifyJWT(token, this.validationKey, {alg: ['RS256']})) {
38
- return KJUR.jws.JWS.parse(token).payloadObj;
39
- } else {
40
- throw new LicenseError('invalid jwt token', token);
41
- }
42
- }
43
-
44
- private validateBasicTokenData(token: string): LicensePayload {
45
- const decoded = this.decrypt(token) as LicensePayload;
46
- if (['paid', 'trial'].indexOf(decoded.type) === -1) {
47
- throw new LicenseError('Invalid license type', token);
48
- }
49
- return decoded;
50
- }
51
-
52
- getLicenseStatus(token: string, now: Date = new Date()): LicenseEvaluationResult {
53
- try {
54
- const license = this.validateBasicTokenData(token);
55
- const isExpired = license.expiration < now.getTime();
56
- const licenseValidationResult = this.tokenResultMap[`${license.type}-${isExpired}`];
57
- return {
58
- ...licenseValidationResult,
59
- license
60
- };
61
- } catch (e) {
62
- return {
63
- ...licenseValidationResults.NO_LICENSE,
64
- error: e.message,
65
- };
66
- }
67
-
68
- }
69
- }
70
-
71
- export class LicenseValidator {
72
- private readonly licenseHelper: LicenseEvaluator;
73
- private readonly logger: Logger;
74
-
75
- constructor({validationKey, logger}: LicenseValidatorOptions) {
76
- this.licenseHelper = new LicenseEvaluator(validationKey);
77
- this.logger = logger ?? getLogger("LicenseValidator"); // Default to console if no logger provided
78
- }
79
-
80
- public validate(licenseKeyString: string, options?: LicenseValidationOptions): void {
81
- if (typeof licenseKeyString !== 'string') {
82
- throw new LicenseError('Invalid license key format', licenseKeyString);
83
- }
84
-
85
- const licenseStatus = this.licenseHelper.getLicenseStatus(licenseKeyString);
86
- this.printLicenseMessage(licenseStatus, options?.logSuccessMessages ?? true);
87
- if (licenseStatus.fatal) {
88
- throw new LicenseError('License validation failed', licenseStatus.license);
89
- }
90
- }
91
-
92
- private printLicenseMessage(licenseStatus: LicenseEvaluationResult, logSuccessMessages: boolean): void {
93
- if (!licenseStatus || licenseStatus.licenseType === 'none') {
94
- this.logger.error('This license is invalid. Please contact us at sales@interop.io to get a valid license');
95
- return;
96
- }
97
-
98
- const message = [
99
- licenseStatus.licenseType === 'paid' ? `This is a paid license that was issued for client ` : `This is a trial license that was issued for `,
100
- licenseStatus.license.organization.displayName,
101
- licenseStatus.expired ? `, but it has expired at ` : ` and is valid until `,
102
- new Date(licenseStatus.license.expiration).toString(),
103
- '.'
104
- ].join('');
105
-
106
- if (licenseStatus.fatal) {
107
- this.logger.error(message);
108
- } else if (licenseStatus.expired) {
109
- this.logger.warn(message);
110
- } else if(logSuccessMessages) {
111
- this.logger.info(message);
112
- }
113
- }
114
- }
@@ -1,40 +0,0 @@
1
- import type {Logger} from "../logging.ts";
2
-
3
- export type LicenseValidatorOptions = {
4
- validationKey: string;
5
- logger?: Logger
6
- }
7
-
8
- export type LicenseValidationOptions = {
9
- logSuccessMessages?: boolean
10
- };
11
-
12
- export type LicensePayload = {
13
- "type": "paid" | "trial";
14
- "expiration": number // in milliseconds
15
- "email": string,
16
- "issuedBy": string;
17
- "iat": number; // in seconds
18
- "licensee": string;
19
- "organization": {
20
- "displayName": string,
21
- "identifier": string
22
- }
23
- }
24
-
25
- export type LicenseEvaluationResult = {
26
- licenseType: 'paid' | 'trial' | 'none';
27
- expired: boolean;
28
- fatal: boolean;
29
- license?: LicensePayload;
30
- error?: string;
31
- }
32
-
33
-
34
- export const licenseValidationResults = {
35
- TRIAL_LICENSE_EXPIRED: {licenseType: 'trial', expired: true, fatal: true} as LicenseEvaluationResult,
36
- TRIAL_LICENSE_VALID: {licenseType: 'trial', expired: false, fatal: false} as LicenseEvaluationResult,
37
- PAID_LICENSE_EXPIRED: {licenseType: 'paid', expired: true, fatal: false} as LicenseEvaluationResult,
38
- PAID_LICENSE_VALID: {licenseType: 'paid', expired: false, fatal: false} as LicenseEvaluationResult,
39
- NO_LICENSE: {licenseType: 'none', expired: false, fatal: true} as LicenseEvaluationResult,
40
- };
package/src/logging.ts DELETED
@@ -1,22 +0,0 @@
1
- import {IOGateway} from '@interopio/gateway';
2
-
3
- export type Logger = ReturnType<typeof IOGateway.Logging.getLogger>;
4
- IOGateway.Logging.getLogger(`gateway.server.app`); // ensure the logger is created
5
- IOGateway.Logging.getLogger(`gateway.bridge`); // ensure the logger is created
6
- IOGateway.Logging.getLogger(`gateway.bridge.gossiper`); // ensure the logger is created
7
- IOGateway.Logging.getLogger(`gateway.bridge.net.callbacks`); // ensure the logger is created
8
- IOGateway.Logging.configure({
9
- level: {
10
- "gateway": 'info',
11
- "gateway.server": 'trace',
12
- "gateway.server.app": 'info',
13
- "gateway.bridge": 'trace',
14
- "gateway.bridge.gossiper": 'info',
15
- // "gateway.bridge.net.callbacks": 'debug'
16
- "gateway.bridge.net.internal.channel": 'debug'
17
- }
18
- });
19
-
20
- export default function getLogger(name: string): Logger {
21
- return IOGateway.Logging.getLogger(`gateway.bridge.${name}`);
22
- }
package/src/main.mts DELETED
@@ -1,53 +0,0 @@
1
- import {BridgeNode} from './instance/BridgeNode.ts';
2
- import {Config} from './config/Config.ts';
3
- import {BOOLEAN, NUMBER, type PropertyType, type PropertyTypeConverter, STRING} from './config/Properties.ts';
4
-
5
- import info from '@interopio/bridge/package.json' with {type: 'json'};
6
-
7
- let hadFatalError = false;
8
- const reportedErrors = new Set();
9
- function onFatalError(error) {
10
-
11
- process.exitCode = 2;
12
- hadFatalError = true;
13
-
14
- const errorMessage = `io.Bridge: ${info.version}`
15
-
16
- if (!reportedErrors.has(errorMessage)) {
17
- console.error(error);
18
- reportedErrors.add(errorMessage);
19
- }
20
- }
21
-
22
- function loadConfig<T extends PropertyType=string>(name: string, converter: PropertyTypeConverter<T>): T | undefined {
23
- const cmdArg = process.argv.find(arg => {return arg.startsWith(`--${name}=`);})?.split('=')[1];
24
- if (cmdArg) {
25
- return converter.convert(cmdArg);
26
- }
27
- const envKey = `IO_BRIDGE_${name.toUpperCase().replace('-', '_').replace('.', '_')}`;
28
- const envVar = process.env[envKey];
29
- if (envVar) {
30
- return converter.convert(envVar);
31
- }
32
- }
33
-
34
- try {
35
- process.on('uncaughtException', onFatalError);
36
- process.on('unhandledRejection', onFatalError);
37
-
38
- await import('dotenv/config');
39
- const config = new Config();
40
- config.license ??= loadConfig('license-key', STRING);
41
- config.server.port ??= loadConfig('server.port', NUMBER) ?? 8383;
42
- config.server.host ??= loadConfig('server.host', STRING);
43
- config.server.mesh.ping ??= loadConfig('mesh.ping-interval', NUMBER);
44
- config.server.gateway.enabled ??= loadConfig('gateway.enabled', BOOLEAN);
45
- config.server.gateway.contexts.lifetime ??= loadConfig('gateway.contexts.lifetime', STRING) as 'retained' | 'ref-counted' | 'ownership';
46
- const bridge = new BridgeNode(config);
47
-
48
- await bridge.start();
49
-
50
- }
51
- catch (error) {
52
- onFatalError(error);
53
- }
package/src/net/Action.ts DELETED
@@ -1,143 +0,0 @@
1
- import {type Message, type MessageFactory} from './Message.ts';
2
- import type {DataInput, DataOutput, VersionedSerializer} from '../io/VersionedSerializer.ts';
3
- import {convert, type Unit} from '../config/Duration.ts';
4
- import {
5
- type Gossiper,
6
- type GossipDigestSyn,
7
- type GossipDigestAck,
8
- type GossipDigestAck2,
9
- gossipDigestSynHandler,
10
- gossipDigestAckHandler,
11
- gossipDigestAck2Handler,
12
- echoHandler,
13
- GossipDigestSynSerializer,
14
- GossipDigestAckSerializer,
15
- GossipDigestAck2Serializer
16
- } from '../gossip/Gossiper.ts';
17
- import {type RequestFailureReason, RequestFailureReasonSerializer} from '../error/RequestFailure.ts';
18
- import type {MessageDelivery} from '../gossip/Messenger.ts';
19
- import {responseHandler} from './ResponseHandler.ts';
20
- import {maxn} from '../utils/bigint.ts';
21
-
22
- const timeouts: {[keys: string]: (unit: Unit) => bigint} = {
23
- rpcTimeout: (unit: Unit) => convert(unit, 10, 'seconds'),
24
- writeTimeout: (unit: Unit) => convert(unit, 2, 'seconds'),
25
- longTimeout: (unit: Unit) => maxn(timeouts.rpcTimeout(unit), convert(unit, 5, 'minutes')),
26
- noTimeout: (unit: Unit) => { throw new Error(''); }
27
- }
28
-
29
- export interface VerbHandler<T> {
30
- doVerb(message: Message<T>) : void
31
- }
32
-
33
- export type VerbHandlerContext = {
34
- messageFactory: () => MessageFactory;
35
- messaging: () => MessageDelivery
36
- gossiper: () => Gossiper
37
- }
38
-
39
- export interface Verb<T> {
40
- readonly id: number
41
- readonly expirationNs: () => bigint
42
- readonly serializer: VersionedSerializer<T>
43
- handler(context: VerbHandlerContext): VerbHandler<T>
44
- expiresAt(createdAt: bigint): bigint
45
-
46
- responseVerb?: Verb<unknown>
47
- }
48
-
49
-
50
- class NetVerb<T> implements Verb<T> {
51
- readonly id: number;
52
- readonly expiration: (unit: Unit) => bigint;
53
- private readonly _serializer: () => VersionedSerializer<T>;
54
- private readonly _handler: (context: VerbHandlerContext) => VerbHandler<T>;
55
- private readonly _responseVerb?: () => Verb<unknown>;
56
-
57
- constructor(id: number,
58
- expiration: (unit: Unit) => bigint,
59
- serializer: () => VersionedSerializer<T>,
60
- handler: (context: VerbHandlerContext) => VerbHandler<T>,
61
- responseVerb?: () => Verb<unknown>) {
62
- this.id = id;
63
- this.expiration = expiration;
64
- this._serializer = serializer;
65
- this._handler = handler;
66
- this._responseVerb = responseVerb;
67
- }
68
-
69
- get serializer(): VersionedSerializer<T> {
70
- return this._serializer();
71
- }
72
-
73
- handler(context: VerbHandlerContext): VerbHandler<T> {
74
- return this._handler(context);
75
- }
76
-
77
- expiresAt(nowNs: bigint): bigint {
78
- return nowNs + this.expiration('nanoseconds');
79
- }
80
-
81
- expirationNs(): bigint {
82
- return this.expiration('nanoseconds');
83
- }
84
-
85
- get responseVerb(): Verb<unknown> | undefined {
86
- return this._responseVerb ? this._responseVerb() : undefined;
87
- }
88
-
89
- /* testing */ unsafeSetHandler(handler: (context: VerbHandlerContext) => VerbHandler<T>) {
90
- const original = this._handler;
91
- (this as any)._handler = handler;
92
- return original;
93
- }
94
- }
95
-
96
- export class NoPayload {
97
- static readonly instance = new NoPayload();
98
- toString() {
99
- return '<NoPayload>';
100
- }
101
- }
102
- export const NoPayloadSerializer: VersionedSerializer<NoPayload> = new (class implements VersionedSerializer<NoPayload> {
103
- serialize(value: NoPayload, output: DataOutput, version?: number) {
104
- if (value !== NoPayload.instance) {
105
- throw new Error('NoPayload can only be serialized as NoPayload.instance');
106
- }
107
- }
108
-
109
- deserialize(input: DataInput, version?: number): NoPayload {
110
- return NoPayload.instance;
111
- }
112
-
113
- serializedSize(value: NoPayload, version?: number): number {
114
- return 0;
115
- }
116
- });
117
-
118
- export const Verbs = {
119
- GOSSIP_DIGEST_SYN: new NetVerb<GossipDigestSyn>(14, timeouts.longTimeout, () => GossipDigestSynSerializer, gossipDigestSynHandler),
120
- GOSSIP_DIGEST_ACK: new NetVerb<GossipDigestAck>(15, timeouts.longTimeout, () => GossipDigestAckSerializer, gossipDigestAckHandler),
121
- GOSSIP_DIGEST_ACK2: new NetVerb<GossipDigestAck2>(16, timeouts.longTimeout, () => GossipDigestAck2Serializer, gossipDigestAck2Handler),
122
- // GOSSIP_SHUTDOWN: new NetVerb<GossipShutdown>(29, timeouts.longTimeout, () => GossipShutdownSerializer, gossipShutdownHandler),
123
-
124
- ECHO_RSP: new NetVerb<NoPayload>(91, timeouts.rpcTimeout, () => NoPayloadSerializer, responseHandler),
125
- ECHO_REQ: new NetVerb<NoPayload>(31, timeouts.rpcTimeout, () => NoPayloadSerializer, echoHandler, () => Verbs.ECHO_RSP),
126
-
127
- // generic failure
128
- FAILURE_RESPONSE: new NetVerb<RequestFailureReason>(99, timeouts.noTimeout, () => RequestFailureReasonSerializer, responseHandler),
129
-
130
- // dummy verb for testing
131
- _TEST1: new NetVerb<NoPayload>(10, timeouts.writeTimeout, () => NoPayloadSerializer, () => undefined)
132
- };
133
-
134
- export type MessageType = keyof typeof Verbs;
135
-
136
- export function fromId(id: number): MessageType {
137
- for (const [key, value] of Object.entries<Verb<unknown>>(Verbs)) {
138
- if (value.id === id) {
139
- return key as MessageType;
140
- }
141
- }
142
- throw new Error(`Unknown verb id: ${id}`);
143
- }
@@ -1,44 +0,0 @@
1
- import type {DataInput, DataOutput, VersionedSerializer} from '../io/VersionedSerializer.ts';
2
- import {type Address, fromIpAddress} from '../cluster/Address.ts';
3
- import {getByAddress} from '../utils/network.ts';
4
-
5
- class AddressSerializer implements VersionedSerializer<Address> {
6
- readonly MAX_SIZE = 1 + 16 + 2; // 1 byte for length, 16 bytes for address, 2 bytes for port
7
- serialize(value: Address, output: DataOutput, version?: number) {
8
- this.serializeAddressAndPort(value.address.addressBytes, value.port, output, version);
9
- }
10
- deserialize(input: DataInput, version?: number): Address {
11
- const size = input.readInt8() & 0xFF;
12
- switch (size) {
13
- case 4:
14
- case 16:
15
- throw new Error(`unexpected address size: ${size}`);
16
- case 6:
17
- case 18: {
18
- const address = new Uint8Array(size - 2);
19
- input.readUint8Array(address);
20
- const port = input.readInt16() & 0xFFFF;
21
-
22
- const ipAddress = getByAddress(undefined, address);
23
- return fromIpAddress(ipAddress, port);
24
- }
25
- default:
26
- throw new Error(`unexpected address size: ${size}`);
27
- }
28
- }
29
-
30
- private serializeAddressAndPort(address: Uint8Array, port: number, output: DataOutput, version?: number) {
31
- output.writeUint8(address.length + 2);
32
- output.writeUint8Array(address);
33
- output.writeUint16(port);
34
- }
35
-
36
- serializedSize(value: Address, version?: number): number {
37
- if (value.type === 4) {
38
- return 1 + 4 + 2;
39
- }
40
- return 1 + 16 + 2;
41
- }
42
- }
43
-
44
- export const addressSerializer = new AddressSerializer();
@@ -1,27 +0,0 @@
1
- import type {ByteBuffer} from '../utils/buffer.ts';
2
- import {forNetworking} from '../utils/memory/BufferPools.ts';
3
-
4
- const bufferPool= forNetworking();
5
-
6
- abstract class ByteBufferAllocator {
7
-
8
- getAtLeast(size: number): ByteBuffer {
9
- return bufferPool.getAtLeast(size);
10
- }
11
-
12
- put(buffer: ByteBuffer) {
13
- return bufferPool.put(buffer);
14
- }
15
- }
16
-
17
- export type {ByteBufferAllocator};
18
-
19
- class GlobalByteBufferAllocator extends ByteBufferAllocator {
20
- public static readonly instance= new GlobalByteBufferAllocator();
21
-
22
- private constructor() {
23
- super();
24
- }
25
- }
26
-
27
- export const globalByteBufferAllocator: ByteBufferAllocator = GlobalByteBufferAllocator.instance;