@livestore/webmesh 0.3.0-dev.5 → 0.3.0-dev.50

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 (69) hide show
  1. package/README.md +43 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/channel/direct-channel-internal.d.ts +26 -0
  4. package/dist/channel/direct-channel-internal.d.ts.map +1 -0
  5. package/dist/channel/direct-channel-internal.js +217 -0
  6. package/dist/channel/direct-channel-internal.js.map +1 -0
  7. package/dist/channel/direct-channel.d.ts +22 -0
  8. package/dist/channel/direct-channel.d.ts.map +1 -0
  9. package/dist/channel/direct-channel.js +153 -0
  10. package/dist/channel/direct-channel.js.map +1 -0
  11. package/dist/channel/proxy-channel.d.ts +3 -3
  12. package/dist/channel/proxy-channel.d.ts.map +1 -1
  13. package/dist/channel/proxy-channel.js +119 -37
  14. package/dist/channel/proxy-channel.js.map +1 -1
  15. package/dist/common.d.ts +47 -19
  16. package/dist/common.d.ts.map +1 -1
  17. package/dist/common.js +13 -5
  18. package/dist/common.js.map +1 -1
  19. package/dist/mesh-schema.d.ts +79 -13
  20. package/dist/mesh-schema.d.ts.map +1 -1
  21. package/dist/mesh-schema.js +59 -10
  22. package/dist/mesh-schema.js.map +1 -1
  23. package/dist/mod.d.ts +2 -2
  24. package/dist/mod.d.ts.map +1 -1
  25. package/dist/mod.js +2 -2
  26. package/dist/mod.js.map +1 -1
  27. package/dist/node.d.ts +56 -23
  28. package/dist/node.d.ts.map +1 -1
  29. package/dist/node.js +323 -115
  30. package/dist/node.js.map +1 -1
  31. package/dist/node.test.d.ts +1 -1
  32. package/dist/node.test.d.ts.map +1 -1
  33. package/dist/node.test.js +489 -157
  34. package/dist/node.test.js.map +1 -1
  35. package/dist/utils.d.ts +4 -4
  36. package/dist/utils.d.ts.map +1 -1
  37. package/dist/utils.js +7 -1
  38. package/dist/utils.js.map +1 -1
  39. package/dist/websocket-edge.d.ts +56 -0
  40. package/dist/websocket-edge.d.ts.map +1 -0
  41. package/dist/websocket-edge.js +93 -0
  42. package/dist/websocket-edge.js.map +1 -0
  43. package/package.json +10 -6
  44. package/src/channel/direct-channel-internal.ts +356 -0
  45. package/src/channel/direct-channel.ts +234 -0
  46. package/src/channel/proxy-channel.ts +344 -234
  47. package/src/common.ts +24 -17
  48. package/src/mesh-schema.ts +73 -20
  49. package/src/mod.ts +2 -2
  50. package/src/node.test.ts +723 -190
  51. package/src/node.ts +482 -156
  52. package/src/utils.ts +13 -2
  53. package/src/websocket-edge.ts +191 -0
  54. package/dist/channel/message-channel.d.ts +0 -20
  55. package/dist/channel/message-channel.d.ts.map +0 -1
  56. package/dist/channel/message-channel.js +0 -183
  57. package/dist/channel/message-channel.js.map +0 -1
  58. package/dist/websocket-connection.d.ts +0 -51
  59. package/dist/websocket-connection.d.ts.map +0 -1
  60. package/dist/websocket-connection.js +0 -74
  61. package/dist/websocket-connection.js.map +0 -1
  62. package/dist/websocket-server.d.ts +0 -7
  63. package/dist/websocket-server.d.ts.map +0 -1
  64. package/dist/websocket-server.js +0 -24
  65. package/dist/websocket-server.js.map +0 -1
  66. package/src/channel/message-channel.ts +0 -354
  67. package/src/websocket-connection.ts +0 -158
  68. package/src/websocket-server.ts +0 -40
  69. package/tsconfig.json +0 -11
package/src/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable prefer-arrow/prefer-arrow-functions */
2
- import { Duration } from '@livestore/utils/effect'
2
+ import { Duration, Effect } from '@livestore/utils/effect'
3
3
 
4
4
  /**
5
5
  * A set of values that expire after a given timeout
@@ -10,10 +10,19 @@ export class TimeoutSet<V> {
10
10
  private timeoutHandle: NodeJS.Timeout | undefined
11
11
  private readonly timeoutMs: number
12
12
 
13
- constructor({ timeout }: { timeout: Duration.DurationInput }) {
13
+ private constructor({ timeout }: { timeout: Duration.DurationInput }) {
14
14
  this.timeoutMs = Duration.toMillis(timeout)
15
15
  }
16
16
 
17
+ static make = (timeout: Duration.DurationInput) =>
18
+ Effect.gen(function* () {
19
+ const timeoutSet = new TimeoutSet({ timeout })
20
+
21
+ yield* Effect.addFinalizer(() => Effect.sync(() => timeoutSet.onShutdown()))
22
+
23
+ return timeoutSet
24
+ })
25
+
17
26
  add(value: V): void {
18
27
  this.values.set(value, Date.now())
19
28
  this.scheduleCleanup()
@@ -44,4 +53,6 @@ export class TimeoutSet<V> {
44
53
  }
45
54
  }
46
55
  }
56
+
57
+ onShutdown = () => clearTimeout(this.timeoutHandle)
47
58
  }
@@ -0,0 +1,191 @@
1
+ import type { HttpClient } from '@livestore/utils/effect'
2
+ import {
3
+ Deferred,
4
+ Effect,
5
+ Either,
6
+ Exit,
7
+ Layer,
8
+ Queue,
9
+ Schedule,
10
+ Schema,
11
+ Scope,
12
+ Socket,
13
+ Stream,
14
+ WebChannel,
15
+ } from '@livestore/utils/effect'
16
+
17
+ import * as WebmeshSchema from './mesh-schema.js'
18
+ import type { MeshNode } from './node.js'
19
+
20
+ export class WSEdgeInit extends Schema.TaggedStruct('WSEdgeInit', {
21
+ from: Schema.String,
22
+ }) {}
23
+
24
+ export class WSEdgePayload extends Schema.TaggedStruct('WSEdgePayload', {
25
+ from: Schema.String,
26
+ payload: Schema.Any,
27
+ }) {}
28
+
29
+ export class WSEdgeMessage extends Schema.Union(WSEdgeInit, WSEdgePayload) {}
30
+
31
+ export const MessageMsgPack = Schema.MsgPack(WSEdgeMessage)
32
+
33
+ export type SocketType =
34
+ | {
35
+ _tag: 'leaf'
36
+ from: string
37
+ }
38
+ | {
39
+ _tag: 'relay'
40
+ }
41
+
42
+ export const connectViaWebSocket = ({
43
+ node,
44
+ url,
45
+ openTimeout,
46
+ }: {
47
+ node: MeshNode
48
+ url: string
49
+ openTimeout?: number
50
+ }): Effect.Effect<void, never, Scope.Scope | HttpClient.HttpClient> =>
51
+ Effect.gen(function* () {
52
+ const socket = yield* Socket.makeWebSocket(url, { openTimeout })
53
+
54
+ const edgeChannel = yield* makeWebSocketEdge({
55
+ socket,
56
+ socketType: { _tag: 'leaf', from: node.nodeName },
57
+ debug: { id: `node:${node.nodeName}` },
58
+ })
59
+
60
+ yield* node
61
+ .addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true })
62
+ .pipe(Effect.acquireRelease(() => node.removeEdge('ws').pipe(Effect.orDie)))
63
+
64
+ yield* edgeChannel.webChannel.closedDeferred
65
+ }).pipe(Effect.scoped, Effect.forever, Effect.interruptible, Effect.provide(binaryWebSocketConstructorLayer))
66
+
67
+ const binaryWebSocketConstructorLayer = Layer.succeed(Socket.WebSocketConstructor, (url, protocols) => {
68
+ const socket = new globalThis.WebSocket(url, protocols)
69
+ socket.binaryType = 'arraybuffer'
70
+ return socket
71
+ })
72
+
73
+ export const makeWebSocketEdge = ({
74
+ socket,
75
+ socketType,
76
+ debug: debugInfo,
77
+ }: {
78
+ socket: Socket.Socket
79
+ socketType: SocketType
80
+ debug?: { id?: string }
81
+ }): Effect.Effect<
82
+ {
83
+ webChannel: WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
84
+ from: string
85
+ },
86
+ never,
87
+ Scope.Scope | HttpClient.HttpClient
88
+ > =>
89
+ Effect.scopeWithCloseable((scope) =>
90
+ Effect.gen(function* () {
91
+ const fromDeferred = yield* Deferred.make<string>()
92
+
93
+ const listenQueue = yield* Queue.unbounded<typeof WebmeshSchema.Packet.Type>().pipe(
94
+ Effect.acquireRelease(Queue.shutdown),
95
+ )
96
+
97
+ const schema = WebChannel.mapSchema(WebmeshSchema.Packet)
98
+
99
+ const isConnectedLatch = yield* Effect.makeLatch(true)
100
+
101
+ const closedDeferred = yield* Deferred.make<void>().pipe(Effect.acquireRelease(Deferred.done(Exit.void)))
102
+
103
+ const retryOpenTimeoutSchedule = Schedule.union(Schedule.exponential(100), Schedule.spaced(5000)).pipe(
104
+ Schedule.whileInput((_: Socket.SocketError) => _.reason === 'OpenTimeout' || _.reason === 'Open'),
105
+ )
106
+
107
+ yield* Stream.never.pipe(
108
+ Stream.pipeThroughChannel(Socket.toChannel(socket)),
109
+ Stream.catchTag(
110
+ 'SocketError',
111
+ Effect.fnUntraced(function* (error) {
112
+ // yield* Effect.logError(`[websocket-edge] Socket error`, error, { socketType, debugId: debugInfo?.id })
113
+ // In the case of the socket being closed, we're interrupting the stream
114
+ // and close the WebChannel (which can be observed from the outside)
115
+ if (error.reason === 'Close') {
116
+ yield* Deferred.succeed(closedDeferred, undefined)
117
+ yield* isConnectedLatch.close
118
+ return yield* Effect.interrupt
119
+ } else {
120
+ return yield* Effect.fail(error)
121
+ }
122
+ }),
123
+ ),
124
+ Stream.retry(retryOpenTimeoutSchedule),
125
+ Stream.tap(
126
+ Effect.fn(function* (bytes) {
127
+ const msg = yield* Schema.decode(MessageMsgPack)(new Uint8Array(bytes))
128
+ if (msg._tag === 'WSEdgeInit') {
129
+ yield* Deferred.succeed(fromDeferred, msg.from)
130
+ } else {
131
+ const decodedPayload = yield* Schema.decode(schema.listen)(msg.payload)
132
+ // yield* Effect.logDebug(`[websocket-edge] recv from ${msg.from}: ${decodedPayload._tag}`, decodedPayload)
133
+ yield* Queue.offer(listenQueue, decodedPayload)
134
+ }
135
+ }),
136
+ ),
137
+ Stream.runDrain,
138
+ Effect.tap(
139
+ Effect.fnUntraced(function* () {
140
+ yield* Deferred.succeed(closedDeferred, undefined)
141
+ yield* isConnectedLatch.close
142
+ }),
143
+ ),
144
+ Effect.interruptible,
145
+ Effect.withSpan('makeWebSocketEdge:listen'),
146
+ Effect.tapCauseLogPretty,
147
+ Effect.forkScoped,
148
+ )
149
+
150
+ const sendToSocket = yield* socket.writer
151
+
152
+ const initHandshake = (from: string) =>
153
+ sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgeInit', from }))
154
+
155
+ if (socketType._tag === 'leaf') {
156
+ yield* initHandshake(socketType.from)
157
+ }
158
+
159
+ const deferredResult = yield* fromDeferred
160
+ const from = socketType._tag === 'leaf' ? socketType.from : deferredResult
161
+
162
+ if (socketType._tag === 'relay') {
163
+ yield* initHandshake(from)
164
+ }
165
+
166
+ const send = (message: typeof WebmeshSchema.Packet.Type) =>
167
+ Effect.gen(function* () {
168
+ yield* isConnectedLatch.await
169
+ const payload = yield* Schema.encode(schema.send)(message)
170
+ yield* sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgePayload', payload, from }))
171
+ }).pipe(Effect.orDie)
172
+
173
+ const listen = Stream.fromQueue(listenQueue).pipe(
174
+ Stream.map(Either.right),
175
+ WebChannel.listenToDebugPing('websocket-edge'),
176
+ )
177
+
178
+ const webChannel = {
179
+ [WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
180
+ send,
181
+ listen,
182
+ closedDeferred,
183
+ schema,
184
+ supportsTransferables: false,
185
+ shutdown: Scope.close(scope, Exit.void),
186
+ debugInfo,
187
+ } satisfies WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
188
+
189
+ return { webChannel, from }
190
+ }).pipe(Effect.withSpanScoped('makeWebSocketEdge'), Effect.orDie),
191
+ )
@@ -1,20 +0,0 @@
1
- import type { PubSub, Schema, Scope } from '@livestore/utils/effect';
2
- import { Effect, Queue, WebChannel } from '@livestore/utils/effect';
3
- import { type ChannelName, type MeshNodeName, type MessageQueueItem } from '../common.js';
4
- import * as MeshSchema from '../mesh-schema.js';
5
- interface MakeMessageChannelArgs {
6
- nodeName: MeshNodeName;
7
- queue: Queue.Queue<MessageQueueItem>;
8
- newConnectionAvailablePubSub: PubSub.PubSub<MeshNodeName>;
9
- channelName: ChannelName;
10
- target: MeshNodeName;
11
- sendPacket: (packet: typeof MeshSchema.MessageChannelPacket.Type) => Effect.Effect<void>;
12
- checkTransferableConnections: (packet: typeof MeshSchema.MessageChannelPacket.Type) => typeof MeshSchema.MessageChannelResponseNoTransferables.Type | undefined;
13
- schema: {
14
- send: Schema.Schema<any, any>;
15
- listen: Schema.Schema<any, any>;
16
- };
17
- }
18
- export declare const makeMessageChannel: ({ nodeName, queue, newConnectionAvailablePubSub, target, checkTransferableConnections, channelName, schema, sendPacket, }: MakeMessageChannelArgs) => Effect.Effect<WebChannel.WebChannel<any, any, never>, never, Scope.Scope>;
19
- export {};
20
- //# sourceMappingURL=message-channel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-channel.d.ts","sourceRoot":"","sources":["../../src/channel/message-channel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpE,OAAO,EAEL,MAAM,EAIN,KAAK,EAIL,UAAU,EACX,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAA0B,MAAM,cAAc,CAAA;AACjH,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAE/C,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,YAAY,CAAA;IACtB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IACpC,4BAA4B,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACzD,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,YAAY,CAAA;IACpB,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,UAAU,CAAC,oBAAoB,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACxF,4BAA4B,EAAE,CAC5B,MAAM,EAAE,OAAO,UAAU,CAAC,oBAAoB,CAAC,IAAI,KAChD,OAAO,UAAU,CAAC,qCAAqC,CAAC,IAAI,GAAG,SAAS,CAAA;IAC7E,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;KAChC,CAAA;CACF;AAED,eAAO,MAAM,kBAAkB,8HAS5B,sBAAsB,8EAsT6B,CAAA"}
@@ -1,183 +0,0 @@
1
- import { casesHandled, shouldNeverHappen } from '@livestore/utils';
2
- import { Deferred, Effect, Either, Fiber, FiberHandle, Queue, Schedule, Stream, SubscriptionRef, WebChannel, } from '@livestore/utils/effect';
3
- import { packetAsOtelAttributes } from '../common.js';
4
- import * as MeshSchema from '../mesh-schema.js';
5
- export const makeMessageChannel = ({ nodeName, queue, newConnectionAvailablePubSub, target, checkTransferableConnections, channelName, schema, sendPacket, }) => Effect.gen(function* () {
6
- const reconnectTriggerQueue = yield* Queue.unbounded();
7
- const reconnect = Queue.offer(reconnectTriggerQueue, void 0);
8
- const makeInitialState = Effect.gen(function* () {
9
- const deferred = yield* Deferred.make();
10
- return { _tag: 'Initial', deferred };
11
- });
12
- const channelStateRef = { current: yield* makeInitialState };
13
- const makeMessageChannelInternal = Effect.gen(function* () {
14
- const processMessagePacket = ({ packet, respondToSender }) => Effect.gen(function* () {
15
- const channelState = channelStateRef.current;
16
- // yield* Effect.log(`${nodeName}:processing packet ${packet._tag}, channel state: ${channelState._tag}`)
17
- switch (packet._tag) {
18
- // Since there can be concurrent MessageChannel responses from both sides,
19
- // we need to decide which side's port we want to use and which side's port we want to ignore.
20
- // This is only relevant in the case where both sides already sent their responses.
21
- // In this case we're using the target name as a "tie breaker" to decide which side's port to use.
22
- // We do this by sorting the target names lexicographically and use the first one as the winner.
23
- case 'MessageChannelResponseSuccess': {
24
- if (channelState._tag === 'Initial') {
25
- return shouldNeverHappen(`Expected to find message channel request from ${target}, but was in ${channelState._tag} state`);
26
- }
27
- if (channelState._tag === 'Established') {
28
- const deferred = yield* Deferred.make();
29
- channelStateRef.current = { _tag: 'RequestSent', deferred };
30
- yield* reconnect;
31
- return;
32
- }
33
- const thisSideAlsoResponded = channelState._tag === 'ResponseSent';
34
- const usePortFromThisSide = thisSideAlsoResponded && nodeName > target;
35
- yield* Effect.annotateCurrentSpan({ usePortFromThisSide });
36
- const winnerPort = usePortFromThisSide ? channelState.locallyCreatedPort : packet.port;
37
- yield* Deferred.succeed(channelState.deferred, winnerPort);
38
- return;
39
- }
40
- case 'MessageChannelResponseNoTransferables': {
41
- if (channelState._tag === 'Established')
42
- return;
43
- yield* Deferred.fail(channelState.deferred, packet);
44
- channelStateRef.current = yield* makeInitialState;
45
- return;
46
- }
47
- case 'MessageChannelRequest': {
48
- const mc = new MessageChannel();
49
- const shouldReconnect = channelState._tag === 'Established';
50
- const deferred = channelState._tag === 'Established'
51
- ? yield* Deferred.make()
52
- : channelState.deferred;
53
- channelStateRef.current = { _tag: 'ResponseSent', locallyCreatedPort: mc.port1, deferred };
54
- yield* respondToSender(MeshSchema.MessageChannelResponseSuccess.make({
55
- reqId: packet.id,
56
- target,
57
- source: nodeName,
58
- channelName: packet.channelName,
59
- hops: [],
60
- remainingHops: packet.hops,
61
- port: mc.port2,
62
- }));
63
- // If there's an established channel, we use the new request as a signal
64
- // to drop the old channel and use the new one
65
- if (shouldReconnect) {
66
- yield* reconnect;
67
- }
68
- break;
69
- }
70
- default: {
71
- return casesHandled(packet);
72
- }
73
- }
74
- }).pipe(Effect.withSpan(`handleMessagePacket:${packet._tag}:${packet.source}→${packet.target}`, {
75
- attributes: packetAsOtelAttributes(packet),
76
- }));
77
- yield* Stream.fromQueue(queue).pipe(Stream.tap(processMessagePacket), Stream.runDrain, Effect.tapCauseLogPretty, Effect.forkScoped);
78
- const channelFromPort = (port) => Effect.gen(function* () {
79
- channelStateRef.current = { _tag: 'Established' };
80
- // NOTE to support re-connects we need to ack each message
81
- const channel = yield* WebChannel.messagePortChannelWithAck({ port, schema });
82
- return channel;
83
- });
84
- const channelState = channelStateRef.current;
85
- if (channelState._tag === 'Initial' || channelState._tag === 'RequestSent') {
86
- // Important to make a new deferred here as the old one might have been used already
87
- // TODO model this better
88
- const deferred = channelState._tag === 'RequestSent'
89
- ? yield* Deferred.make()
90
- : channelState.deferred;
91
- channelStateRef.current = { _tag: 'RequestSent', deferred };
92
- const connectionRequest = Effect.gen(function* () {
93
- const packet = MeshSchema.MessageChannelRequest.make({ source: nodeName, target, channelName, hops: [] });
94
- const noTransferableResponse = checkTransferableConnections(packet);
95
- if (noTransferableResponse !== undefined) {
96
- yield* Effect.spanEvent(`No transferable connections found for ${packet.source}→${packet.target}`);
97
- yield* Deferred.fail(deferred, noTransferableResponse);
98
- return;
99
- }
100
- yield* sendPacket(packet);
101
- });
102
- yield* connectionRequest;
103
- const retryOnNewConnectionFiber = yield* Stream.fromPubSub(newConnectionAvailablePubSub).pipe(Stream.tap(() => Effect.spanEvent(`RetryOnNewConnection`)), Stream.tap(() => connectionRequest), Stream.runDrain, Effect.forkScoped);
104
- const portResult = yield* deferred.pipe(Effect.either);
105
- yield* Fiber.interrupt(retryOnNewConnectionFiber);
106
- if (portResult._tag === 'Right') {
107
- return yield* channelFromPort(portResult.right);
108
- }
109
- else {
110
- // We'll keep retrying with a new connection
111
- yield* Stream.fromPubSub(newConnectionAvailablePubSub).pipe(Stream.take(1), Stream.runDrain);
112
- yield* reconnect;
113
- return yield* Effect.interrupt;
114
- }
115
- }
116
- else {
117
- // In this case we've already received a request from the other side (before we had a chance to send our request),
118
- // so we already created a MessageChannel,responded with one port
119
- // and are now using the other port to create the channel.
120
- if (channelState._tag === 'ResponseSent') {
121
- return yield* channelFromPort(channelState.locallyCreatedPort);
122
- }
123
- else {
124
- return shouldNeverHappen(`Expected pending message channel to be in ResponseSent state, but was in ${channelState._tag} state`);
125
- }
126
- }
127
- });
128
- const internalChannelSref = yield* SubscriptionRef.make(false);
129
- const listenQueue = yield* Queue.unbounded();
130
- let connectCounter = 0;
131
- const connect = Effect.gen(function* () {
132
- const connectCount = ++connectCounter;
133
- yield* Effect.spanEvent(`Connecting#${connectCount}`);
134
- yield* SubscriptionRef.set(internalChannelSref, false);
135
- yield* Effect.addFinalizer(() => Effect.spanEvent(`Disconnected#${connectCount}`));
136
- const internalChannel = yield* makeMessageChannelInternal;
137
- yield* SubscriptionRef.set(internalChannelSref, internalChannel);
138
- yield* Effect.spanEvent(`Connected#${connectCount}`);
139
- yield* internalChannel.listen.pipe(Stream.flatten(), Stream.tap((msg) => Queue.offer(listenQueue, msg)), Stream.runDrain, Effect.tapCauseLogPretty, Effect.forkScoped);
140
- yield* Effect.never;
141
- }).pipe(Effect.scoped);
142
- const fiberHandle = yield* FiberHandle.make();
143
- const runConnect = Effect.gen(function* () {
144
- // Cleanly shutdown the previous connection first
145
- // Otherwise the old and new connection will "overlap"
146
- yield* FiberHandle.clear(fiberHandle);
147
- yield* FiberHandle.run(fiberHandle, connect);
148
- });
149
- yield* runConnect;
150
- // Then listen for reconnects
151
- yield* Stream.fromQueue(reconnectTriggerQueue).pipe(Stream.tap(() => runConnect), Stream.runDrain, Effect.tapCauseLogPretty, Effect.forkScoped);
152
- // Wait for the initial connection to be established or for an error to occur
153
- yield* Effect.raceFirst(SubscriptionRef.waitUntil(internalChannelSref, (channel) => channel !== false), FiberHandle.join(fiberHandle));
154
- const parentSpan = yield* Effect.currentSpan.pipe(Effect.orDie);
155
- const send = (message) => Effect.gen(function* () {
156
- const sendFiberHandle = yield* FiberHandle.make();
157
- const sentDeferred = yield* Deferred.make();
158
- const trySend = Effect.gen(function* () {
159
- const channel = (yield* SubscriptionRef.waitUntil(internalChannelSref, (channel) => channel !== false));
160
- const innerSend = Effect.gen(function* () {
161
- yield* channel.send(message);
162
- yield* Deferred.succeed(sentDeferred, void 0);
163
- });
164
- yield* innerSend.pipe(Effect.timeout(100), Effect.retry(Schedule.exponential(100)), Effect.orDie);
165
- }).pipe(Effect.tapErrorCause(Effect.logError));
166
- const rerunOnNewChannelFiber = yield* internalChannelSref.changes.pipe(Stream.filter((_) => _ === false), Stream.tap(() => FiberHandle.run(sendFiberHandle, trySend)), Stream.runDrain, Effect.fork);
167
- yield* FiberHandle.run(sendFiberHandle, trySend);
168
- yield* sentDeferred;
169
- yield* Fiber.interrupt(rerunOnNewChannelFiber);
170
- }).pipe(Effect.scoped, Effect.withParentSpan(parentSpan));
171
- const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right));
172
- const closedDeferred = yield* Deferred.make();
173
- const webChannel = {
174
- [WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
175
- send,
176
- listen,
177
- closedDeferred,
178
- supportsTransferables: true,
179
- schema,
180
- };
181
- return webChannel;
182
- }).pipe(Effect.withSpanScoped('makeMessageChannel'));
183
- //# sourceMappingURL=message-channel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-channel.js","sourceRoot":"","sources":["../../src/channel/message-channel.ts"],"names":[],"mappings":"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"}
@@ -1,51 +0,0 @@
1
- import type { Scope } from '@livestore/utils/effect';
2
- import { Effect, Schedule, Schema, WebChannel } from '@livestore/utils/effect';
3
- import type NodeWebSocket from 'ws';
4
- import * as MeshSchema from './mesh-schema.js';
5
- import type { MeshNode } from './node.js';
6
- declare const WSConnectionInit_base: Schema.TaggedStruct<"WSConnectionInit", {
7
- from: typeof Schema.String;
8
- }>;
9
- export declare class WSConnectionInit extends WSConnectionInit_base {
10
- }
11
- declare const WSConnectionPayload_base: Schema.TaggedStruct<"WSConnectionPayload", {
12
- from: typeof Schema.String;
13
- payload: typeof Schema.Any;
14
- }>;
15
- export declare class WSConnectionPayload extends WSConnectionPayload_base {
16
- }
17
- declare const WSConnectionMessage_base: Schema.Union<[typeof WSConnectionInit, typeof WSConnectionPayload]>;
18
- export declare class WSConnectionMessage extends WSConnectionMessage_base {
19
- }
20
- export declare const MessageMsgPack: Schema.transform<Schema.Schema<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, never>, Schema.Schema<{
21
- readonly _tag: "WSConnectionInit";
22
- readonly from: string;
23
- } | {
24
- readonly _tag: "WSConnectionPayload";
25
- readonly payload: any;
26
- readonly from: string;
27
- }, {
28
- readonly _tag: "WSConnectionInit";
29
- readonly from: string;
30
- } | {
31
- readonly _tag: "WSConnectionPayload";
32
- readonly payload: any;
33
- readonly from: string;
34
- }, never>>;
35
- export type SocketType = {
36
- _tag: 'leaf';
37
- from: string;
38
- } | {
39
- _tag: 'relay';
40
- };
41
- export declare const connectViaWebSocket: ({ node, url, reconnect, }: {
42
- node: MeshNode;
43
- url: string;
44
- reconnect?: Schedule.Schedule<unknown> | false;
45
- }) => Effect.Effect<void, never, Scope.Scope>;
46
- export declare const makeWebSocketConnection: (socket: globalThis.WebSocket | NodeWebSocket.WebSocket, socketType: SocketType) => Effect.Effect<{
47
- webChannel: WebChannel.WebChannel<typeof MeshSchema.Packet.Type, typeof MeshSchema.Packet.Type>;
48
- from: string;
49
- }, never, Scope.Scope>;
50
- export {};
51
- //# sourceMappingURL=websocket-connection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-connection.d.ts","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAEL,MAAM,EAIN,QAAQ,EACR,MAAM,EAEN,UAAU,EAEX,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,aAAa,MAAM,IAAI,CAAA;AAEnC,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;;;;AAEzC,qBAAa,gBAAiB,SAAQ,qBAEpC;CAAG;;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAGvC;CAAG;;AAEL,qBAAa,mBAAoB,SAAQ,wBAAmD;CAAG;AAE/F,eAAO,MAAM,cAAc;;;;;;;;;;;;;;UAAsC,CAAA;AAEjE,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAEL,eAAO,MAAM,mBAAmB,8BAI7B;IACD,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,KAAK,CAAA;CAC/C,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAkBtC,CAAA;AAEJ,eAAO,MAAM,uBAAuB,WAC1B,UAAU,CAAC,SAAS,GAAG,aAAa,CAAC,SAAS,cAC1C,UAAU,KACrB,MAAM,CAAC,MAAM,CACd;IACE,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/F,IAAI,EAAE,MAAM,CAAA;CACb,EACD,KAAK,EACL,KAAK,CAAC,KAAK,CAgFT,CAAA"}
@@ -1,74 +0,0 @@
1
- import { Deferred, Effect, Either, FiberHandle, Queue, Schedule, Schema, Stream, WebChannel, WebSocket, } from '@livestore/utils/effect';
2
- import * as MeshSchema from './mesh-schema.js';
3
- export class WSConnectionInit extends Schema.TaggedStruct('WSConnectionInit', {
4
- from: Schema.String,
5
- }) {
6
- }
7
- export class WSConnectionPayload extends Schema.TaggedStruct('WSConnectionPayload', {
8
- from: Schema.String,
9
- payload: Schema.Any,
10
- }) {
11
- }
12
- export class WSConnectionMessage extends Schema.Union(WSConnectionInit, WSConnectionPayload) {
13
- }
14
- export const MessageMsgPack = Schema.MsgPack(WSConnectionMessage);
15
- export const connectViaWebSocket = ({ node, url, reconnect = Schedule.exponential(100), }) => Effect.gen(function* () {
16
- const fiberHandle = yield* FiberHandle.make();
17
- const connect = Effect.gen(function* () {
18
- const socket = yield* WebSocket.makeWebSocket({ url, reconnect });
19
- // NOTE we want to use `runFork` here so this Effect is not part of the fiber that will be interrupted
20
- socket.addEventListener('close', () => FiberHandle.run(fiberHandle, connect).pipe(Effect.runFork));
21
- const connection = yield* makeWebSocketConnection(socket, { _tag: 'leaf', from: node.nodeName });
22
- yield* node.addConnection({ target: 'ws', connectionChannel: connection.webChannel, replaceIfExists: true });
23
- yield* Effect.never;
24
- }).pipe(Effect.scoped, Effect.withSpan('@livestore/webmesh:websocket-connection:connect'));
25
- yield* FiberHandle.run(fiberHandle, connect);
26
- });
27
- export const makeWebSocketConnection = (socket, socketType) => Effect.gen(function* () {
28
- socket.binaryType = 'arraybuffer';
29
- const fromDeferred = yield* Deferred.make();
30
- yield* Stream.fromEventListener(socket, 'message').pipe(Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg.data))), Stream.flatten(), Stream.tap((msg) => Effect.gen(function* () {
31
- if (msg._tag === 'WSConnectionInit') {
32
- yield* Deferred.succeed(fromDeferred, msg.from);
33
- }
34
- else {
35
- const decodedPayload = yield* Schema.decode(MeshSchema.Packet)(msg.payload);
36
- yield* Queue.offer(listenQueue, decodedPayload);
37
- }
38
- })), Stream.runDrain, Effect.tapCauseLogPretty, Effect.forkScoped);
39
- const listenQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
40
- const initHandshake = (from) => socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSConnectionInit', from }));
41
- if (socketType._tag === 'leaf') {
42
- initHandshake(socketType.from);
43
- }
44
- const deferredResult = yield* fromDeferred;
45
- const from = socketType._tag === 'leaf' ? socketType.from : deferredResult;
46
- if (socketType._tag === 'relay') {
47
- initHandshake(from);
48
- }
49
- const isConnectedLatch = yield* Effect.makeLatch(true);
50
- const closedDeferred = yield* Deferred.make();
51
- yield* Effect.eventListener(socket, 'close', () => Effect.gen(function* () {
52
- yield* isConnectedLatch.close;
53
- yield* Deferred.succeed(closedDeferred, undefined);
54
- }), { once: true });
55
- const send = (message) => Effect.gen(function* () {
56
- yield* isConnectedLatch.await;
57
- const payload = yield* Schema.encode(MeshSchema.Packet)(message);
58
- socket.send(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSConnectionPayload', payload, from }));
59
- });
60
- const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right));
61
- const webChannel = {
62
- [WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
63
- send,
64
- listen,
65
- closedDeferred,
66
- schema: { listen: MeshSchema.Packet, send: MeshSchema.Packet },
67
- supportsTransferables: false,
68
- };
69
- return {
70
- webChannel: webChannel,
71
- from,
72
- };
73
- });
74
- //# sourceMappingURL=websocket-connection.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-connection.js","sourceRoot":"","sources":["../src/websocket-connection.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import type { Scope } from '@livestore/utils/effect';
2
- import { Effect } from '@livestore/utils/effect';
3
- import * as WebSocket from 'ws';
4
- export declare const makeWebSocketServer: ({ relayNodeName, }: {
5
- relayNodeName: string;
6
- }) => Effect.Effect<WebSocket.WebSocketServer, never, Scope.Scope>;
7
- //# sourceMappingURL=websocket-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,KAAK,SAAS,MAAM,IAAI,CAAA;AAK/B,eAAO,MAAM,mBAAmB,uBAE7B;IACD,aAAa,EAAE,MAAM,CAAA;CACtB,KAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA4B3D,CAAA"}
@@ -1,24 +0,0 @@
1
- import { Effect } from '@livestore/utils/effect';
2
- import * as WebSocket from 'ws';
3
- import { makeMeshNode } from './node.js';
4
- import { makeWebSocketConnection } from './websocket-connection.js';
5
- export const makeWebSocketServer = ({ relayNodeName, }) => Effect.gen(function* () {
6
- const server = new WebSocket.WebSocketServer({ noServer: true });
7
- const node = yield* makeMeshNode(relayNodeName);
8
- const runtime = yield* Effect.runtime();
9
- // TODO handle node disconnects (i.e. remove respective connection)
10
- server.on('connection', (socket) => {
11
- Effect.gen(function* () {
12
- const { webChannel, from } = yield* makeWebSocketConnection(socket, { _tag: 'relay' });
13
- yield* node.addConnection({ target: from, connectionChannel: webChannel, replaceIfExists: true });
14
- yield* Effect.log(`WS Relay ${relayNodeName}: added connection from '${from}'`);
15
- socket.addEventListener('close', () => Effect.gen(function* () {
16
- yield* node.removeConnection(from);
17
- yield* Effect.log(`WS Relay ${relayNodeName}: removed connection from '${from}'`);
18
- }).pipe(Effect.provide(runtime), Effect.runFork));
19
- yield* Effect.never;
20
- }).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.provide(runtime), Effect.runFork);
21
- });
22
- return server;
23
- });
24
- //# sourceMappingURL=websocket-server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,KAAK,SAAS,MAAM,IAAI,CAAA;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAEnE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,aAAa,GAGd,EAAgE,EAAE,CACjE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAEhE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;IAE/C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAS,CAAA;IAE9C,mEAAmE;IACnE,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QACjC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,uBAAuB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;YAEtF,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAA;YACjG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,aAAa,4BAA4B,IAAI,GAAG,CAAC,CAAA;YAE/E,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CACpC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAClB,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;gBAClC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,aAAa,8BAA8B,IAAI,GAAG,CAAC,CAAA;YACnF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CACjD,CAAA;YAED,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;QACrB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3F,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC,CAAC,CAAA"}