@livestore/webmesh 0.0.0-snapshot-12c4570d047bcfaefc85bc6243c1b61f57580913 → 0.0.0-snapshot-b12fe44662a4a2f917d402ea2562edb3c404f26a
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 +3 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/channel/message-channel-internal.js +1 -1
- package/dist/channel/message-channel-internal.js.map +1 -1
- package/dist/channel/proxy-channel.d.ts.map +1 -1
- package/dist/channel/proxy-channel.js +10 -6
- package/dist/channel/proxy-channel.js.map +1 -1
- package/dist/common.d.ts +24 -1
- package/dist/common.d.ts.map +1 -1
- package/dist/mesh-schema.d.ts +45 -1
- package/dist/mesh-schema.d.ts.map +1 -1
- package/dist/mesh-schema.js +32 -2
- package/dist/mesh-schema.js.map +1 -1
- package/dist/node.d.ts +16 -5
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +177 -41
- package/dist/node.js.map +1 -1
- package/dist/node.test.js +54 -0
- package/dist/node.test.js.map +1 -1
- package/dist/websocket-connection.d.ts.map +1 -1
- package/dist/websocket-connection.js +5 -4
- package/dist/websocket-connection.js.map +1 -1
- package/package.json +3 -3
- package/src/channel/message-channel-internal.ts +1 -1
- package/src/channel/proxy-channel.ts +10 -6
- package/src/common.ts +1 -1
- package/src/mesh-schema.ts +40 -2
- package/src/node.test.ts +81 -0
- package/src/node.ts +265 -62
- package/src/websocket-connection.ts +9 -4
|
@@ -24,12 +24,13 @@ export const makeWebSocketConnection = (socket, socketType) => Effect.scopeWithC
|
|
|
24
24
|
socket.binaryType = 'arraybuffer';
|
|
25
25
|
const fromDeferred = yield* Deferred.make();
|
|
26
26
|
const listenQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
27
|
+
const schema = WebChannel.mapSchema(WebmeshSchema.Packet);
|
|
27
28
|
yield* Stream.fromEventListener(socket, 'message').pipe(Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg.data))), Stream.flatten(), Stream.tap((msg) => Effect.gen(function* () {
|
|
28
29
|
if (msg._tag === 'WSConnectionInit') {
|
|
29
30
|
yield* Deferred.succeed(fromDeferred, msg.from);
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
|
-
const decodedPayload = yield* Schema.decode(
|
|
33
|
+
const decodedPayload = yield* Schema.decode(schema.listen)(msg.payload);
|
|
33
34
|
yield* Queue.offer(listenQueue, decodedPayload);
|
|
34
35
|
}
|
|
35
36
|
})), Stream.runDrain, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
@@ -50,16 +51,16 @@ export const makeWebSocketConnection = (socket, socketType) => Effect.scopeWithC
|
|
|
50
51
|
}), { once: true });
|
|
51
52
|
const send = (message) => Effect.gen(function* () {
|
|
52
53
|
yield* isConnectedLatch.await;
|
|
53
|
-
const payload = yield* Schema.encode(
|
|
54
|
+
const payload = yield* Schema.encode(schema.send)(message);
|
|
54
55
|
socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSConnectionPayload', payload, from }));
|
|
55
56
|
});
|
|
56
|
-
const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right));
|
|
57
|
+
const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right), WebChannel.listenToDebugPing('websocket-connection'));
|
|
57
58
|
const webChannel = {
|
|
58
59
|
[WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
|
|
59
60
|
send,
|
|
60
61
|
listen,
|
|
61
62
|
closedDeferred,
|
|
62
|
-
schema
|
|
63
|
+
schema,
|
|
63
64
|
supportsTransferables: false,
|
|
64
65
|
shutdown: Scope.close(scope, Exit.void),
|
|
65
66
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-connection.js","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"websocket-connection.js","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/webmesh",
|
|
3
|
-
"version": "0.0.0-snapshot-
|
|
3
|
+
"version": "0.0.0-snapshot-b12fe44662a4a2f917d402ea2562edb3c404f26a",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"types": "./dist/mod.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"ws": "8.18.0",
|
|
19
|
-
"@livestore/common": "0.0.0-snapshot-
|
|
20
|
-
"@livestore/utils": "0.0.0-snapshot-
|
|
19
|
+
"@livestore/common": "0.0.0-snapshot-b12fe44662a4a2f917d402ea2562edb3c404f26a",
|
|
20
|
+
"@livestore/utils": "0.0.0-snapshot-b12fe44662a4a2f917d402ea2562edb3c404f26a"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/ws": "^8.18.0",
|
|
@@ -123,7 +123,7 @@ export const makeProxyChannel = ({
|
|
|
123
123
|
// yield* Effect.log(`${nodeName}:processing packet ${packet._tag} from ${packet.source}`)
|
|
124
124
|
|
|
125
125
|
const otherSideName = packet.source
|
|
126
|
-
const channelKey =
|
|
126
|
+
const channelKey = `target:${otherSideName}, channelName:${packet.channelName}` satisfies ChannelKey
|
|
127
127
|
const channelState = channelStateRef.current
|
|
128
128
|
|
|
129
129
|
switch (packet._tag) {
|
|
@@ -166,7 +166,7 @@ export const makeProxyChannel = ({
|
|
|
166
166
|
channelState.combinedChannelId !== packet.combinedChannelId
|
|
167
167
|
) {
|
|
168
168
|
return shouldNeverHappen(
|
|
169
|
-
`Expected proxy channel to have the same combinedChannelId as the packet:\n${channelState.combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
169
|
+
`ProxyChannel[${channelKey}]: Expected proxy channel to have the same combinedChannelId as the packet:\n${channelState.combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
170
170
|
)
|
|
171
171
|
} else {
|
|
172
172
|
// for now just ignore it but should be looked into (there seems to be some kind of race condition/inefficiency)
|
|
@@ -176,7 +176,7 @@ export const makeProxyChannel = ({
|
|
|
176
176
|
const combinedChannelId = getCombinedChannelId(packet.channelIdCandidate)
|
|
177
177
|
if (combinedChannelId !== packet.combinedChannelId) {
|
|
178
178
|
return yield* Effect.die(
|
|
179
|
-
`Expected proxy channel to have the same combinedChannelId as the packet:\n${combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
179
|
+
`ProxyChannel[${channelKey}]: Expected proxy channel to have the same combinedChannelId as the packet:\n${combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
180
180
|
)
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -193,7 +193,7 @@ export const makeProxyChannel = ({
|
|
|
193
193
|
|
|
194
194
|
if (channelState.combinedChannelId !== packet.combinedChannelId) {
|
|
195
195
|
return yield* Effect.die(
|
|
196
|
-
`Expected proxy channel to have the same combinedChannelId as the packet:\n${channelState.combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
196
|
+
`ProxyChannel[${channelKey}]: Expected proxy channel to have the same combinedChannelId as the packet:\n${channelState.combinedChannelId} (channel) === ${packet.combinedChannelId} (packet)`,
|
|
197
197
|
)
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -222,7 +222,7 @@ export const makeProxyChannel = ({
|
|
|
222
222
|
|
|
223
223
|
const ack =
|
|
224
224
|
channelState.ackMap.get(packet.reqId) ??
|
|
225
|
-
shouldNeverHappen(`Expected ack for ${packet.reqId}
|
|
225
|
+
shouldNeverHappen(`[ProxyChannel[${channelKey}]] Expected ack for ${packet.reqId}`)
|
|
226
226
|
|
|
227
227
|
yield* Deferred.succeed(ack, void 0)
|
|
228
228
|
|
|
@@ -305,6 +305,8 @@ export const makeProxyChannel = ({
|
|
|
305
305
|
target,
|
|
306
306
|
combinedChannelId,
|
|
307
307
|
})
|
|
308
|
+
// TODO consider handling previous ackMap entries which might leak/fill-up memory
|
|
309
|
+
// as only successful acks are removed from the map
|
|
308
310
|
ackMap.set(packet.id, ack)
|
|
309
311
|
|
|
310
312
|
yield* sendPacket(packet)
|
|
@@ -315,7 +317,9 @@ export const makeProxyChannel = ({
|
|
|
315
317
|
debugInfo.pendingSends--
|
|
316
318
|
})
|
|
317
319
|
|
|
318
|
-
|
|
320
|
+
// TODO make this configurable
|
|
321
|
+
// Schedule.exponential(10): 10, 20, 40, 80, 160, 320, ...
|
|
322
|
+
yield* innerSend.pipe(Effect.timeout(100), Effect.retry(Schedule.exponential(10)), Effect.orDie)
|
|
319
323
|
}).pipe(Effect.tapErrorCause(Effect.logError))
|
|
320
324
|
|
|
321
325
|
const rerunOnNewChannelFiber = yield* connectedStateRef.changes.pipe(
|
package/src/common.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type MessageQueueItem = {
|
|
|
15
15
|
export type MeshNodeName = string
|
|
16
16
|
|
|
17
17
|
export type ChannelName = string
|
|
18
|
-
export type ChannelKey =
|
|
18
|
+
export type ChannelKey = `target:${MeshNodeName}, channelName:${ChannelName}`
|
|
19
19
|
|
|
20
20
|
// TODO actually use this to avoid timeouts in certain cases
|
|
21
21
|
export class NoConnectionRouteSignal extends Schema.TaggedError<NoConnectionRouteSignal>()(
|
package/src/mesh-schema.ts
CHANGED
|
@@ -86,13 +86,44 @@ export class ProxyChannelPayloadAck extends Schema.TaggedStruct('ProxyChannelPay
|
|
|
86
86
|
* Broadcast to all nodes when a new connection is added.
|
|
87
87
|
* Mostly used for auto-reconnect purposes.
|
|
88
88
|
*/
|
|
89
|
-
// TODO actually use for this use case
|
|
90
89
|
export class NetworkConnectionAdded extends Schema.TaggedStruct('NetworkConnectionAdded', {
|
|
91
90
|
id,
|
|
92
91
|
source: Schema.String,
|
|
93
92
|
target: Schema.String,
|
|
94
93
|
}) {}
|
|
95
94
|
|
|
95
|
+
export class NetworkConnectionTopologyRequest extends Schema.TaggedStruct('NetworkConnectionTopologyRequest', {
|
|
96
|
+
id,
|
|
97
|
+
hops: Schema.Array(Schema.String),
|
|
98
|
+
/** Always fixed to who requested the topology */
|
|
99
|
+
source: Schema.String,
|
|
100
|
+
target: Schema.Literal('-'),
|
|
101
|
+
}) {}
|
|
102
|
+
|
|
103
|
+
export class NetworkConnectionTopologyResponse extends Schema.TaggedStruct('NetworkConnectionTopologyResponse', {
|
|
104
|
+
id,
|
|
105
|
+
reqId: Schema.String,
|
|
106
|
+
remainingHops: Schema.Array(Schema.String),
|
|
107
|
+
nodeName: Schema.String,
|
|
108
|
+
connections: Schema.Array(Schema.String),
|
|
109
|
+
/** Always fixed to who requested the topology */
|
|
110
|
+
source: Schema.String,
|
|
111
|
+
target: Schema.Literal('-'),
|
|
112
|
+
}) {}
|
|
113
|
+
|
|
114
|
+
export const BroadcastChannelPacket = Schema.TaggedStruct('BroadcastChannelPacket', {
|
|
115
|
+
id,
|
|
116
|
+
channelName: Schema.String,
|
|
117
|
+
/**
|
|
118
|
+
* The payload is expected to be encoded/decoded by the send/listen schema.
|
|
119
|
+
* Transferables are not supported.
|
|
120
|
+
*/
|
|
121
|
+
payload: Schema.Any,
|
|
122
|
+
hops: Schema.Array(Schema.String),
|
|
123
|
+
source: Schema.String,
|
|
124
|
+
target: Schema.Literal('-'),
|
|
125
|
+
})
|
|
126
|
+
|
|
96
127
|
export class MessageChannelPacket extends Schema.Union(
|
|
97
128
|
MessageChannelRequest,
|
|
98
129
|
MessageChannelResponseSuccess,
|
|
@@ -106,7 +137,14 @@ export class ProxyChannelPacket extends Schema.Union(
|
|
|
106
137
|
ProxyChannelPayloadAck,
|
|
107
138
|
) {}
|
|
108
139
|
|
|
109
|
-
export class Packet extends Schema.Union(
|
|
140
|
+
export class Packet extends Schema.Union(
|
|
141
|
+
MessageChannelPacket,
|
|
142
|
+
ProxyChannelPacket,
|
|
143
|
+
NetworkConnectionAdded,
|
|
144
|
+
NetworkConnectionTopologyRequest,
|
|
145
|
+
NetworkConnectionTopologyResponse,
|
|
146
|
+
BroadcastChannelPacket,
|
|
147
|
+
) {}
|
|
110
148
|
|
|
111
149
|
export class MessageChannelPing extends Schema.TaggedStruct('MessageChannelPing', {}) {}
|
|
112
150
|
export class MessageChannelPong extends Schema.TaggedStruct('MessageChannelPong', {}) {}
|
package/src/node.test.ts
CHANGED
|
@@ -204,6 +204,8 @@ Vitest.describe('webmesh node', { timeout: testTimeout }, () => {
|
|
|
204
204
|
channelType,
|
|
205
205
|
delays: { x: delayX, y: delayY, connect: connectDelay },
|
|
206
206
|
})
|
|
207
|
+
|
|
208
|
+
yield* Effect.promise(() => nodeX.debug.requestTopology(100))
|
|
207
209
|
}).pipe(
|
|
208
210
|
withCtx(test, {
|
|
209
211
|
skipOtel: true,
|
|
@@ -759,6 +761,50 @@ Vitest.describe('webmesh node', { timeout: testTimeout }, () => {
|
|
|
759
761
|
)
|
|
760
762
|
})
|
|
761
763
|
|
|
764
|
+
/**
|
|
765
|
+
* A E
|
|
766
|
+
* \ /
|
|
767
|
+
* C---D
|
|
768
|
+
* / \
|
|
769
|
+
* B F
|
|
770
|
+
*
|
|
771
|
+
* Topology: Butterfly topology with two connected hubs (C-D) each serving multiple nodes
|
|
772
|
+
*/
|
|
773
|
+
Vitest.describe('butterfly topology', () => {
|
|
774
|
+
Vitest.scopedLive('should work', (test) =>
|
|
775
|
+
Effect.gen(function* () {
|
|
776
|
+
const nodeA = yield* makeMeshNode('A')
|
|
777
|
+
const nodeB = yield* makeMeshNode('B')
|
|
778
|
+
const nodeC = yield* makeMeshNode('C')
|
|
779
|
+
const nodeD = yield* makeMeshNode('D')
|
|
780
|
+
const nodeE = yield* makeMeshNode('E')
|
|
781
|
+
const nodeF = yield* makeMeshNode('F')
|
|
782
|
+
|
|
783
|
+
yield* connectNodesViaMessageChannel(nodeA, nodeC)
|
|
784
|
+
yield* connectNodesViaMessageChannel(nodeB, nodeC)
|
|
785
|
+
yield* connectNodesViaMessageChannel(nodeC, nodeD)
|
|
786
|
+
yield* connectNodesViaMessageChannel(nodeD, nodeE)
|
|
787
|
+
yield* connectNodesViaMessageChannel(nodeD, nodeF)
|
|
788
|
+
|
|
789
|
+
yield* Effect.promise(() => nodeA.debug.requestTopology(100))
|
|
790
|
+
|
|
791
|
+
const nodeACode = Effect.gen(function* () {
|
|
792
|
+
const channelAToE = yield* createChannel(nodeA, 'E')
|
|
793
|
+
yield* channelAToE.send({ message: 'A1' })
|
|
794
|
+
expect(yield* getFirstMessage(channelAToE)).toEqual({ message: 'E1' })
|
|
795
|
+
})
|
|
796
|
+
|
|
797
|
+
const nodeECode = Effect.gen(function* () {
|
|
798
|
+
const channelEToA = yield* createChannel(nodeE, 'A')
|
|
799
|
+
yield* channelEToA.send({ message: 'E1' })
|
|
800
|
+
expect(yield* getFirstMessage(channelEToA)).toEqual({ message: 'A1' })
|
|
801
|
+
})
|
|
802
|
+
|
|
803
|
+
yield* Effect.all([nodeACode, nodeECode], { concurrency: 'unbounded' })
|
|
804
|
+
}).pipe(withCtx(test)),
|
|
805
|
+
)
|
|
806
|
+
})
|
|
807
|
+
|
|
762
808
|
Vitest.describe('mixture of messagechannel and proxy connections', () => {
|
|
763
809
|
// TODO test case to better guard against case where side A tries to create a proxy channel to B
|
|
764
810
|
// and side B tries to create a messagechannel to A
|
|
@@ -799,6 +845,41 @@ Vitest.describe('webmesh node', { timeout: testTimeout }, () => {
|
|
|
799
845
|
}).pipe(withCtx(test)),
|
|
800
846
|
)
|
|
801
847
|
})
|
|
848
|
+
|
|
849
|
+
Vitest.describe('broadcast channel', () => {
|
|
850
|
+
Vitest.scopedLive('should work', (test) =>
|
|
851
|
+
Effect.gen(function* () {
|
|
852
|
+
const nodeA = yield* makeMeshNode('A')
|
|
853
|
+
const nodeB = yield* makeMeshNode('B')
|
|
854
|
+
const nodeC = yield* makeMeshNode('C')
|
|
855
|
+
|
|
856
|
+
yield* connectNodesViaMessageChannel(nodeA, nodeB)
|
|
857
|
+
yield* connectNodesViaMessageChannel(nodeB, nodeC)
|
|
858
|
+
|
|
859
|
+
const channelOnA = yield* nodeA.makeBroadcastChannel({ channelName: 'test', schema: Schema.String })
|
|
860
|
+
const channelOnC = yield* nodeC.makeBroadcastChannel({ channelName: 'test', schema: Schema.String })
|
|
861
|
+
|
|
862
|
+
const listenOnAFiber = yield* channelOnA.listen.pipe(
|
|
863
|
+
Stream.flatten(),
|
|
864
|
+
Stream.runHead,
|
|
865
|
+
Effect.flatten,
|
|
866
|
+
Effect.fork,
|
|
867
|
+
)
|
|
868
|
+
const listenOnCFiber = yield* channelOnC.listen.pipe(
|
|
869
|
+
Stream.flatten(),
|
|
870
|
+
Stream.runHead,
|
|
871
|
+
Effect.flatten,
|
|
872
|
+
Effect.fork,
|
|
873
|
+
)
|
|
874
|
+
|
|
875
|
+
yield* channelOnA.send('A1')
|
|
876
|
+
yield* channelOnC.send('C1')
|
|
877
|
+
|
|
878
|
+
expect(yield* listenOnAFiber).toEqual('C1')
|
|
879
|
+
expect(yield* listenOnCFiber).toEqual('A1')
|
|
880
|
+
}).pipe(withCtx(test)),
|
|
881
|
+
)
|
|
882
|
+
})
|
|
802
883
|
})
|
|
803
884
|
|
|
804
885
|
const otelLayer = IS_CI ? Layer.empty : OtelLiveHttp({ serviceName: 'webmesh-node-test', skipLogUrl: false })
|