@persistica/flux-mesh 0.0.1 → 0.0.4
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/README.md +9 -0
- package/main.js +6 -0
- package/package.json +24 -21
- package/build.js +0 -21
- package/message-routing.excalidraw +0 -2433
- package/project.json +0 -80
- package/src/_classes/web-rtc-client-interface.class.ts +0 -79
- package/src/_routes/auth/network-authority.post.route.ts +0 -74
- package/src/_routes/auth/network-client.post.route.ts +0 -169
- package/src/_routes/options.route.ts +0 -9
- package/src/auth/auth.ts +0 -29
- package/src/business-logic/channels/channel-manager.class.ts +0 -209
- package/src/index.ts +0 -3
- package/src/main.ts +0 -680
- package/src/orchestrators/facilitate-webrtc-connection.class.ts +0 -23
- package/src/register/network-client-manager.class.ts +0 -175
- package/src/register/register-network-authority.class.ts +0 -123
- package/src/routing/addressing.utils.ts +0 -34
- package/src/routing/global-channel/global-channel-pubsub.class.ts +0 -76
- package/src/routing/incomming-message-router.class.ts +0 -47
- package/src/routing/outgoing-message-router.class.ts +0 -72
- package/src/routing/process-message-router.class.ts +0 -85
- package/src/routing/redis/hash/network-agent.redis.sorted-set.ts +0 -60
- package/src/routing/redis/network-agent.redis.ts +0 -135
- package/src/routing/redis/redis-connection.class.ts +0 -261
- package/src/routing/rpc/core/global-rpc-client.class.ts +0 -215
- package/src/test.spec.ts +0 -7
- package/tsconfig.json +0 -23
- package/tsconfig.lib.json +0 -20
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
GlobalWebRTCClient,
|
|
3
|
-
WebRTCClient,
|
|
4
|
-
} from '../_classes/web-rtc-client-interface.class';
|
|
5
|
-
|
|
6
|
-
export const facilitateWebRTCConnection = async (
|
|
7
|
-
initiator: WebRTCClient | GlobalWebRTCClient,
|
|
8
|
-
remoteClient: GlobalWebRTCClient
|
|
9
|
-
) => {
|
|
10
|
-
// console.log('Orchestrate ICS COnnection', initiator, remoteClient);
|
|
11
|
-
|
|
12
|
-
// initiator.
|
|
13
|
-
const offer = await initiator.createOffer();
|
|
14
|
-
console.log('Created offer:', !!offer);
|
|
15
|
-
|
|
16
|
-
const answer = await remoteClient.acceptOfferAndCreateAnswer(offer);
|
|
17
|
-
console.log('Got answer:', !!answer);
|
|
18
|
-
|
|
19
|
-
const acceptAnswer: boolean = await initiator.acceptAnswer(answer);
|
|
20
|
-
console.log('Answer was accepted by initiator:', acceptAnswer);
|
|
21
|
-
|
|
22
|
-
await remoteClient.answerWasAccepted(acceptAnswer);
|
|
23
|
-
};
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type RedisConnection,
|
|
3
|
-
getMeshRedisConnection,
|
|
4
|
-
} from '../routing/redis/redis-connection.class';
|
|
5
|
-
import type {
|
|
6
|
-
NetworkAgentRedisService,
|
|
7
|
-
} from '@flux/mesh/store/redis/network-agent';
|
|
8
|
-
import {
|
|
9
|
-
NetworkUsageRedisCacheService,
|
|
10
|
-
} from '@flux/mesh/store/redis/network-usage';
|
|
11
|
-
import type {
|
|
12
|
-
TAddress,
|
|
13
|
-
TClientId,
|
|
14
|
-
TAgentOwnUId,
|
|
15
|
-
TNetworkId_S,
|
|
16
|
-
} from '@flux/shared/types';
|
|
17
|
-
import type {
|
|
18
|
-
TFluxClientUID,
|
|
19
|
-
} from '@flux/shared/utils';
|
|
20
|
-
|
|
21
|
-
export class NetworkAgentManager {
|
|
22
|
-
public readonly networkAgentRedisService: NetworkAgentRedisService;
|
|
23
|
-
public readonly networkUsageRedisCacheService: NetworkUsageRedisCacheService;
|
|
24
|
-
|
|
25
|
-
private readonly redisConnection: RedisConnection = getMeshRedisConnection();
|
|
26
|
-
private readonly cache: Map<`${TNetworkId_S}.${TAgentOwnUId}`, TAddress> = new Map(); // ! cleanup
|
|
27
|
-
private readonly timers: Map<TClientId, ReturnType<typeof setInterval>> = new Map();
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
|
|
31
|
-
) {
|
|
32
|
-
this.networkAgentRedisService = this.redisConnection.networkAgentRedisService;
|
|
33
|
-
this.networkUsageRedisCacheService = new NetworkUsageRedisCacheService(this.redisConnection['cacheClient'].getClient());
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Register an agent.
|
|
38
|
-
*
|
|
39
|
-
* @param { TNetworkId_S } networkId
|
|
40
|
-
* @param { TClientId } id
|
|
41
|
-
* @param { Bun.SocketAddress | null } ip
|
|
42
|
-
* @param { TAddress } address
|
|
43
|
-
* @param { TAgentOwnUId } [uid]
|
|
44
|
-
*
|
|
45
|
-
* @returns { void }
|
|
46
|
-
*/
|
|
47
|
-
public registerAgent(
|
|
48
|
-
networkId: TNetworkId_S,
|
|
49
|
-
id: TClientId,
|
|
50
|
-
ip: Bun.SocketAddress | null,
|
|
51
|
-
address: TAddress,
|
|
52
|
-
throughput: {
|
|
53
|
-
bytes: number,
|
|
54
|
-
packets: number,
|
|
55
|
-
},
|
|
56
|
-
uid?: TAgentOwnUId,
|
|
57
|
-
machineUID?: TFluxClientUID,
|
|
58
|
-
): Promise<void> {
|
|
59
|
-
this.timers.set(
|
|
60
|
-
id,
|
|
61
|
-
setInterval(async () => {
|
|
62
|
-
await this.networkAgentRedisService
|
|
63
|
-
.registerAgentThroughput(
|
|
64
|
-
networkId,
|
|
65
|
-
id,
|
|
66
|
-
throughput.bytes,
|
|
67
|
-
throughput.packets,
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if ((throughput.bytes > 0) || (throughput.packets > 0)) {
|
|
71
|
-
await this.networkUsageRedisCacheService
|
|
72
|
-
.increaseNetworkUsage(
|
|
73
|
-
networkId,
|
|
74
|
-
throughput.bytes,
|
|
75
|
-
throughput.packets,
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
throughput.bytes = 0;
|
|
80
|
-
throughput.packets = 0;
|
|
81
|
-
}, 1_000),
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
return this.networkAgentRedisService
|
|
85
|
-
.registerAgent(
|
|
86
|
-
networkId,
|
|
87
|
-
id,
|
|
88
|
-
ip,
|
|
89
|
-
address,
|
|
90
|
-
uid,
|
|
91
|
-
machineUID,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Unregisters a network agent UID and associated data from the Redis hash.
|
|
97
|
-
*
|
|
98
|
-
* @param { TNetworkId_S } networkId
|
|
99
|
-
* @param { TClientId } clientId
|
|
100
|
-
* @param { TAgentOwnUId } clientOwnUId
|
|
101
|
-
*
|
|
102
|
-
* @returns { void }
|
|
103
|
-
*/
|
|
104
|
-
public unregisterNetworkAgent(
|
|
105
|
-
networkId: TNetworkId_S,
|
|
106
|
-
clientId: TClientId,
|
|
107
|
-
clientOwnUId?: TAgentOwnUId,
|
|
108
|
-
): void {
|
|
109
|
-
if (clientOwnUId) {
|
|
110
|
-
// Unregisters a network client UID and address in the Redis hash.
|
|
111
|
-
this.cache.delete(`${networkId}.${clientOwnUId}`);
|
|
112
|
-
|
|
113
|
-
this.networkAgentRedisService.unregisterNetworkAgent(
|
|
114
|
-
networkId,
|
|
115
|
-
clientId,
|
|
116
|
-
clientOwnUId,
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Cancel the timer
|
|
121
|
-
clearInterval(this.timers.get(clientId));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
public async resolveNetworkClientAddressByUid(
|
|
125
|
-
networkId: TNetworkId_S,
|
|
126
|
-
clientOwnUId: TAgentOwnUId,
|
|
127
|
-
// retryWithDelay?: number,
|
|
128
|
-
): Promise<TAddress> {
|
|
129
|
-
const cached: TAddress | undefined = this.cache.get(
|
|
130
|
-
`${networkId}.${clientOwnUId}`
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
if (cached) {
|
|
134
|
-
return cached;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const address: TAddress = await this.redisConnection
|
|
138
|
-
.networkAgentRedisService
|
|
139
|
-
.readNetworkClientAddressByUIDOrThrow(
|
|
140
|
-
networkId,
|
|
141
|
-
clientOwnUId
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
this.cache.set(`${networkId}.${clientOwnUId}`, address);
|
|
145
|
-
|
|
146
|
-
return address;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// public register(
|
|
150
|
-
// networkId: TNetworkId_S,
|
|
151
|
-
// socketId: TClientId,
|
|
152
|
-
// ): void {
|
|
153
|
-
// this.redisConnection
|
|
154
|
-
// .networkAuthoritySet
|
|
155
|
-
// .registerNetworkAuthority(
|
|
156
|
-
// networkId,
|
|
157
|
-
// socketId,
|
|
158
|
-
// );
|
|
159
|
-
// }
|
|
160
|
-
|
|
161
|
-
// public unregister(
|
|
162
|
-
// networkId: TNetworkId_S,
|
|
163
|
-
// socketId: TClientId,
|
|
164
|
-
// ): void {
|
|
165
|
-
// this.cache.delete(networkId);
|
|
166
|
-
|
|
167
|
-
// this.redisConnection
|
|
168
|
-
// .networkAuthoritySet
|
|
169
|
-
// .unregister(
|
|
170
|
-
// networkId,
|
|
171
|
-
// socketId,
|
|
172
|
-
// );
|
|
173
|
-
// }
|
|
174
|
-
|
|
175
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { splitAddressOrThrow, type TAddress, type TClientId, type TNetworkId_S } from '@flux/shared/types';
|
|
2
|
-
import {
|
|
3
|
-
type RedisConnection,
|
|
4
|
-
getMeshRedisConnection,
|
|
5
|
-
} from '../routing/redis/redis-connection.class';
|
|
6
|
-
import type {
|
|
7
|
-
TFluxClientUID,
|
|
8
|
-
} from '@flux/shared/utils';
|
|
9
|
-
|
|
10
|
-
export class NetworkAuthorityManager {
|
|
11
|
-
private readonly redisConnection: RedisConnection = getMeshRedisConnection();
|
|
12
|
-
private readonly cache: Map<TNetworkId_S, Set<TAddress>> = new Map();
|
|
13
|
-
|
|
14
|
-
public async register(
|
|
15
|
-
networkId: TNetworkId_S,
|
|
16
|
-
socketId: TClientId,
|
|
17
|
-
machineUID?: TFluxClientUID,
|
|
18
|
-
): Promise<void> {
|
|
19
|
-
await this.redisConnection.networkAuthoritySet
|
|
20
|
-
.registerNetworkAuthority(
|
|
21
|
-
networkId,
|
|
22
|
-
socketId,
|
|
23
|
-
machineUID,
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public unregister(
|
|
28
|
-
networkId: TNetworkId_S,
|
|
29
|
-
networkAuthorityAddress: TAddress,
|
|
30
|
-
): void {
|
|
31
|
-
const cached: Set<TAddress> | undefined = this.cache.get(networkId);
|
|
32
|
-
if (cached) {
|
|
33
|
-
cached.delete(networkAuthorityAddress);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const [_machineAddress, _processId, clientId] = splitAddressOrThrow(networkAuthorityAddress);
|
|
37
|
-
|
|
38
|
-
this.redisConnection.networkAuthoritySet.unregister(
|
|
39
|
-
networkId,
|
|
40
|
-
clientId,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Used for cleanup, in case of discovering an idle authority.
|
|
46
|
-
*
|
|
47
|
-
* @param { TNetworkId_S } networkId
|
|
48
|
-
* @param { TAddress } networkAuthorityAddress
|
|
49
|
-
*
|
|
50
|
-
* @returns { void }
|
|
51
|
-
*/
|
|
52
|
-
public unregisterGlobal(
|
|
53
|
-
networkId: TNetworkId_S,
|
|
54
|
-
networkAuthorityAddress: TAddress,
|
|
55
|
-
): void {
|
|
56
|
-
const cached: Set<TAddress> | undefined = this.cache.get(networkId);
|
|
57
|
-
if (cached) {
|
|
58
|
-
cached.delete(networkAuthorityAddress);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
this.redisConnection.networkAuthoritySet
|
|
62
|
-
.unregisterGlobal(
|
|
63
|
-
networkId,
|
|
64
|
-
networkAuthorityAddress,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Resolves a random network authority address for a given network ID.
|
|
70
|
-
*
|
|
71
|
-
* @param { TNetworkId_S } networkId
|
|
72
|
-
*
|
|
73
|
-
* @returns { Promise<TAddress> }
|
|
74
|
-
*/
|
|
75
|
-
public async resolveNetworkAuthorityAddressOrThrow(
|
|
76
|
-
networkId: TNetworkId_S
|
|
77
|
-
// retryWithDelay?: number,
|
|
78
|
-
): Promise<TAddress> {
|
|
79
|
-
const cached: Set<TAddress> | undefined = this.cache.get(networkId);
|
|
80
|
-
|
|
81
|
-
if (cached && (cached.size > 0)) {
|
|
82
|
-
const randomItem = [...cached][Math.floor(Math.random() * [...cached].length)];
|
|
83
|
-
|
|
84
|
-
if (randomItem) {
|
|
85
|
-
return randomItem;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const address: TAddress[] = await this.redisConnection
|
|
90
|
-
.networkAuthoritySet
|
|
91
|
-
.resolveNetworkAuthorityAddressesOrThrow(
|
|
92
|
-
networkId,
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
if (cached) {
|
|
96
|
-
for (const a of address) {
|
|
97
|
-
cached.add(a);
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
this.cache.set(networkId, new Set(address));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const cached_: Set<TAddress> = this.cache.get(networkId) as Set<TAddress>;
|
|
104
|
-
const randomItem = [...cached_][Math.floor(Math.random() * [...cached_].length)];
|
|
105
|
-
|
|
106
|
-
return randomItem;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Removes a client.
|
|
111
|
-
*
|
|
112
|
-
* @param { TNetworkId_S } networkId
|
|
113
|
-
* @param { TAddress } networkAuthorityAddress
|
|
114
|
-
*
|
|
115
|
-
* @returns { void }
|
|
116
|
-
*/
|
|
117
|
-
public removeUnresponsiveClient(
|
|
118
|
-
networkId: TNetworkId_S,
|
|
119
|
-
networkAuthorityAddress: TAddress,
|
|
120
|
-
): void {
|
|
121
|
-
this.unregisterGlobal(networkId, networkAuthorityAddress);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import * as os from 'node:os';
|
|
2
|
-
import type {
|
|
3
|
-
TMachineAddress,
|
|
4
|
-
TProcessId,
|
|
5
|
-
TProcessAddress,
|
|
6
|
-
} from '@flux/shared/types';
|
|
7
|
-
|
|
8
|
-
export const readProcessId = (): TProcessId => {
|
|
9
|
-
return process.pid as TProcessId;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
let machineAddress: TMachineAddress | undefined;
|
|
13
|
-
export const readMachineAddress = (): TMachineAddress => {
|
|
14
|
-
if (machineAddress) {
|
|
15
|
-
return machineAddress;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
machineAddress = Object.values(os.networkInterfaces())
|
|
19
|
-
.flat()
|
|
20
|
-
.find((i) => i && !i.internal && i.mac !== '00:00:00:00:00:00')
|
|
21
|
-
?.mac.replaceAll(':', '')
|
|
22
|
-
.replace(/^0+/, '') as TMachineAddress;
|
|
23
|
-
|
|
24
|
-
return machineAddress;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Returns the process address.
|
|
29
|
-
*
|
|
30
|
-
* @returns { TProcessAddress }
|
|
31
|
-
*/
|
|
32
|
-
export const readProcessAddress = (): TProcessAddress => {
|
|
33
|
-
return `${readMachineAddress()}/${readProcessId()}`;
|
|
34
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 1. Detects global events and publishes them to all clients subscribed to the websocket channel system.
|
|
3
|
-
*
|
|
4
|
-
* 2. Sends messages to all nodes in the cluster, and when reached, publishes locally
|
|
5
|
-
* on the server channel to everyone subscribed.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { TProcessAddress } from '@flux/shared/types';
|
|
9
|
-
import type { TConnectedClientSocket } from '../../main';
|
|
10
|
-
import type { RedisConnection } from '../redis/redis-connection.class';
|
|
11
|
-
|
|
12
|
-
export type TGlobalChannel = string & { __brand: 'global-channel'; };
|
|
13
|
-
|
|
14
|
-
export class GlobalChannelPubsub {
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
private readonly redisConnection: RedisConnection,
|
|
18
|
-
private readonly bunServer: Bun.Server,
|
|
19
|
-
private readonly processAddress: TProcessAddress,
|
|
20
|
-
) {
|
|
21
|
-
this.subscribeWebsocketChannelEvent();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Subscribes to the websocket channel event and publishes it on the local process.
|
|
26
|
-
*
|
|
27
|
-
* @returns { void }
|
|
28
|
-
*/
|
|
29
|
-
private subscribeWebsocketChannelEvent(
|
|
30
|
-
): void {
|
|
31
|
-
this.redisConnection
|
|
32
|
-
.subscribeWebsocketChannelEvent((
|
|
33
|
-
channel: TGlobalChannel,
|
|
34
|
-
skipProcessAddress: TProcessAddress,
|
|
35
|
-
message: string,
|
|
36
|
-
): void => {
|
|
37
|
-
if (this.processAddress === skipProcessAddress) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Publish it on the local process
|
|
42
|
-
this.bunServer.publish(
|
|
43
|
-
message,
|
|
44
|
-
channel,
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Publishes a message to the given channel.
|
|
51
|
-
*
|
|
52
|
-
* @param { string } channel
|
|
53
|
-
* @param { string } message
|
|
54
|
-
* @param { TConnectedClientSocket } [ws]
|
|
55
|
-
*
|
|
56
|
-
* @returns { Promise<void> }
|
|
57
|
-
*/
|
|
58
|
-
public async publish(
|
|
59
|
-
channel: string,
|
|
60
|
-
message: string,
|
|
61
|
-
ws?: TConnectedClientSocket,
|
|
62
|
-
): Promise<void> {
|
|
63
|
-
// Publish locally on the process to everyone but the client (if a client is provided)
|
|
64
|
-
(ws ?? this.bunServer).publish(
|
|
65
|
-
channel,
|
|
66
|
-
message,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// Publish globally to clients connected to other processes
|
|
70
|
-
await this.redisConnection.publishWebsocketChannelEvent(
|
|
71
|
-
this.processAddress, // The event is already sent to the local process
|
|
72
|
-
channel as TGlobalChannel,
|
|
73
|
-
message,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route messages to the correct destination.
|
|
3
|
-
*/
|
|
4
|
-
import type { TClientId } from '@flux/shared/types';
|
|
5
|
-
import {
|
|
6
|
-
type RedisConnection,
|
|
7
|
-
getMeshRedisConnection,
|
|
8
|
-
} from './redis/redis-connection.class';
|
|
9
|
-
|
|
10
|
-
export class IncommingMessageRouter {
|
|
11
|
-
private readonly redisConnection: RedisConnection = getMeshRedisConnection();
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
private readonly onLocal: (
|
|
15
|
-
clientId: TClientId,
|
|
16
|
-
onMessage: (message: string) => void
|
|
17
|
-
) => void
|
|
18
|
-
) { }
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
* @param address
|
|
23
|
-
* @param message
|
|
24
|
-
*
|
|
25
|
-
* @returns { void }
|
|
26
|
-
*/
|
|
27
|
-
// public subscribe(
|
|
28
|
-
// clientId: TClientId,
|
|
29
|
-
// onMessage: (
|
|
30
|
-
// message: string,
|
|
31
|
-
// ) => void,
|
|
32
|
-
// ): void {
|
|
33
|
-
// console.log("subscreibing client", clientId);
|
|
34
|
-
// // Listen to local
|
|
35
|
-
// this.onLocal(
|
|
36
|
-
// clientId,
|
|
37
|
-
// onMessage,
|
|
38
|
-
// );
|
|
39
|
-
|
|
40
|
-
// // Listen to remote
|
|
41
|
-
// this.redisConnection
|
|
42
|
-
// .subscribe(
|
|
43
|
-
// clientId,
|
|
44
|
-
// onMessage,
|
|
45
|
-
// );
|
|
46
|
-
// }
|
|
47
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route messages to the correct destination.
|
|
3
|
-
*/
|
|
4
|
-
import {
|
|
5
|
-
type TAddress,
|
|
6
|
-
type TClientId,
|
|
7
|
-
type TMachineAddress,
|
|
8
|
-
type TProcessId,
|
|
9
|
-
splitAddressOrThrow,
|
|
10
|
-
} from '@flux/shared/types';
|
|
11
|
-
import { readMachineAddress, readProcessId } from './addressing.utils';
|
|
12
|
-
import {
|
|
13
|
-
type RedisConnection,
|
|
14
|
-
getMeshRedisConnection,
|
|
15
|
-
} from './redis/redis-connection.class';
|
|
16
|
-
import { PicoLogger } from '@utils/pico-logger';
|
|
17
|
-
|
|
18
|
-
export class OutgoingMessageRouter {
|
|
19
|
-
private readonly processId: TProcessId = readProcessId();
|
|
20
|
-
private readonly machineAddress: TMachineAddress = readMachineAddress();
|
|
21
|
-
|
|
22
|
-
private readonly redisConnection: RedisConnection = getMeshRedisConnection();
|
|
23
|
-
|
|
24
|
-
constructor(
|
|
25
|
-
private readonly passToLocalClientOrThrowUnknownClient: (
|
|
26
|
-
clientId: TClientId,
|
|
27
|
-
message: string,
|
|
28
|
-
) => void,
|
|
29
|
-
) {
|
|
30
|
-
console.log(
|
|
31
|
-
`Created MessageRouter on machine address: ${this.machineAddress}, process id: ${this.processId}`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
* @param address
|
|
38
|
-
* @param message
|
|
39
|
-
*
|
|
40
|
-
* @returns
|
|
41
|
-
*/
|
|
42
|
-
public message(
|
|
43
|
-
address: TAddress,
|
|
44
|
-
message: string,
|
|
45
|
-
): void {
|
|
46
|
-
const [machineAddress, processId, clientId] = splitAddressOrThrow(address);
|
|
47
|
-
|
|
48
|
-
// * Not on the same machine
|
|
49
|
-
if (machineAddress !== this.machineAddress) {
|
|
50
|
-
PicoLogger.log('🛣️ Routing message to machine', 'routing');
|
|
51
|
-
|
|
52
|
-
this.redisConnection.directPublish(address, message);
|
|
53
|
-
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// * On the same machine, but not on the same process
|
|
58
|
-
if (processId !== this.processId) {
|
|
59
|
-
PicoLogger.log(`🛣️ Routing message from process ID '${this.processId}' to process ID: '${processId}'`, 'routing');
|
|
60
|
-
|
|
61
|
-
// ! Route through Redis for now, but change to direct process connection
|
|
62
|
-
this.redisConnection.directPublish(address, message);
|
|
63
|
-
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// * On the same machine and process
|
|
68
|
-
PicoLogger.log('🛣️ Routing message to local client', 'routing');
|
|
69
|
-
|
|
70
|
-
this.passToLocalClientOrThrowUnknownClient(clientId, message);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route messages to the correct process if necessary.
|
|
3
|
-
*/
|
|
4
|
-
import {
|
|
5
|
-
type TCallbackFunction,
|
|
6
|
-
type TMachineAddress,
|
|
7
|
-
type TProcessId,
|
|
8
|
-
type TProcessAddress,
|
|
9
|
-
splitProcessAddress,
|
|
10
|
-
} from '@flux/shared/types';
|
|
11
|
-
import {
|
|
12
|
-
type RedisConnection,
|
|
13
|
-
getMeshRedisConnection,
|
|
14
|
-
} from './redis/redis-connection.class';
|
|
15
|
-
import {
|
|
16
|
-
readMachineAddress,
|
|
17
|
-
readProcessAddress,
|
|
18
|
-
readProcessId,
|
|
19
|
-
} from './addressing.utils';
|
|
20
|
-
import { PicoLogger } from '@utils/pico-logger';
|
|
21
|
-
|
|
22
|
-
export class ProcessMessageRouter {
|
|
23
|
-
private readonly machineAddress: TMachineAddress = readMachineAddress();
|
|
24
|
-
private readonly processAddress: TProcessAddress = readProcessAddress();
|
|
25
|
-
private readonly processId: TProcessId = readProcessId();
|
|
26
|
-
private readonly redisConnection: RedisConnection = getMeshRedisConnection();
|
|
27
|
-
private readonly localCallbacks: Set<TCallbackFunction> = new Set();
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Sends a message to a process.
|
|
31
|
-
*
|
|
32
|
-
* @param { TProcessAddress } address
|
|
33
|
-
* @param { string } message
|
|
34
|
-
*
|
|
35
|
-
* @returns
|
|
36
|
-
*/
|
|
37
|
-
public message(
|
|
38
|
-
address: TProcessAddress,
|
|
39
|
-
message: string,
|
|
40
|
-
): void {
|
|
41
|
-
const [machineAddress, processId] = splitProcessAddress(address);
|
|
42
|
-
|
|
43
|
-
// * Not on the same machine
|
|
44
|
-
if (machineAddress !== this.machineAddress) {
|
|
45
|
-
PicoLogger.log('🛣️ Routing message to machine', 'routing');
|
|
46
|
-
|
|
47
|
-
this.redisConnection.directPublish(address, message);
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// * Not on the same process
|
|
53
|
-
if (processId !== this.processId) {
|
|
54
|
-
PicoLogger.log('🛣️ Routing message to process (todo; direct process)', 'routing');
|
|
55
|
-
// ! Route through Redis for now, but change to direct process connection
|
|
56
|
-
this.redisConnection.directPublish(address, message);
|
|
57
|
-
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// * This must be to local process
|
|
62
|
-
PicoLogger.log('🛣️ Routing message to local', 'routing');
|
|
63
|
-
for (const localCallback of this.localCallbacks) {
|
|
64
|
-
localCallback(message);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Subscribe to mesaages for local process.
|
|
70
|
-
*
|
|
71
|
-
* @param message
|
|
72
|
-
*
|
|
73
|
-
* @returns { void }
|
|
74
|
-
*/
|
|
75
|
-
public subscribe(
|
|
76
|
-
onMessage: TCallbackFunction,
|
|
77
|
-
): void {
|
|
78
|
-
console.log('🗒️ Subscribing process', this.processAddress);
|
|
79
|
-
|
|
80
|
-
this.localCallbacks.add(onMessage);
|
|
81
|
-
|
|
82
|
-
// Listen to remote
|
|
83
|
-
this.redisConnection.subscribe(this.processAddress, onMessage);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { RedisClient } from 'bun';
|
|
2
|
-
import type {
|
|
3
|
-
TAddress,
|
|
4
|
-
TClientId,
|
|
5
|
-
TMachineAddress,
|
|
6
|
-
TNetworkId_S,
|
|
7
|
-
TProcessId,
|
|
8
|
-
} from '@flux/shared/types';
|
|
9
|
-
import { readMachineAddress, readProcessId } from '../../addressing.utils';
|
|
10
|
-
|
|
11
|
-
export class NetworkAgentRedisSortedSet {
|
|
12
|
-
private readonly processId: TProcessId = readProcessId();
|
|
13
|
-
private readonly machineAddress: TMachineAddress = readMachineAddress();
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
private readonly client: RedisClient,
|
|
17
|
-
) { }
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Registers a network agent in the sorted set.
|
|
21
|
-
*
|
|
22
|
-
* @param { TNetworkId_S } networkId
|
|
23
|
-
* @param { TClientId } socketId
|
|
24
|
-
*
|
|
25
|
-
* @returns { Promise<void> }
|
|
26
|
-
*/
|
|
27
|
-
public async registerAgent(
|
|
28
|
-
networkId: TNetworkId_S,
|
|
29
|
-
socketId: TClientId,
|
|
30
|
-
): Promise<void> {
|
|
31
|
-
const address: TAddress = `${this.machineAddress}/${this.processId}/${socketId}`;
|
|
32
|
-
|
|
33
|
-
await this.client.send('ZADD', [
|
|
34
|
-
`networks/${networkId}/agents`, // Key
|
|
35
|
-
`${Date.now()}`, // Score
|
|
36
|
-
address, // Member
|
|
37
|
-
]);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Unregisters a network agent from the sorted set.
|
|
42
|
-
*
|
|
43
|
-
* @param { TNetworkId_S } networkId
|
|
44
|
-
* @param { TClientId } socketId
|
|
45
|
-
*
|
|
46
|
-
* @returns { Promise<number> }
|
|
47
|
-
*/
|
|
48
|
-
public async unregisterAgent(
|
|
49
|
-
networkId: TNetworkId_S,
|
|
50
|
-
socketId: TClientId
|
|
51
|
-
): Promise<number> {
|
|
52
|
-
const address: TAddress = `${this.machineAddress}/${this.processId}/${socketId}`;
|
|
53
|
-
|
|
54
|
-
return await this.client.send('ZREM', [
|
|
55
|
-
`networks/${networkId}/agents`,
|
|
56
|
-
address, // Member
|
|
57
|
-
]);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|