@livestore/webmesh 0.3.0-dev.21 → 0.3.0-dev.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/channel/message-channel-internal.d.ts +3 -3
- package/dist/channel/message-channel-internal.d.ts.map +1 -1
- package/dist/channel/message-channel-internal.js +8 -8
- package/dist/channel/message-channel-internal.js.map +1 -1
- package/dist/channel/message-channel.d.ts +5 -5
- package/dist/channel/message-channel.d.ts.map +1 -1
- package/dist/channel/message-channel.js +22 -22
- package/dist/channel/message-channel.js.map +1 -1
- package/dist/channel/proxy-channel.d.ts +2 -2
- package/dist/channel/proxy-channel.d.ts.map +1 -1
- package/dist/channel/proxy-channel.js +9 -9
- package/dist/channel/proxy-channel.js.map +1 -1
- package/dist/common.d.ts +7 -12
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +5 -3
- package/dist/common.js.map +1 -1
- package/dist/mesh-schema.d.ts +10 -10
- package/dist/mesh-schema.d.ts.map +1 -1
- package/dist/mesh-schema.js +7 -7
- package/dist/mesh-schema.js.map +1 -1
- package/dist/mod.d.ts +2 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +2 -2
- package/dist/mod.js.map +1 -1
- package/dist/node.d.ts +14 -14
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +86 -86
- package/dist/node.js.map +1 -1
- package/dist/node.test.js +25 -25
- package/dist/node.test.js.map +1 -1
- package/dist/websocket-connection.d.ts +1 -1
- package/dist/websocket-connection.d.ts.map +1 -1
- package/dist/websocket-connection.js +5 -5
- package/dist/websocket-connection.js.map +1 -1
- package/dist/websocket-edge.d.ts +51 -0
- package/dist/websocket-edge.d.ts.map +1 -0
- package/dist/websocket-edge.js +69 -0
- package/dist/websocket-edge.js.map +1 -0
- package/dist/websocket-server.d.ts +2 -2
- package/dist/websocket-server.d.ts.map +1 -1
- package/dist/websocket-server.js +6 -6
- package/dist/websocket-server.js.map +1 -1
- package/package.json +3 -3
- package/src/channel/message-channel-internal.ts +10 -10
- package/src/channel/message-channel.ts +25 -25
- package/src/channel/proxy-channel.ts +11 -11
- package/src/common.ts +8 -11
- package/src/mesh-schema.ts +9 -9
- package/src/mod.ts +2 -2
- package/src/node.test.ts +25 -25
- package/src/node.ts +102 -113
- package/src/{websocket-connection.ts → websocket-edge.ts} +15 -14
- package/src/websocket-server.ts +9 -9
package/dist/mesh-schema.js
CHANGED
|
@@ -10,7 +10,7 @@ const defaultPacketFields = {
|
|
|
10
10
|
};
|
|
11
11
|
const remainingHopsUndefined = Schema.Undefined.pipe(Schema.optional);
|
|
12
12
|
/**
|
|
13
|
-
* Needs to go through already existing MessageChannel
|
|
13
|
+
* Needs to go through already existing MessageChannel edges, times out otherwise
|
|
14
14
|
*
|
|
15
15
|
* Can't yet contain the `port` because the request might be duplicated while forwarding to multiple nodes.
|
|
16
16
|
* We need a clear path back to the sender to avoid this, thus we respond with a separate
|
|
@@ -73,16 +73,16 @@ export class ProxyChannelPayloadAck extends Schema.TaggedStruct('ProxyChannelPay
|
|
|
73
73
|
}) {
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* Broadcast to all nodes when a new
|
|
76
|
+
* Broadcast to all nodes when a new edge is added.
|
|
77
77
|
* Mostly used for auto-reconnect purposes.
|
|
78
78
|
*/
|
|
79
|
-
export class
|
|
79
|
+
export class NetworkEdgeAdded extends Schema.TaggedStruct('NetworkEdgeAdded', {
|
|
80
80
|
id,
|
|
81
81
|
source: Schema.String,
|
|
82
82
|
target: Schema.String,
|
|
83
83
|
}) {
|
|
84
84
|
}
|
|
85
|
-
export class
|
|
85
|
+
export class NetworkTopologyRequest extends Schema.TaggedStruct('NetworkTopologyRequest', {
|
|
86
86
|
id,
|
|
87
87
|
hops: Schema.Array(Schema.String),
|
|
88
88
|
/** Always fixed to who requested the topology */
|
|
@@ -90,12 +90,12 @@ export class NetworkConnectionTopologyRequest extends Schema.TaggedStruct('Netwo
|
|
|
90
90
|
target: Schema.Literal('-'),
|
|
91
91
|
}) {
|
|
92
92
|
}
|
|
93
|
-
export class
|
|
93
|
+
export class NetworkTopologyResponse extends Schema.TaggedStruct('NetworkTopologyResponse', {
|
|
94
94
|
id,
|
|
95
95
|
reqId: Schema.String,
|
|
96
96
|
remainingHops: Schema.Array(Schema.String),
|
|
97
97
|
nodeName: Schema.String,
|
|
98
|
-
|
|
98
|
+
edges: Schema.Array(Schema.String),
|
|
99
99
|
/** Always fixed to who requested the topology */
|
|
100
100
|
source: Schema.String,
|
|
101
101
|
target: Schema.Literal('-'),
|
|
@@ -117,7 +117,7 @@ export class MessageChannelPacket extends Schema.Union(MessageChannelRequest, Me
|
|
|
117
117
|
}
|
|
118
118
|
export class ProxyChannelPacket extends Schema.Union(ProxyChannelRequest, ProxyChannelResponseSuccess, ProxyChannelPayload, ProxyChannelPayloadAck) {
|
|
119
119
|
}
|
|
120
|
-
export class Packet extends Schema.Union(MessageChannelPacket, ProxyChannelPacket,
|
|
120
|
+
export class Packet extends Schema.Union(MessageChannelPacket, ProxyChannelPacket, NetworkEdgeAdded, NetworkTopologyRequest, NetworkTopologyResponse, BroadcastChannelPacket) {
|
|
121
121
|
}
|
|
122
122
|
export class MessageChannelPing extends Schema.TaggedStruct('MessageChannelPing', {}) {
|
|
123
123
|
}
|
package/dist/mesh-schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-schema.js","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mesh-schema.js","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"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"}
|
package/dist/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './websocket-
|
|
1
|
+
export * from './websocket-edge.js';
|
|
2
2
|
export * from './node.js';
|
|
3
3
|
export * as WebmeshSchema from './mesh-schema.js';
|
|
4
|
-
export {
|
|
4
|
+
export { EdgeAlreadyExistsError } from './common.js';
|
|
5
5
|
//# sourceMappingURL=mod.d.ts.map
|
package/dist/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/mod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './websocket-
|
|
1
|
+
export * from './websocket-edge.js';
|
|
2
2
|
export * from './node.js';
|
|
3
3
|
export * as WebmeshSchema from './mesh-schema.js';
|
|
4
|
-
export {
|
|
4
|
+
export { EdgeAlreadyExistsError } from './common.js';
|
|
5
5
|
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/node.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Cause, Duration, Effect, Schema, Scope, WebChannel } from '@livestore/utils/effect';
|
|
2
2
|
import type { MeshNodeName } from './common.js';
|
|
3
|
-
import {
|
|
3
|
+
import { EdgeAlreadyExistsError } from './common.js';
|
|
4
4
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
5
|
-
type
|
|
5
|
+
type EdgeChannel = WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>;
|
|
6
6
|
export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
7
7
|
nodeName: TName;
|
|
8
|
-
|
|
8
|
+
edgeKeys: Effect.Effect<Set<MeshNodeName>>;
|
|
9
9
|
debug: {
|
|
10
10
|
print: () => void;
|
|
11
11
|
/** Sends a ping message to all connected nodes and channels */
|
|
@@ -16,31 +16,31 @@ export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
|
16
16
|
requestTopology: (timeoutMs?: number) => Promise<void>;
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
|
-
* Manually adds a
|
|
19
|
+
* Manually adds a edge to get connected to the network of nodes with an existing WebChannel.
|
|
20
20
|
*
|
|
21
|
-
* Assumptions about the WebChannel
|
|
22
|
-
* - 1:1
|
|
21
|
+
* Assumptions about the WebChannel edge:
|
|
22
|
+
* - 1:1 edge
|
|
23
23
|
* - Queues messages internally to never drop messages
|
|
24
24
|
* - Automatically reconnects
|
|
25
25
|
* - Ideally supports transferables
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
addEdge: {
|
|
28
28
|
(options: {
|
|
29
29
|
target: MeshNodeName;
|
|
30
|
-
|
|
30
|
+
edgeChannel: EdgeChannel;
|
|
31
31
|
replaceIfExists: true;
|
|
32
32
|
}): Effect.Effect<void, never, Scope.Scope>;
|
|
33
33
|
(options: {
|
|
34
34
|
target: MeshNodeName;
|
|
35
|
-
|
|
35
|
+
edgeChannel: EdgeChannel;
|
|
36
36
|
replaceIfExists?: boolean;
|
|
37
|
-
}): Effect.Effect<void,
|
|
37
|
+
}): Effect.Effect<void, EdgeAlreadyExistsError, Scope.Scope>;
|
|
38
38
|
};
|
|
39
|
-
|
|
39
|
+
removeEdge: (targetNodeName: MeshNodeName) => Effect.Effect<void, Cause.NoSuchElementException>;
|
|
40
40
|
/**
|
|
41
|
-
* Tries to broker a MessageChannel
|
|
41
|
+
* Tries to broker a MessageChannel edge between the nodes, otherwise will proxy messages via hop-nodes
|
|
42
42
|
*
|
|
43
|
-
* For a channel to successfully open, both sides need to have a
|
|
43
|
+
* For a channel to successfully open, both sides need to have a edge and call `makeChannel`.
|
|
44
44
|
*
|
|
45
45
|
* Example:
|
|
46
46
|
* ```ts
|
|
@@ -67,7 +67,7 @@ export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
|
67
67
|
*/
|
|
68
68
|
mode: 'messagechannel' | 'proxy';
|
|
69
69
|
/**
|
|
70
|
-
* Amount of time before we consider a channel creation failed and retry when a new
|
|
70
|
+
* Amount of time before we consider a channel creation failed and retry when a new edge is available
|
|
71
71
|
*
|
|
72
72
|
* @default 1 second
|
|
73
73
|
*/
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAEL,QAAQ,EACR,MAAM,EAMN,MAAM,EACN,KAAK,EAEL,UAAU,EACX,MAAM,yBAAyB,CAAA;AAIhC,OAAO,KAAK,EAAc,YAAY,EAAoC,MAAM,aAAa,CAAA;AAC7F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|
package/dist/node.js
CHANGED
|
@@ -2,14 +2,14 @@ import { indent, LS_DEV, shouldNeverHappen } from '@livestore/utils';
|
|
|
2
2
|
import { Cause, Deferred, Duration, Effect, Exit, Fiber, Option, PubSub, Queue, Schema, Scope, Stream, WebChannel, } from '@livestore/utils/effect';
|
|
3
3
|
import { makeMessageChannel } from './channel/message-channel.js';
|
|
4
4
|
import { makeProxyChannel } from './channel/proxy-channel.js';
|
|
5
|
-
import {
|
|
5
|
+
import { EdgeAlreadyExistsError, packetAsOtelAttributes } from './common.js';
|
|
6
6
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
7
7
|
import { TimeoutSet } from './utils.js';
|
|
8
8
|
export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
9
|
-
const
|
|
9
|
+
const edgeChannels = new Map();
|
|
10
10
|
// To avoid unbounded memory growth, we automatically forget about packet ids after a while
|
|
11
11
|
const handledPacketIds = new TimeoutSet({ timeout: Duration.minutes(1) });
|
|
12
|
-
const
|
|
12
|
+
const newEdgeAvailablePubSub = yield* PubSub.unbounded().pipe(Effect.acquireRelease(PubSub.shutdown));
|
|
13
13
|
// const proxyPacketsToProcess = yield* Queue.unbounded<ProxyQueueItem>().pipe(Effect.acquireRelease(Queue.shutdown))
|
|
14
14
|
// const messagePacketsToProcess = yield* Queue.unbounded<MessageQueueItem>().pipe(
|
|
15
15
|
// Effect.acquireRelease(Queue.shutdown),
|
|
@@ -17,13 +17,13 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
17
17
|
const channelMap = new Map();
|
|
18
18
|
const topologyRequestsMap = new Map();
|
|
19
19
|
const broadcastChannelListenQueueMap = new Map();
|
|
20
|
-
const
|
|
20
|
+
const checkTransferableEdges = (packet) => {
|
|
21
21
|
if ((packet._tag === 'MessageChannelRequest' &&
|
|
22
|
-
(
|
|
23
|
-
// Either if direct
|
|
24
|
-
|
|
25
|
-
// ... or if no forward-
|
|
26
|
-
![...
|
|
22
|
+
(edgeChannels.size === 0 ||
|
|
23
|
+
// Either if direct edge does not support transferables ...
|
|
24
|
+
edgeChannels.get(packet.target)?.channel.supportsTransferables === false)) ||
|
|
25
|
+
// ... or if no forward-edges support transferables
|
|
26
|
+
![...edgeChannels.values()].some((c) => c.channel.supportsTransferables === true)) {
|
|
27
27
|
return WebmeshSchema.MessageChannelResponseNoTransferables.make({
|
|
28
28
|
reqId: packet.id,
|
|
29
29
|
channelName: packet.channelName,
|
|
@@ -40,24 +40,24 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
40
40
|
};
|
|
41
41
|
const sendPacket = (packet) => Effect.gen(function* () {
|
|
42
42
|
// yield* Effect.log(`${nodeName}: sendPacket:${packet._tag} [${packet.id}]`)
|
|
43
|
-
if (Schema.is(WebmeshSchema.
|
|
44
|
-
yield* Effect.spanEvent('
|
|
45
|
-
yield* PubSub.publish(
|
|
46
|
-
const
|
|
43
|
+
if (Schema.is(WebmeshSchema.NetworkEdgeAdded)(packet)) {
|
|
44
|
+
yield* Effect.spanEvent('NetworkEdgeAdded', { packet, nodeName });
|
|
45
|
+
yield* PubSub.publish(newEdgeAvailablePubSub, packet.target);
|
|
46
|
+
const edgesToForwardTo = Array.from(edgeChannels)
|
|
47
47
|
.filter(([name]) => name !== packet.source)
|
|
48
48
|
.map(([_, con]) => con.channel);
|
|
49
|
-
yield* Effect.forEach(
|
|
49
|
+
yield* Effect.forEach(edgesToForwardTo, (con) => con.send(packet), { concurrency: 'unbounded' });
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
if (Schema.is(WebmeshSchema.BroadcastChannelPacket)(packet)) {
|
|
53
|
-
const
|
|
53
|
+
const edgesToForwardTo = Array.from(edgeChannels)
|
|
54
54
|
.filter(([name]) => !packet.hops.includes(name))
|
|
55
55
|
.map(([_, con]) => con.channel);
|
|
56
56
|
const adjustedPacket = {
|
|
57
57
|
...packet,
|
|
58
58
|
hops: [...packet.hops, nodeName],
|
|
59
59
|
};
|
|
60
|
-
yield* Effect.forEach(
|
|
60
|
+
yield* Effect.forEach(edgesToForwardTo, (con) => con.send(adjustedPacket), { concurrency: 'unbounded' });
|
|
61
61
|
// Don't emit the packet to the own node listen queue
|
|
62
62
|
if (packet.source === nodeName) {
|
|
63
63
|
return;
|
|
@@ -69,109 +69,109 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
69
69
|
}
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
if (Schema.is(WebmeshSchema.
|
|
72
|
+
if (Schema.is(WebmeshSchema.NetworkTopologyRequest)(packet)) {
|
|
73
73
|
if (packet.source !== nodeName) {
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
// Respond with own
|
|
77
|
-
const response = WebmeshSchema.
|
|
74
|
+
const backEdgeName = packet.hops.at(-1) ?? shouldNeverHappen(`${nodeName}: Expected hops for packet`, packet);
|
|
75
|
+
const backEdgeChannel = edgeChannels.get(backEdgeName).channel;
|
|
76
|
+
// Respond with own edge info
|
|
77
|
+
const response = WebmeshSchema.NetworkTopologyResponse.make({
|
|
78
78
|
reqId: packet.id,
|
|
79
79
|
source: packet.source,
|
|
80
80
|
target: packet.target,
|
|
81
81
|
remainingHops: packet.hops.slice(0, -1),
|
|
82
82
|
nodeName,
|
|
83
|
-
|
|
83
|
+
edges: Array.from(edgeChannels.keys()),
|
|
84
84
|
});
|
|
85
|
-
yield*
|
|
85
|
+
yield* backEdgeChannel.send(response);
|
|
86
86
|
}
|
|
87
|
-
// Forward the packet to all
|
|
88
|
-
const
|
|
87
|
+
// Forward the packet to all edges except the already visited ones
|
|
88
|
+
const edgesToForwardTo = Array.from(edgeChannels)
|
|
89
89
|
.filter(([name]) => !packet.hops.includes(name))
|
|
90
90
|
.map(([_, con]) => con.channel);
|
|
91
91
|
const adjustedPacket = {
|
|
92
92
|
...packet,
|
|
93
93
|
hops: [...packet.hops, nodeName],
|
|
94
94
|
};
|
|
95
|
-
yield* Effect.forEach(
|
|
95
|
+
yield* Effect.forEach(edgesToForwardTo, (con) => con.send(adjustedPacket), { concurrency: 'unbounded' });
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
|
-
if (Schema.is(WebmeshSchema.
|
|
98
|
+
if (Schema.is(WebmeshSchema.NetworkTopologyResponse)(packet)) {
|
|
99
99
|
if (packet.source === nodeName) {
|
|
100
100
|
const topologyRequestItem = topologyRequestsMap.get(packet.reqId);
|
|
101
|
-
topologyRequestItem.set(packet.nodeName, new Set(packet.
|
|
101
|
+
topologyRequestItem.set(packet.nodeName, new Set(packet.edges));
|
|
102
102
|
}
|
|
103
103
|
else {
|
|
104
104
|
const remainingHops = packet.remainingHops;
|
|
105
105
|
// Forwarding the response to the original sender via the route back
|
|
106
106
|
const routeBack = remainingHops.at(-1) ?? shouldNeverHappen(`${nodeName}: Expected remaining hops for packet`, packet);
|
|
107
|
-
const
|
|
108
|
-
shouldNeverHappen(`${nodeName}: Expected
|
|
109
|
-
yield*
|
|
107
|
+
const edgeChannel = edgeChannels.get(routeBack)?.channel ??
|
|
108
|
+
shouldNeverHappen(`${nodeName}: Expected edge channel (${routeBack}) for packet`, packet, 'Available edges:', Array.from(edgeChannels.keys()));
|
|
109
|
+
yield* edgeChannel.send({ ...packet, remainingHops: packet.remainingHops.slice(0, -1) });
|
|
110
110
|
}
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
|
-
// We have a direct
|
|
114
|
-
if (
|
|
115
|
-
const
|
|
113
|
+
// We have a direct edge to the target node
|
|
114
|
+
if (edgeChannels.has(packet.target)) {
|
|
115
|
+
const edgeChannel = edgeChannels.get(packet.target).channel;
|
|
116
116
|
const hops = packet.source === nodeName ? [] : [...packet.hops, nodeName];
|
|
117
|
-
yield*
|
|
117
|
+
yield* edgeChannel.send({ ...packet, hops });
|
|
118
118
|
}
|
|
119
119
|
// In this case we have an expected route back we should follow
|
|
120
120
|
// eslint-disable-next-line unicorn/no-negated-condition
|
|
121
121
|
else if (packet.remainingHops !== undefined) {
|
|
122
122
|
const hopTarget = packet.remainingHops.at(-1) ?? shouldNeverHappen(`${nodeName}: Expected remaining hops for packet`, packet);
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
yield* Effect.logWarning(`${nodeName}: Expected to find hop target ${hopTarget} in
|
|
123
|
+
const edgeChannel = edgeChannels.get(hopTarget)?.channel;
|
|
124
|
+
if (edgeChannel === undefined) {
|
|
125
|
+
yield* Effect.logWarning(`${nodeName}: Expected to find hop target ${hopTarget} in edges. Dropping packet.`, packet);
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
|
-
yield*
|
|
128
|
+
yield* edgeChannel.send({
|
|
129
129
|
...packet,
|
|
130
130
|
remainingHops: packet.remainingHops.slice(0, -1),
|
|
131
131
|
hops: [...packet.hops, nodeName],
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
|
-
// No route found, forward to all
|
|
134
|
+
// No route found, forward to all edges
|
|
135
135
|
else {
|
|
136
136
|
const hops = packet.source === nodeName ? [] : [...packet.hops, nodeName];
|
|
137
|
-
// Optimization: filter out
|
|
138
|
-
const
|
|
137
|
+
// Optimization: filter out edge where packet just came from
|
|
138
|
+
const edgesToForwardTo = Array.from(edgeChannels)
|
|
139
139
|
.filter(([name]) => name !== packet.source)
|
|
140
140
|
.map(([_, con]) => con.channel);
|
|
141
141
|
// TODO if hops-depth=0, we should fail right away with no route found
|
|
142
|
-
if (hops.length === 0 &&
|
|
142
|
+
if (hops.length === 0 && edgesToForwardTo.length === 0 && LS_DEV) {
|
|
143
143
|
console.log(nodeName, 'no route found', packet._tag, 'TODO handle better');
|
|
144
144
|
// TODO return a expected failure
|
|
145
145
|
}
|
|
146
146
|
const packetToSend = { ...packet, hops };
|
|
147
147
|
// console.debug(nodeName, 'sendPacket:forwarding', packetToSend)
|
|
148
|
-
yield* Effect.forEach(
|
|
148
|
+
yield* Effect.forEach(edgesToForwardTo, (con) => con.send(packetToSend), { concurrency: 'unbounded' });
|
|
149
149
|
}
|
|
150
150
|
}).pipe(Effect.withSpan(`sendPacket:${packet._tag}:${packet.source}→${packet.target}`, {
|
|
151
151
|
attributes: packetAsOtelAttributes(packet),
|
|
152
152
|
}), Effect.orDie);
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
153
|
+
const addEdge = ({ target: targetNodeName, edgeChannel, replaceIfExists = false }) => Effect.gen(function* () {
|
|
154
|
+
if (edgeChannels.has(targetNodeName)) {
|
|
155
155
|
if (replaceIfExists) {
|
|
156
|
-
yield*
|
|
156
|
+
yield* removeEdge(targetNodeName).pipe(Effect.orDie);
|
|
157
157
|
// console.log('interrupting', targetNodeName)
|
|
158
|
-
// yield* Fiber.interrupt(
|
|
158
|
+
// yield* Fiber.interrupt(edgeChannels.get(targetNodeName)!.listenFiber)
|
|
159
159
|
}
|
|
160
160
|
else {
|
|
161
|
-
return yield* new
|
|
161
|
+
return yield* new EdgeAlreadyExistsError({ target: targetNodeName });
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
// TODO use a priority queue instead to prioritize network-changes/
|
|
165
|
-
const listenFiber = yield*
|
|
164
|
+
// TODO use a priority queue instead to prioritize network-changes/edge-requests over payloads
|
|
165
|
+
const listenFiber = yield* edgeChannel.listen.pipe(Stream.flatten(), Stream.tap((message) => Effect.gen(function* () {
|
|
166
166
|
const packet = yield* Schema.decodeUnknown(WebmeshSchema.Packet)(message);
|
|
167
167
|
// console.debug(nodeName, 'received', packet._tag, packet.source, packet.target)
|
|
168
168
|
if (handledPacketIds.has(packet.id))
|
|
169
169
|
return;
|
|
170
170
|
handledPacketIds.add(packet.id);
|
|
171
171
|
switch (packet._tag) {
|
|
172
|
-
case '
|
|
173
|
-
case '
|
|
174
|
-
case '
|
|
172
|
+
case 'NetworkEdgeAdded':
|
|
173
|
+
case 'NetworkTopologyRequest':
|
|
174
|
+
case 'NetworkTopologyResponse': {
|
|
175
175
|
yield* sendPacket(packet);
|
|
176
176
|
break;
|
|
177
177
|
}
|
|
@@ -183,7 +183,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
183
183
|
channelMap.set(channelKey, { queue, debugInfo: undefined });
|
|
184
184
|
}
|
|
185
185
|
const queue = channelMap.get(channelKey).queue;
|
|
186
|
-
const respondToSender = (outgoingPacket) =>
|
|
186
|
+
const respondToSender = (outgoingPacket) => edgeChannel
|
|
187
187
|
.send(outgoingPacket)
|
|
188
188
|
.pipe(Effect.withSpan(`respondToSender:${outgoingPacket._tag}:${outgoingPacket.source}→${outgoingPacket.target}`, { attributes: packetAsOtelAttributes(outgoingPacket) }), Effect.orDie);
|
|
189
189
|
if (Schema.is(WebmeshSchema.ProxyChannelPacket)(packet)) {
|
|
@@ -195,10 +195,10 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
195
195
|
}
|
|
196
196
|
else {
|
|
197
197
|
if (Schema.is(WebmeshSchema.MessageChannelPacket)(packet)) {
|
|
198
|
-
const noTransferableResponse =
|
|
198
|
+
const noTransferableResponse = checkTransferableEdges(packet);
|
|
199
199
|
if (noTransferableResponse !== undefined) {
|
|
200
|
-
yield* Effect.spanEvent(`No transferable
|
|
201
|
-
return yield*
|
|
200
|
+
yield* Effect.spanEvent(`No transferable edges found for ${packet.source}→${packet.target}`);
|
|
201
|
+
return yield* edgeChannel.send(noTransferableResponse).pipe(Effect.withSpan(`sendNoTransferableResponse:${packet.source}→${packet.target}`, {
|
|
202
202
|
attributes: packetAsOtelAttributes(noTransferableResponse),
|
|
203
203
|
}));
|
|
204
204
|
}
|
|
@@ -208,23 +208,23 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
})), Stream.runDrain, Effect.orDie, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
211
|
-
|
|
212
|
-
const
|
|
211
|
+
edgeChannels.set(targetNodeName, { channel: edgeChannel, listenFiber });
|
|
212
|
+
const edgeAddedPacket = WebmeshSchema.NetworkEdgeAdded.make({
|
|
213
213
|
source: nodeName,
|
|
214
214
|
target: targetNodeName,
|
|
215
215
|
});
|
|
216
|
-
yield* sendPacket(
|
|
217
|
-
}).pipe(Effect.withSpan(`
|
|
218
|
-
attributes: { supportsTransferables:
|
|
216
|
+
yield* sendPacket(edgeAddedPacket).pipe(Effect.orDie);
|
|
217
|
+
}).pipe(Effect.withSpan(`addEdge:${nodeName}→${targetNodeName}`, {
|
|
218
|
+
attributes: { supportsTransferables: edgeChannel.supportsTransferables },
|
|
219
219
|
})); // any-cast needed for error/never overload
|
|
220
|
-
const
|
|
221
|
-
if (!
|
|
222
|
-
yield* new Cause.NoSuchElementException(`No
|
|
220
|
+
const removeEdge = (targetNodeName) => Effect.gen(function* () {
|
|
221
|
+
if (!edgeChannels.has(targetNodeName)) {
|
|
222
|
+
yield* new Cause.NoSuchElementException(`No edge found for ${targetNodeName}`);
|
|
223
223
|
}
|
|
224
|
-
yield* Fiber.interrupt(
|
|
225
|
-
|
|
224
|
+
yield* Fiber.interrupt(edgeChannels.get(targetNodeName).listenFiber);
|
|
225
|
+
edgeChannels.delete(targetNodeName);
|
|
226
226
|
});
|
|
227
|
-
// TODO add heartbeat to detect dead
|
|
227
|
+
// TODO add heartbeat to detect dead edges (for both e2e and proxying)
|
|
228
228
|
// TODO when a channel is established in the same origin, we can use a weblock to detect disconnects
|
|
229
229
|
const makeChannel = ({ target, channelName, schema: inputSchema,
|
|
230
230
|
// TODO in the future we could have a mode that prefers messagechannels and then falls back to proxies if needed
|
|
@@ -251,24 +251,24 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
251
251
|
// We should figure out some day why this is needed and further simplify if possible.
|
|
252
252
|
yield* Queue.takeBetween(queue, 1, 10).pipe(Effect.tap((_) => Queue.offerAll(incomingPacketsQueue, _)), Effect.forever, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
253
253
|
// NOTE already retries internally when transferables are required
|
|
254
|
-
const { webChannel,
|
|
254
|
+
const { webChannel, initialEdgeDeferred } = yield* makeMessageChannel({
|
|
255
255
|
nodeName,
|
|
256
256
|
incomingPacketsQueue,
|
|
257
|
-
|
|
257
|
+
newEdgeAvailablePubSub,
|
|
258
258
|
target,
|
|
259
259
|
channelName,
|
|
260
260
|
schema,
|
|
261
261
|
sendPacket,
|
|
262
|
-
|
|
262
|
+
checkTransferableEdges,
|
|
263
263
|
});
|
|
264
264
|
channelMap.set(channelKey, { queue, debugInfo: { channel: webChannel, target } });
|
|
265
|
-
yield*
|
|
265
|
+
yield* initialEdgeDeferred;
|
|
266
266
|
return webChannel;
|
|
267
267
|
}
|
|
268
268
|
else {
|
|
269
269
|
const channel = yield* makeProxyChannel({
|
|
270
270
|
nodeName,
|
|
271
|
-
|
|
271
|
+
newEdgeAvailablePubSub,
|
|
272
272
|
target,
|
|
273
273
|
channelName,
|
|
274
274
|
schema,
|
|
@@ -314,13 +314,13 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
314
314
|
debugInfo,
|
|
315
315
|
};
|
|
316
316
|
}));
|
|
317
|
-
const
|
|
317
|
+
const edgeKeys = Effect.sync(() => new Set(edgeChannels.keys()));
|
|
318
318
|
const runtime = yield* Effect.runtime();
|
|
319
319
|
const debug = {
|
|
320
320
|
print: () => {
|
|
321
321
|
console.log('Webmesh debug info for node:', nodeName);
|
|
322
|
-
console.log('
|
|
323
|
-
for (const [key, value] of
|
|
322
|
+
console.log('Edges:', edgeChannels.size);
|
|
323
|
+
for (const [key, value] of edgeChannels) {
|
|
324
324
|
console.log(` ${key}: supportsTransferables=${value.channel.supportsTransferables}`);
|
|
325
325
|
}
|
|
326
326
|
console.log('Channels:', channelMap.size);
|
|
@@ -340,10 +340,10 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
340
340
|
},
|
|
341
341
|
ping: (payload) => {
|
|
342
342
|
Effect.gen(function* () {
|
|
343
|
-
const msg = (via) => WebChannel.DebugPingMessage.make({ message: `ping from ${nodeName} via
|
|
344
|
-
for (const [channelName, con] of
|
|
345
|
-
yield* Effect.logDebug(`sending ping via
|
|
346
|
-
yield* con.channel.send(msg(`
|
|
343
|
+
const msg = (via) => WebChannel.DebugPingMessage.make({ message: `ping from ${nodeName} via edge ${via}`, payload });
|
|
344
|
+
for (const [channelName, con] of edgeChannels) {
|
|
345
|
+
yield* Effect.logDebug(`sending ping via edge ${channelName}`);
|
|
346
|
+
yield* con.channel.send(msg(`edge ${channelName}`));
|
|
347
347
|
}
|
|
348
348
|
for (const [channelKey, channel] of channelMap) {
|
|
349
349
|
if (channel.debugInfo === undefined)
|
|
@@ -354,13 +354,13 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
354
354
|
}).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runFork);
|
|
355
355
|
},
|
|
356
356
|
requestTopology: (timeoutMs = 1000) => Effect.gen(function* () {
|
|
357
|
-
const packet = WebmeshSchema.
|
|
357
|
+
const packet = WebmeshSchema.NetworkTopologyRequest.make({
|
|
358
358
|
source: nodeName,
|
|
359
359
|
target: '-',
|
|
360
360
|
hops: [],
|
|
361
361
|
});
|
|
362
362
|
const item = new Map();
|
|
363
|
-
item.set(nodeName, new Set(
|
|
363
|
+
item.set(nodeName, new Set(edgeChannels.keys()));
|
|
364
364
|
topologyRequestsMap.set(packet.id, item);
|
|
365
365
|
yield* sendPacket(packet);
|
|
366
366
|
yield* Effect.logDebug(`Waiting ${timeoutMs}ms for topology response`);
|
|
@@ -372,11 +372,11 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
372
372
|
};
|
|
373
373
|
return {
|
|
374
374
|
nodeName,
|
|
375
|
-
|
|
376
|
-
|
|
375
|
+
addEdge,
|
|
376
|
+
removeEdge,
|
|
377
377
|
makeChannel,
|
|
378
378
|
makeBroadcastChannel,
|
|
379
|
-
|
|
379
|
+
edgeKeys,
|
|
380
380
|
debug,
|
|
381
381
|
};
|
|
382
382
|
}).pipe(Effect.withSpan(`makeMeshNode:${nodeName}`));
|