@livestore/webmesh 0.0.0-snapshot-76bdaead452769e22fce7f5ec10482474416e04d → 0.0.0-snapshot-2da03812fc739d068b0e57f612c11fe4c4b28b0c
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/websocket-edge.d.ts +6 -5
- package/dist/websocket-edge.d.ts.map +1 -1
- package/dist/websocket-edge.js +34 -21
- package/dist/websocket-edge.js.map +1 -1
- package/package.json +3 -5
- package/src/websocket-edge.ts +53 -38
- package/dist/websocket-server.d.ts +0 -7
- package/dist/websocket-server.d.ts.map +0 -1
- package/dist/websocket-server.js +0 -38
- package/dist/websocket-server.js.map +0 -1
- package/src/websocket-server.ts +0 -57
package/dist/websocket-edge.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { HttpClient } from '@livestore/utils/effect';
|
|
2
|
-
import { Effect,
|
|
3
|
-
import type * as NodeWebSocket from 'ws';
|
|
2
|
+
import { Effect, Schema, Scope, Socket, WebChannel } from '@livestore/utils/effect';
|
|
4
3
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
5
4
|
import type { MeshNode } from './node.js';
|
|
6
5
|
declare const WSEdgeInit_base: Schema.TaggedStruct<"WSEdgeInit", {
|
|
@@ -38,12 +37,14 @@ export type SocketType = {
|
|
|
38
37
|
} | {
|
|
39
38
|
_tag: 'relay';
|
|
40
39
|
};
|
|
41
|
-
export declare const connectViaWebSocket: ({ node, url,
|
|
40
|
+
export declare const connectViaWebSocket: ({ node, url, }: {
|
|
42
41
|
node: MeshNode;
|
|
43
42
|
url: string;
|
|
44
|
-
reconnect?: Schedule.Schedule<unknown> | false;
|
|
45
43
|
}) => Effect.Effect<void, never, Scope.Scope | HttpClient.HttpClient>;
|
|
46
|
-
export declare const makeWebSocketEdge: (socket
|
|
44
|
+
export declare const makeWebSocketEdge: ({ socket, socketType, }: {
|
|
45
|
+
socket: Socket.Socket;
|
|
46
|
+
socketType: SocketType;
|
|
47
|
+
}) => Effect.Effect<{
|
|
47
48
|
webChannel: WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>;
|
|
48
49
|
from: string;
|
|
49
50
|
}, never, Scope.Scope | HttpClient.HttpClient>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-edge.d.ts","sourceRoot":"","sources":["../src/websocket-edge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAEL,MAAM,
|
|
1
|
+
{"version":3,"file":"websocket-edge.d.ts","sourceRoot":"","sources":["../src/websocket-edge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAEL,MAAM,EAMN,MAAM,EACN,KAAK,EACL,MAAM,EAEN,UAAU,EACX,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;;;;AAEzC,qBAAa,UAAW,SAAQ,eAE9B;CAAG;;;;;AAEL,qBAAa,aAAc,SAAQ,kBAGjC;CAAG;;AAEL,qBAAa,aAAc,SAAQ,kBAAuC;CAAG;AAE7E,eAAO,MAAM,cAAc;;;;;;;;;;;;;;UAAgC,CAAA;AAE3D,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,GAAI,gBAGjC;IACD,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,UAAU,CAcuB,CAAA;AAQzF,eAAO,MAAM,iBAAiB,GAAI,yBAG/B;IACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAA;IACrB,UAAU,EAAE,UAAU,CAAA;CACvB,KAAG,MAAM,CAAC,MAAM,CACf;IACE,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACrG,IAAI,EAAE,MAAM,CAAA;CACb,EACD,KAAK,EACL,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,UAAU,CA6FlC,CAAA"}
|
package/dist/websocket-edge.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Deferred, Effect, Either, Exit, Queue, Schedule, Schema, Scope, Stream, WebChannel,
|
|
1
|
+
import { Deferred, Effect, Either, Exit, Layer, Queue, Schedule, Schema, Scope, Socket, Stream, WebChannel, } from '@livestore/utils/effect';
|
|
2
2
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
3
3
|
export class WSEdgeInit extends Schema.TaggedStruct('WSEdgeInit', {
|
|
4
4
|
from: Schema.String,
|
|
@@ -12,20 +12,38 @@ export class WSEdgePayload extends Schema.TaggedStruct('WSEdgePayload', {
|
|
|
12
12
|
export class WSEdgeMessage extends Schema.Union(WSEdgeInit, WSEdgePayload) {
|
|
13
13
|
}
|
|
14
14
|
export const MessageMsgPack = Schema.MsgPack(WSEdgeMessage);
|
|
15
|
-
export const connectViaWebSocket = ({ node, url,
|
|
15
|
+
export const connectViaWebSocket = ({ node, url, }) => Effect.gen(function* () {
|
|
16
16
|
const disconnected = yield* Deferred.make();
|
|
17
|
-
const socket = yield*
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const socket = yield* Socket.makeWebSocket(url, { openTimeout: 50 });
|
|
18
|
+
const edgeChannel = yield* makeWebSocketEdge({
|
|
19
|
+
socket,
|
|
20
|
+
socketType: { _tag: 'leaf', from: node.nodeName },
|
|
21
|
+
});
|
|
20
22
|
yield* node.addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true });
|
|
21
23
|
yield* disconnected;
|
|
22
|
-
}).pipe(Effect.scoped, Effect.forever, Effect.
|
|
23
|
-
|
|
24
|
+
}).pipe(Effect.scoped, Effect.forever, Effect.provide(binaryWebSocketConstructorLayer));
|
|
25
|
+
const binaryWebSocketConstructorLayer = Layer.succeed(Socket.WebSocketConstructor, (url, protocols) => {
|
|
26
|
+
const socket = new globalThis.WebSocket(url, protocols);
|
|
24
27
|
socket.binaryType = 'arraybuffer';
|
|
28
|
+
return socket;
|
|
29
|
+
});
|
|
30
|
+
export const makeWebSocketEdge = ({ socket, socketType, }) => Effect.scopeWithCloseable((scope) => Effect.gen(function* () {
|
|
25
31
|
const fromDeferred = yield* Deferred.make();
|
|
26
32
|
const listenQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
27
33
|
const schema = WebChannel.mapSchema(WebmeshSchema.Packet);
|
|
28
|
-
|
|
34
|
+
const isConnectedLatch = yield* Effect.makeLatch(true);
|
|
35
|
+
const closedDeferred = yield* Deferred.make().pipe(Effect.acquireRelease(Deferred.done(Exit.void)));
|
|
36
|
+
yield* Stream.never.pipe(Stream.pipeThroughChannel(Socket.toChannel(socket)), Stream.catchTag('SocketError', Effect.fn(function* (error) {
|
|
37
|
+
if (error.reason === 'Close') {
|
|
38
|
+
console.log('socket closed', error);
|
|
39
|
+
yield* isConnectedLatch.close;
|
|
40
|
+
yield* Deferred.succeed(closedDeferred, undefined);
|
|
41
|
+
return yield* Effect.interrupt;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return yield* Effect.fail(error);
|
|
45
|
+
}
|
|
46
|
+
})), Stream.retry(Schedule.exponential(100).pipe(Schedule.whileInput((_) => _.reason === 'OpenTimeout'))), Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg))), Stream.flatten(), Stream.tap((msg) => Effect.gen(function* () {
|
|
29
47
|
if (msg._tag === 'WSEdgeInit') {
|
|
30
48
|
yield* Deferred.succeed(fromDeferred, msg.from);
|
|
31
49
|
}
|
|
@@ -33,27 +51,22 @@ export const makeWebSocketEdge = (socket, socketType) => Effect.scopeWithCloseab
|
|
|
33
51
|
const decodedPayload = yield* Schema.decode(schema.listen)(msg.payload);
|
|
34
52
|
yield* Queue.offer(listenQueue, decodedPayload);
|
|
35
53
|
}
|
|
36
|
-
})), Stream.runDrain, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
37
|
-
const
|
|
54
|
+
})), Stream.runDrain, Effect.interruptible, Effect.withSpan('makeWebSocketEdge:listen'), Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
55
|
+
const sendToSocket = yield* socket.writer;
|
|
56
|
+
const initHandshake = (from) => sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgeInit', from }));
|
|
38
57
|
if (socketType._tag === 'leaf') {
|
|
39
|
-
initHandshake(socketType.from);
|
|
58
|
+
yield* initHandshake(socketType.from);
|
|
40
59
|
}
|
|
41
60
|
const deferredResult = yield* fromDeferred;
|
|
42
61
|
const from = socketType._tag === 'leaf' ? socketType.from : deferredResult;
|
|
43
62
|
if (socketType._tag === 'relay') {
|
|
44
|
-
initHandshake(from);
|
|
63
|
+
yield* initHandshake(from);
|
|
45
64
|
}
|
|
46
|
-
const isConnectedLatch = yield* Effect.makeLatch(true);
|
|
47
|
-
const closedDeferred = yield* Deferred.make().pipe(Effect.acquireRelease(Deferred.done(Exit.void)));
|
|
48
|
-
yield* Effect.eventListener(socket, 'close', () => Effect.gen(function* () {
|
|
49
|
-
yield* isConnectedLatch.close;
|
|
50
|
-
yield* Deferred.succeed(closedDeferred, undefined);
|
|
51
|
-
}), { once: true });
|
|
52
65
|
const send = (message) => Effect.gen(function* () {
|
|
53
66
|
yield* isConnectedLatch.await;
|
|
54
67
|
const payload = yield* Schema.encode(schema.send)(message);
|
|
55
|
-
|
|
56
|
-
});
|
|
68
|
+
yield* sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgePayload', payload, from }));
|
|
69
|
+
}).pipe(Effect.orDie);
|
|
57
70
|
const listen = Stream.fromQueue(listenQueue).pipe(Stream.map(Either.right), WebChannel.listenToDebugPing('websocket-edge'));
|
|
58
71
|
const webChannel = {
|
|
59
72
|
[WebChannel.WebChannelSymbol]: WebChannel.WebChannelSymbol,
|
|
@@ -65,5 +78,5 @@ export const makeWebSocketEdge = (socket, socketType) => Effect.scopeWithCloseab
|
|
|
65
78
|
shutdown: Scope.close(scope, Exit.void),
|
|
66
79
|
};
|
|
67
80
|
return { webChannel, from };
|
|
68
|
-
}).pipe(Effect.withSpanScoped('makeWebSocketEdge')));
|
|
81
|
+
}).pipe(Effect.withSpanScoped('makeWebSocketEdge'), Effect.orDie));
|
|
69
82
|
//# sourceMappingURL=websocket-edge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-edge.js","sourceRoot":"","sources":["../src/websocket-edge.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,KAAK,EACL,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"websocket-edge.js","sourceRoot":"","sources":["../src/websocket-edge.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-2da03812fc739d068b0e57f612c11fe4c4b28b0c",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -15,12 +15,10 @@
|
|
|
15
15
|
},
|
|
16
16
|
"types": "./dist/mod.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"
|
|
19
|
-
"@livestore/
|
|
20
|
-
"@livestore/utils": "0.0.0-snapshot-76bdaead452769e22fce7f5ec10482474416e04d"
|
|
18
|
+
"@livestore/common": "0.0.0-snapshot-2da03812fc739d068b0e57f612c11fe4c4b28b0c",
|
|
19
|
+
"@livestore/utils": "0.0.0-snapshot-2da03812fc739d068b0e57f612c11fe4c4b28b0c"
|
|
21
20
|
},
|
|
22
21
|
"devDependencies": {
|
|
23
|
-
"@types/ws": "^8.18.0",
|
|
24
22
|
"vitest": "^3.0.8"
|
|
25
23
|
},
|
|
26
24
|
"publishConfig": {
|
package/src/websocket-edge.ts
CHANGED
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
Effect,
|
|
5
5
|
Either,
|
|
6
6
|
Exit,
|
|
7
|
+
Layer,
|
|
7
8
|
Queue,
|
|
8
9
|
Schedule,
|
|
9
10
|
Schema,
|
|
10
11
|
Scope,
|
|
12
|
+
Socket,
|
|
11
13
|
Stream,
|
|
12
14
|
WebChannel,
|
|
13
|
-
WebSocket,
|
|
14
15
|
} from '@livestore/utils/effect'
|
|
15
|
-
import type * as NodeWebSocket from 'ws'
|
|
16
16
|
|
|
17
17
|
import * as WebmeshSchema from './mesh-schema.js'
|
|
18
18
|
import type { MeshNode } from './node.js'
|
|
@@ -42,30 +42,38 @@ export type SocketType =
|
|
|
42
42
|
export const connectViaWebSocket = ({
|
|
43
43
|
node,
|
|
44
44
|
url,
|
|
45
|
-
reconnect = Schedule.exponential(100),
|
|
46
45
|
}: {
|
|
47
46
|
node: MeshNode
|
|
48
47
|
url: string
|
|
49
|
-
reconnect?: Schedule.Schedule<unknown> | false
|
|
50
48
|
}): Effect.Effect<void, never, Scope.Scope | HttpClient.HttpClient> =>
|
|
51
49
|
Effect.gen(function* () {
|
|
52
50
|
const disconnected = yield* Deferred.make<void>()
|
|
53
51
|
|
|
54
|
-
const socket = yield*
|
|
52
|
+
const socket = yield* Socket.makeWebSocket(url, { openTimeout: 50 })
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const edgeChannel = yield* makeWebSocketEdge({
|
|
55
|
+
socket,
|
|
56
|
+
socketType: { _tag: 'leaf', from: node.nodeName },
|
|
57
|
+
})
|
|
59
58
|
|
|
60
59
|
yield* node.addEdge({ target: 'ws', edgeChannel: edgeChannel.webChannel, replaceIfExists: true })
|
|
61
60
|
|
|
62
61
|
yield* disconnected
|
|
63
|
-
}).pipe(Effect.scoped, Effect.forever, Effect.
|
|
62
|
+
}).pipe(Effect.scoped, Effect.forever, Effect.provide(binaryWebSocketConstructorLayer))
|
|
63
|
+
|
|
64
|
+
const binaryWebSocketConstructorLayer = Layer.succeed(Socket.WebSocketConstructor, (url, protocols) => {
|
|
65
|
+
const socket = new globalThis.WebSocket(url, protocols)
|
|
66
|
+
socket.binaryType = 'arraybuffer'
|
|
67
|
+
return socket
|
|
68
|
+
})
|
|
64
69
|
|
|
65
|
-
export const makeWebSocketEdge = (
|
|
66
|
-
socket
|
|
67
|
-
socketType
|
|
68
|
-
|
|
70
|
+
export const makeWebSocketEdge = ({
|
|
71
|
+
socket,
|
|
72
|
+
socketType,
|
|
73
|
+
}: {
|
|
74
|
+
socket: Socket.Socket
|
|
75
|
+
socketType: SocketType
|
|
76
|
+
}): Effect.Effect<
|
|
69
77
|
{
|
|
70
78
|
webChannel: WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
|
|
71
79
|
from: string
|
|
@@ -75,8 +83,6 @@ export const makeWebSocketEdge = (
|
|
|
75
83
|
> =>
|
|
76
84
|
Effect.scopeWithCloseable((scope) =>
|
|
77
85
|
Effect.gen(function* () {
|
|
78
|
-
socket.binaryType = 'arraybuffer'
|
|
79
|
-
|
|
80
86
|
const fromDeferred = yield* Deferred.make<string>()
|
|
81
87
|
|
|
82
88
|
const listenQueue = yield* Queue.unbounded<typeof WebmeshSchema.Packet.Type>().pipe(
|
|
@@ -85,8 +91,29 @@ export const makeWebSocketEdge = (
|
|
|
85
91
|
|
|
86
92
|
const schema = WebChannel.mapSchema(WebmeshSchema.Packet)
|
|
87
93
|
|
|
88
|
-
yield*
|
|
89
|
-
|
|
94
|
+
const isConnectedLatch = yield* Effect.makeLatch(true)
|
|
95
|
+
|
|
96
|
+
const closedDeferred = yield* Deferred.make<void>().pipe(Effect.acquireRelease(Deferred.done(Exit.void)))
|
|
97
|
+
|
|
98
|
+
yield* Stream.never.pipe(
|
|
99
|
+
Stream.pipeThroughChannel(Socket.toChannel(socket)),
|
|
100
|
+
Stream.catchTag(
|
|
101
|
+
'SocketError',
|
|
102
|
+
Effect.fn(function* (error) {
|
|
103
|
+
if (error.reason === 'Close') {
|
|
104
|
+
console.log('socket closed', error)
|
|
105
|
+
yield* isConnectedLatch.close
|
|
106
|
+
yield* Deferred.succeed(closedDeferred, undefined)
|
|
107
|
+
return yield* Effect.interrupt
|
|
108
|
+
} else {
|
|
109
|
+
return yield* Effect.fail(error)
|
|
110
|
+
}
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
Stream.retry(
|
|
114
|
+
Schedule.exponential(100).pipe(Schedule.whileInput((_: Socket.SocketError) => _.reason === 'OpenTimeout')),
|
|
115
|
+
),
|
|
116
|
+
Stream.map((msg) => Schema.decodeUnknownEither(MessageMsgPack)(new Uint8Array(msg))),
|
|
90
117
|
Stream.flatten(),
|
|
91
118
|
Stream.tap((msg) =>
|
|
92
119
|
Effect.gen(function* () {
|
|
@@ -100,45 +127,33 @@ export const makeWebSocketEdge = (
|
|
|
100
127
|
),
|
|
101
128
|
Stream.runDrain,
|
|
102
129
|
Effect.interruptible,
|
|
130
|
+
Effect.withSpan('makeWebSocketEdge:listen'),
|
|
103
131
|
Effect.tapCauseLogPretty,
|
|
104
132
|
Effect.forkScoped,
|
|
105
133
|
)
|
|
106
134
|
|
|
135
|
+
const sendToSocket = yield* socket.writer
|
|
136
|
+
|
|
107
137
|
const initHandshake = (from: string) =>
|
|
108
|
-
|
|
138
|
+
sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgeInit', from }))
|
|
109
139
|
|
|
110
140
|
if (socketType._tag === 'leaf') {
|
|
111
|
-
initHandshake(socketType.from)
|
|
141
|
+
yield* initHandshake(socketType.from)
|
|
112
142
|
}
|
|
113
143
|
|
|
114
144
|
const deferredResult = yield* fromDeferred
|
|
115
145
|
const from = socketType._tag === 'leaf' ? socketType.from : deferredResult
|
|
116
146
|
|
|
117
147
|
if (socketType._tag === 'relay') {
|
|
118
|
-
initHandshake(from)
|
|
148
|
+
yield* initHandshake(from)
|
|
119
149
|
}
|
|
120
150
|
|
|
121
|
-
const isConnectedLatch = yield* Effect.makeLatch(true)
|
|
122
|
-
|
|
123
|
-
const closedDeferred = yield* Deferred.make<void>().pipe(Effect.acquireRelease(Deferred.done(Exit.void)))
|
|
124
|
-
|
|
125
|
-
yield* Effect.eventListener<any>(
|
|
126
|
-
socket,
|
|
127
|
-
'close',
|
|
128
|
-
() =>
|
|
129
|
-
Effect.gen(function* () {
|
|
130
|
-
yield* isConnectedLatch.close
|
|
131
|
-
yield* Deferred.succeed(closedDeferred, undefined)
|
|
132
|
-
}),
|
|
133
|
-
{ once: true },
|
|
134
|
-
)
|
|
135
|
-
|
|
136
151
|
const send = (message: typeof WebmeshSchema.Packet.Type) =>
|
|
137
152
|
Effect.gen(function* () {
|
|
138
153
|
yield* isConnectedLatch.await
|
|
139
154
|
const payload = yield* Schema.encode(schema.send)(message)
|
|
140
|
-
|
|
141
|
-
})
|
|
155
|
+
yield* sendToSocket(Schema.encodeSync(MessageMsgPack)({ _tag: 'WSEdgePayload', payload, from }))
|
|
156
|
+
}).pipe(Effect.orDie)
|
|
142
157
|
|
|
143
158
|
const listen = Stream.fromQueue(listenQueue).pipe(
|
|
144
159
|
Stream.map(Either.right),
|
|
@@ -156,5 +171,5 @@ export const makeWebSocketEdge = (
|
|
|
156
171
|
} satisfies WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>
|
|
157
172
|
|
|
158
173
|
return { webChannel, from }
|
|
159
|
-
}).pipe(Effect.withSpanScoped('makeWebSocketEdge')),
|
|
174
|
+
}).pipe(Effect.withSpanScoped('makeWebSocketEdge'), Effect.orDie),
|
|
160
175
|
)
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { HttpClient, 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 | HttpClient.HttpClient>;
|
|
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":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAAE,MAAM,EAAY,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,SAAS,MAAM,IAAI,CAAA;AAK/B,eAAO,MAAM,mBAAmB,GAAI,oBAEjC;IACD,aAAa,EAAE,MAAM,CAAA;CACtB,KAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,UAAU,CA4CnF,CAAA"}
|
package/dist/websocket-server.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { UnexpectedError } from '@livestore/common';
|
|
2
|
-
import { Effect, FiberSet } from '@livestore/utils/effect';
|
|
3
|
-
import * as WebSocket from 'ws';
|
|
4
|
-
import { makeMeshNode } from './node.js';
|
|
5
|
-
import { makeWebSocketEdge } from './websocket-edge.js';
|
|
6
|
-
export const makeWebSocketServer = ({ relayNodeName, }) => Effect.gen(function* () {
|
|
7
|
-
const server = new WebSocket.WebSocketServer({ noServer: true });
|
|
8
|
-
yield* Effect.addFinalizer(() => Effect.async((cb) => {
|
|
9
|
-
server.close((cause) => {
|
|
10
|
-
if (cause) {
|
|
11
|
-
cb(Effect.fail(UnexpectedError.make({ cause })));
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
server.removeAllListeners();
|
|
15
|
-
server.clients.forEach((client) => client.terminate());
|
|
16
|
-
cb(Effect.succeed(undefined));
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
}).pipe(Effect.orDie));
|
|
20
|
-
const node = yield* makeMeshNode(relayNodeName);
|
|
21
|
-
const runtime = yield* Effect.runtime();
|
|
22
|
-
const fiberSet = yield* FiberSet.make();
|
|
23
|
-
// TODO handle node disconnects (i.e. remove respective connection)
|
|
24
|
-
server.on('connection', (socket) => {
|
|
25
|
-
Effect.gen(function* () {
|
|
26
|
-
const { webChannel, from } = yield* makeWebSocketEdge(socket, { _tag: 'relay' });
|
|
27
|
-
yield* node.addEdge({ target: from, edgeChannel: webChannel, replaceIfExists: true });
|
|
28
|
-
yield* Effect.log(`WS Relay ${relayNodeName}: added edge from '${from}'`);
|
|
29
|
-
socket.addEventListener('close', () => Effect.gen(function* () {
|
|
30
|
-
yield* node.removeEdge(from);
|
|
31
|
-
yield* Effect.log(`WS Relay ${relayNodeName}: removed edge from '${from}'`);
|
|
32
|
-
}).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runFork));
|
|
33
|
-
yield* Effect.never;
|
|
34
|
-
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.provide(runtime), FiberSet.run(fiberSet), Effect.runFork);
|
|
35
|
-
});
|
|
36
|
-
return server;
|
|
37
|
-
});
|
|
38
|
-
//# sourceMappingURL=websocket-server.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"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"}
|
package/src/websocket-server.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { UnexpectedError } from '@livestore/common'
|
|
2
|
-
import type { HttpClient, Scope } from '@livestore/utils/effect'
|
|
3
|
-
import { Effect, FiberSet } from '@livestore/utils/effect'
|
|
4
|
-
import * as WebSocket from 'ws'
|
|
5
|
-
|
|
6
|
-
import { makeMeshNode } from './node.js'
|
|
7
|
-
import { makeWebSocketEdge } from './websocket-edge.js'
|
|
8
|
-
|
|
9
|
-
export const makeWebSocketServer = ({
|
|
10
|
-
relayNodeName,
|
|
11
|
-
}: {
|
|
12
|
-
relayNodeName: string
|
|
13
|
-
}): Effect.Effect<WebSocket.WebSocketServer, never, Scope.Scope | HttpClient.HttpClient> =>
|
|
14
|
-
Effect.gen(function* () {
|
|
15
|
-
const server = new WebSocket.WebSocketServer({ noServer: true })
|
|
16
|
-
|
|
17
|
-
yield* Effect.addFinalizer(() =>
|
|
18
|
-
Effect.async<void, UnexpectedError>((cb) => {
|
|
19
|
-
server.close((cause) => {
|
|
20
|
-
if (cause) {
|
|
21
|
-
cb(Effect.fail(UnexpectedError.make({ cause })))
|
|
22
|
-
} else {
|
|
23
|
-
server.removeAllListeners()
|
|
24
|
-
server.clients.forEach((client) => client.terminate())
|
|
25
|
-
cb(Effect.succeed(undefined))
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
}).pipe(Effect.orDie),
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
const node = yield* makeMeshNode(relayNodeName)
|
|
32
|
-
|
|
33
|
-
const runtime = yield* Effect.runtime<HttpClient.HttpClient>()
|
|
34
|
-
|
|
35
|
-
const fiberSet = yield* FiberSet.make()
|
|
36
|
-
|
|
37
|
-
// TODO handle node disconnects (i.e. remove respective connection)
|
|
38
|
-
server.on('connection', (socket) => {
|
|
39
|
-
Effect.gen(function* () {
|
|
40
|
-
const { webChannel, from } = yield* makeWebSocketEdge(socket, { _tag: 'relay' })
|
|
41
|
-
|
|
42
|
-
yield* node.addEdge({ target: from, edgeChannel: webChannel, replaceIfExists: true })
|
|
43
|
-
yield* Effect.log(`WS Relay ${relayNodeName}: added edge from '${from}'`)
|
|
44
|
-
|
|
45
|
-
socket.addEventListener('close', () =>
|
|
46
|
-
Effect.gen(function* () {
|
|
47
|
-
yield* node.removeEdge(from)
|
|
48
|
-
yield* Effect.log(`WS Relay ${relayNodeName}: removed edge from '${from}'`)
|
|
49
|
-
}).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runFork),
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
yield* Effect.never
|
|
53
|
-
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.provide(runtime), FiberSet.run(fiberSet), Effect.runFork)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return server
|
|
57
|
-
})
|