@automerge/automerge-repo-network-websocket 1.2.1 → 2.0.0-alpha.1
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/BrowserWebSocketClientAdapter.d.ts +2 -0
- package/dist/BrowserWebSocketClientAdapter.d.ts.map +1 -1
- package/dist/BrowserWebSocketClientAdapter.js +35 -11
- package/dist/NodeWSServerAdapter.d.ts +2 -0
- package/dist/NodeWSServerAdapter.d.ts.map +1 -1
- package/dist/NodeWSServerAdapter.js +19 -10
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/messages.d.ts +1 -7
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +0 -1
- package/package.json +3 -3
- package/src/BrowserWebSocketClientAdapter.ts +39 -11
- package/src/NodeWSServerAdapter.ts +22 -8
- package/src/index.ts +2 -2
- package/src/messages.ts +1 -11
- package/test/Websocket.test.ts +3 -7
|
@@ -8,6 +8,8 @@ export declare class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapt
|
|
|
8
8
|
#private;
|
|
9
9
|
readonly url: string;
|
|
10
10
|
readonly retryInterval: number;
|
|
11
|
+
isReady(): boolean;
|
|
12
|
+
whenReady(): Promise<void>;
|
|
11
13
|
remotePeerId?: PeerId;
|
|
12
14
|
constructor(url: string, retryInterval?: number);
|
|
13
15
|
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,YAAY,EAEb,MAAM,gCAAgC,CAAA;AACvC,OAAO,SAAS,MAAM,eAAe,CAAA;AAIrC,OAAO,EACL,iBAAiB,EAKlB,MAAM,eAAe,CAAA;AAKtB,uBAAe,uBAAwB,SAAQ,cAAc;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,6BAA8B,SAAQ,uBAAuB;;
|
|
1
|
+
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,YAAY,EAEb,MAAM,gCAAgC,CAAA;AACvC,OAAO,SAAS,MAAM,eAAe,CAAA;AAIrC,OAAO,EACL,iBAAiB,EAKlB,MAAM,eAAe,CAAA;AAKtB,uBAAe,uBAAwB,SAAQ,cAAc;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,6BAA8B,SAAQ,uBAAuB;;aA4BtD,GAAG,EAAE,MAAM;aACX,aAAa;IAtB/B,OAAO;IAIP,SAAS;IAcT,YAAY,CAAC,EAAE,MAAM,CAAA;gBAGH,GAAG,EAAE,MAAM,EACX,aAAa,SAAO;IAMtC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY;IAqCnD,MAAM,aAKL;IAGD,OAAO,aAWN;IAED,SAAS,UAAW,SAAS,CAAC,YAAY,UAEzC;IAED,mFAAmF;IACnF,OAAO,UAED,KAAK,GACL,SAAS,CAAC,UAAU,UAezB;IAED,IAAI;IAUJ,UAAU;IAiBV,IAAI,CAAC,OAAO,EAAE,iBAAiB;IAe/B,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY;IAU9D,cAAc,CAAC,YAAY,EAAE,UAAU;CAiBxC"}
|
|
@@ -11,7 +11,23 @@ class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
|
11
11
|
export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
12
12
|
url;
|
|
13
13
|
retryInterval;
|
|
14
|
-
#
|
|
14
|
+
#ready = false;
|
|
15
|
+
#readyResolver;
|
|
16
|
+
#readyPromise = new Promise(resolve => {
|
|
17
|
+
this.#readyResolver = resolve;
|
|
18
|
+
});
|
|
19
|
+
isReady() {
|
|
20
|
+
return this.#ready;
|
|
21
|
+
}
|
|
22
|
+
whenReady() {
|
|
23
|
+
return this.#readyPromise;
|
|
24
|
+
}
|
|
25
|
+
#forceReady() {
|
|
26
|
+
if (!this.#ready) {
|
|
27
|
+
this.#ready = true;
|
|
28
|
+
this.#readyResolver?.();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
15
31
|
#retryIntervalId;
|
|
16
32
|
#log = debug("automerge-repo:websocket:browser");
|
|
17
33
|
remotePeerId; // this adapter only connects to one remote client at a time
|
|
@@ -51,7 +67,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
51
67
|
// Mark this adapter as ready if we haven't received an ack in 1 second.
|
|
52
68
|
// We might hear back from the other end at some point but we shouldn't
|
|
53
69
|
// hold up marking things as unavailable for any longer
|
|
54
|
-
setTimeout(() => this.#
|
|
70
|
+
setTimeout(() => this.#forceReady(), 1000);
|
|
55
71
|
this.join();
|
|
56
72
|
}
|
|
57
73
|
onOpen = () => {
|
|
@@ -93,12 +109,6 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
93
109
|
}
|
|
94
110
|
this.#log("Connection failed, retrying...");
|
|
95
111
|
};
|
|
96
|
-
#ready() {
|
|
97
|
-
if (this.#isReady)
|
|
98
|
-
return;
|
|
99
|
-
this.#isReady = true;
|
|
100
|
-
this.emit("ready", { network: this });
|
|
101
|
-
}
|
|
102
112
|
join() {
|
|
103
113
|
assert(this.peerId);
|
|
104
114
|
assert(this.socket);
|
|
@@ -112,13 +122,27 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
112
122
|
disconnect() {
|
|
113
123
|
assert(this.peerId);
|
|
114
124
|
assert(this.socket);
|
|
115
|
-
|
|
125
|
+
const socket = this.socket;
|
|
126
|
+
if (socket) {
|
|
127
|
+
socket.removeEventListener("open", this.onOpen);
|
|
128
|
+
socket.removeEventListener("close", this.onClose);
|
|
129
|
+
socket.removeEventListener("message", this.onMessage);
|
|
130
|
+
socket.removeEventListener("error", this.onError);
|
|
131
|
+
socket.close();
|
|
132
|
+
}
|
|
133
|
+
clearInterval(this.#retryIntervalId);
|
|
134
|
+
if (this.remotePeerId)
|
|
135
|
+
this.emit("peer-disconnected", { peerId: this.remotePeerId });
|
|
136
|
+
this.socket = undefined;
|
|
116
137
|
}
|
|
117
138
|
send(message) {
|
|
118
139
|
if ("data" in message && message.data?.byteLength === 0)
|
|
119
140
|
throw new Error("Tried to send a zero-length message");
|
|
120
141
|
assert(this.peerId);
|
|
121
|
-
|
|
142
|
+
if (!this.socket) {
|
|
143
|
+
this.#log("Tried to send on a disconnected socket.");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
122
146
|
if (this.socket.readyState !== WebSocket.OPEN)
|
|
123
147
|
throw new Error(`Websocket not ready (${this.socket.readyState})`);
|
|
124
148
|
const encoded = cbor.encode(message);
|
|
@@ -126,7 +150,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
126
150
|
}
|
|
127
151
|
peerCandidate(remotePeerId, peerMetadata) {
|
|
128
152
|
assert(this.socket);
|
|
129
|
-
this.#
|
|
153
|
+
this.#forceReady();
|
|
130
154
|
this.remotePeerId = remotePeerId;
|
|
131
155
|
this.emit("peer-candidate", {
|
|
132
156
|
peerId: remotePeerId,
|
|
@@ -9,6 +9,8 @@ export declare class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
9
9
|
sockets: {
|
|
10
10
|
[peerId: PeerId]: WebSocket;
|
|
11
11
|
};
|
|
12
|
+
isReady(): boolean;
|
|
13
|
+
whenReady(): Promise<void>;
|
|
12
14
|
constructor(server: WebSocketServer, keepAliveInterval?: number);
|
|
13
15
|
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
14
16
|
disconnect(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeWSServerAdapter.d.ts","sourceRoot":"","sources":["../src/NodeWSServerAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,OAAO,EAEL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAEL,iBAAiB,
|
|
1
|
+
{"version":3,"file":"NodeWSServerAdapter.d.ts","sourceRoot":"","sources":["../src/NodeWSServerAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,OAAO,EAEL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAEL,iBAAiB,EAElB,MAAM,eAAe,CAAA;AAOtB,qBAAa,mBAAoB,SAAQ,cAAc;;IAyBnD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,iBAAiB;IAzB3B,OAAO,EAAE;QAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAK;IAQ7C,OAAO;IAIP,SAAS;gBAYC,MAAM,EAAE,eAAe,EACvB,iBAAiB,SAAO;IAKlC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY;IAyCnD,UAAU;IAQV,IAAI,CAAC,OAAO,EAAE,iBAAiB;IAqB/B,cAAc,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS;CAoE3D"}
|
|
@@ -2,7 +2,7 @@ import WebSocket from "isomorphic-ws";
|
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
const log = debug("WebsocketServer");
|
|
4
4
|
import { cbor as cborHelpers, NetworkAdapter, } from "@automerge/automerge-repo/slim";
|
|
5
|
-
import { isJoinMessage,
|
|
5
|
+
import { isJoinMessage, } from "./messages.js";
|
|
6
6
|
import { ProtocolV1 } from "./protocolVersion.js";
|
|
7
7
|
import { assert } from "./assert.js";
|
|
8
8
|
import { toArrayBuffer } from "./toArrayBuffer.js";
|
|
@@ -11,6 +11,23 @@ export class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
11
11
|
server;
|
|
12
12
|
keepAliveInterval;
|
|
13
13
|
sockets = {};
|
|
14
|
+
#ready = false;
|
|
15
|
+
#readyResolver;
|
|
16
|
+
#readyPromise = new Promise(resolve => {
|
|
17
|
+
this.#readyResolver = resolve;
|
|
18
|
+
});
|
|
19
|
+
isReady() {
|
|
20
|
+
return this.#ready;
|
|
21
|
+
}
|
|
22
|
+
whenReady() {
|
|
23
|
+
return this.#readyPromise;
|
|
24
|
+
}
|
|
25
|
+
#forceReady() {
|
|
26
|
+
if (!this.#ready) {
|
|
27
|
+
this.#ready = true;
|
|
28
|
+
this.#readyResolver?.();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
14
31
|
constructor(server, keepAliveInterval = 5000) {
|
|
15
32
|
super();
|
|
16
33
|
this.server = server;
|
|
@@ -32,7 +49,7 @@ export class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
32
49
|
// Start out "alive", and every time we get a pong, reset that state.
|
|
33
50
|
socket.isAlive = true;
|
|
34
51
|
socket.on("pong", () => (socket.isAlive = true));
|
|
35
|
-
this
|
|
52
|
+
this.#forceReady();
|
|
36
53
|
});
|
|
37
54
|
const keepAliveId = setInterval(() => {
|
|
38
55
|
// Terminate connections to lost clients
|
|
@@ -112,14 +129,6 @@ export class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
112
129
|
});
|
|
113
130
|
}
|
|
114
131
|
}
|
|
115
|
-
else if (isLeaveMessage(message)) {
|
|
116
|
-
const { senderId } = message;
|
|
117
|
-
const socket = this.sockets[senderId];
|
|
118
|
-
/* c8 ignore next */
|
|
119
|
-
if (!socket)
|
|
120
|
-
return;
|
|
121
|
-
this.#terminate(socket);
|
|
122
|
-
}
|
|
123
132
|
else {
|
|
124
133
|
this.emit("message", message);
|
|
125
134
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* */
|
|
15
15
|
export { BrowserWebSocketClientAdapter } from "./BrowserWebSocketClientAdapter.js";
|
|
16
16
|
export { NodeWSServerAdapter } from "./NodeWSServerAdapter.js";
|
|
17
|
-
export type { FromClientMessage, FromServerMessage, JoinMessage,
|
|
18
|
-
export type { ProtocolVersion
|
|
17
|
+
export type { FromClientMessage, FromServerMessage, JoinMessage, ErrorMessage, PeerMessage, } from "./messages.js";
|
|
18
|
+
export type { ProtocolVersion } from "./protocolVersion.js";
|
|
19
|
+
export { ProtocolV1 } from "./protocolVersion.js";
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;KAaK;AACL,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAA;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;KAaK;AACL,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAA;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/messages.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { Message, PeerId, PeerMetadata } from "@automerge/automerge-repo/slim";
|
|
2
2
|
import type { ProtocolVersion } from "./protocolVersion.js";
|
|
3
|
-
/** The sender is disconnecting */
|
|
4
|
-
export type LeaveMessage = {
|
|
5
|
-
type: "leave";
|
|
6
|
-
senderId: PeerId;
|
|
7
|
-
};
|
|
8
3
|
/** Sent by the client to the server to tell the server the clients PeerID */
|
|
9
4
|
export type JoinMessage = {
|
|
10
5
|
type: "join";
|
|
@@ -38,11 +33,10 @@ export type ErrorMessage = {
|
|
|
38
33
|
targetId: PeerId;
|
|
39
34
|
};
|
|
40
35
|
/** A message from the client to the server */
|
|
41
|
-
export type FromClientMessage = JoinMessage |
|
|
36
|
+
export type FromClientMessage = JoinMessage | Message;
|
|
42
37
|
/** A message from the server to the client */
|
|
43
38
|
export type FromServerMessage = PeerMessage | ErrorMessage | Message;
|
|
44
39
|
export declare const isJoinMessage: (message: FromClientMessage) => message is JoinMessage;
|
|
45
|
-
export declare const isLeaveMessage: (message: FromClientMessage) => message is LeaveMessage;
|
|
46
40
|
export declare const isPeerMessage: (message: FromServerMessage) => message is PeerMessage;
|
|
47
41
|
export declare const isErrorMessage: (message: FromServerMessage) => message is ErrorMessage;
|
|
48
42
|
//# sourceMappingURL=messages.d.ts.map
|
package/dist/messages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,YAAY,EACb,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,YAAY,EACb,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAEhB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAA;IAE1B,+CAA+C;IAC/C,yBAAyB,EAAE,eAAe,EAAE,CAAA;CAC7C,CAAA;AAED,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAEhB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAA;IAE1B,mEAAmE;IACnE,uBAAuB,EAAE,eAAe,CAAA;IACxC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,OAAO,CAAA;AAErD,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAA;AAIpE,eAAO,MAAM,aAAa,YACf,iBAAiB,KACzB,OAAO,IAAI,WAAsC,CAAA;AAEpD,eAAO,MAAM,aAAa,YACf,iBAAiB,KACzB,OAAO,IAAI,WAAsC,CAAA;AAEpD,eAAO,MAAM,cAAc,YAChB,iBAAiB,KACzB,OAAO,IAAI,YAAwC,CAAA"}
|
package/dist/messages.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// TYPE GUARDS
|
|
2
2
|
export const isJoinMessage = (message) => message.type === "join";
|
|
3
|
-
export const isLeaveMessage = (message) => message.type === "leave";
|
|
4
3
|
export const isPeerMessage = (message) => message.type === "peer";
|
|
5
4
|
export const isErrorMessage = (message) => message.type === "error";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo-network-websocket",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
4
|
"description": "isomorphic node/browser Websocket network adapter for Automerge Repo",
|
|
5
5
|
"repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo-network-websocket",
|
|
6
6
|
"author": "Peter van Hardenberg <pvh@pvh.ca>",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"test": "vitest"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@automerge/automerge-repo": "
|
|
16
|
+
"@automerge/automerge-repo": "2.0.0-alpha.1",
|
|
17
17
|
"cbor-x": "^1.3.0",
|
|
18
18
|
"debug": "^4.3.4",
|
|
19
19
|
"eventemitter3": "^5.0.1",
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "86421aba21c8037b916ee93f962df1c121fef52b"
|
|
35
35
|
}
|
|
@@ -24,7 +24,27 @@ abstract class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
27
|
-
#
|
|
27
|
+
#ready = false
|
|
28
|
+
#readyResolver?: () => void
|
|
29
|
+
#readyPromise: Promise<void> = new Promise<void>(resolve => {
|
|
30
|
+
this.#readyResolver = resolve
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
isReady() {
|
|
34
|
+
return this.#ready
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
whenReady() {
|
|
38
|
+
return this.#readyPromise
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#forceReady() {
|
|
42
|
+
if (!this.#ready) {
|
|
43
|
+
this.#ready = true
|
|
44
|
+
this.#readyResolver?.()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
#retryIntervalId?: TimeoutId
|
|
29
49
|
#log = debug("automerge-repo:websocket:browser")
|
|
30
50
|
|
|
@@ -71,7 +91,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
71
91
|
// Mark this adapter as ready if we haven't received an ack in 1 second.
|
|
72
92
|
// We might hear back from the other end at some point but we shouldn't
|
|
73
93
|
// hold up marking things as unavailable for any longer
|
|
74
|
-
setTimeout(() => this.#
|
|
94
|
+
setTimeout(() => this.#forceReady(), 1000)
|
|
75
95
|
this.join()
|
|
76
96
|
}
|
|
77
97
|
|
|
@@ -121,12 +141,6 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
121
141
|
this.#log("Connection failed, retrying...")
|
|
122
142
|
}
|
|
123
143
|
|
|
124
|
-
#ready() {
|
|
125
|
-
if (this.#isReady) return
|
|
126
|
-
this.#isReady = true
|
|
127
|
-
this.emit("ready", { network: this })
|
|
128
|
-
}
|
|
129
|
-
|
|
130
144
|
join() {
|
|
131
145
|
assert(this.peerId)
|
|
132
146
|
assert(this.socket)
|
|
@@ -140,14 +154,28 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
140
154
|
disconnect() {
|
|
141
155
|
assert(this.peerId)
|
|
142
156
|
assert(this.socket)
|
|
143
|
-
|
|
157
|
+
const socket = this.socket
|
|
158
|
+
if (socket) {
|
|
159
|
+
socket.removeEventListener("open", this.onOpen)
|
|
160
|
+
socket.removeEventListener("close", this.onClose)
|
|
161
|
+
socket.removeEventListener("message", this.onMessage)
|
|
162
|
+
socket.removeEventListener("error", this.onError)
|
|
163
|
+
socket.close()
|
|
164
|
+
}
|
|
165
|
+
clearInterval(this.#retryIntervalId)
|
|
166
|
+
if (this.remotePeerId)
|
|
167
|
+
this.emit("peer-disconnected", { peerId: this.remotePeerId })
|
|
168
|
+
this.socket = undefined
|
|
144
169
|
}
|
|
145
170
|
|
|
146
171
|
send(message: FromClientMessage) {
|
|
147
172
|
if ("data" in message && message.data?.byteLength === 0)
|
|
148
173
|
throw new Error("Tried to send a zero-length message")
|
|
149
174
|
assert(this.peerId)
|
|
150
|
-
|
|
175
|
+
if (!this.socket) {
|
|
176
|
+
this.#log("Tried to send on a disconnected socket.")
|
|
177
|
+
return
|
|
178
|
+
}
|
|
151
179
|
if (this.socket.readyState !== WebSocket.OPEN)
|
|
152
180
|
throw new Error(`Websocket not ready (${this.socket.readyState})`)
|
|
153
181
|
|
|
@@ -157,7 +185,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
157
185
|
|
|
158
186
|
peerCandidate(remotePeerId: PeerId, peerMetadata: PeerMetadata) {
|
|
159
187
|
assert(this.socket)
|
|
160
|
-
this.#
|
|
188
|
+
this.#forceReady()
|
|
161
189
|
this.remotePeerId = remotePeerId
|
|
162
190
|
this.emit("peer-candidate", {
|
|
163
191
|
peerId: remotePeerId,
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
FromClientMessage,
|
|
15
15
|
FromServerMessage,
|
|
16
16
|
isJoinMessage,
|
|
17
|
-
isLeaveMessage,
|
|
18
17
|
} from "./messages.js"
|
|
19
18
|
import { ProtocolV1, ProtocolVersion } from "./protocolVersion.js"
|
|
20
19
|
import { assert } from "./assert.js"
|
|
@@ -25,6 +24,27 @@ const { encode, decode } = cborHelpers
|
|
|
25
24
|
export class NodeWSServerAdapter extends NetworkAdapter {
|
|
26
25
|
sockets: { [peerId: PeerId]: WebSocket } = {}
|
|
27
26
|
|
|
27
|
+
#ready = false
|
|
28
|
+
#readyResolver?: () => void
|
|
29
|
+
#readyPromise: Promise<void> = new Promise<void>(resolve => {
|
|
30
|
+
this.#readyResolver = resolve
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
isReady() {
|
|
34
|
+
return this.#ready
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
whenReady() {
|
|
38
|
+
return this.#readyPromise
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#forceReady() {
|
|
42
|
+
if (!this.#ready) {
|
|
43
|
+
this.#ready = true
|
|
44
|
+
this.#readyResolver?.()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
28
48
|
constructor(
|
|
29
49
|
private server: WebSocketServer,
|
|
30
50
|
private keepAliveInterval = 5000
|
|
@@ -55,7 +75,7 @@ export class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
55
75
|
socket.isAlive = true
|
|
56
76
|
socket.on("pong", () => (socket.isAlive = true))
|
|
57
77
|
|
|
58
|
-
this
|
|
78
|
+
this.#forceReady()
|
|
59
79
|
})
|
|
60
80
|
|
|
61
81
|
const keepAliveId = setInterval(() => {
|
|
@@ -147,12 +167,6 @@ export class NodeWSServerAdapter extends NetworkAdapter {
|
|
|
147
167
|
targetId: senderId,
|
|
148
168
|
})
|
|
149
169
|
}
|
|
150
|
-
} else if (isLeaveMessage(message)) {
|
|
151
|
-
const { senderId } = message
|
|
152
|
-
const socket = this.sockets[senderId]
|
|
153
|
-
/* c8 ignore next */
|
|
154
|
-
if (!socket) return
|
|
155
|
-
this.#terminate(socket as WebSocketWithIsAlive)
|
|
156
170
|
} else {
|
|
157
171
|
this.emit("message", message)
|
|
158
172
|
}
|
package/src/index.ts
CHANGED
|
@@ -18,8 +18,8 @@ export type {
|
|
|
18
18
|
FromClientMessage,
|
|
19
19
|
FromServerMessage,
|
|
20
20
|
JoinMessage,
|
|
21
|
-
LeaveMessage,
|
|
22
21
|
ErrorMessage,
|
|
23
22
|
PeerMessage,
|
|
24
23
|
} from "./messages.js"
|
|
25
|
-
export type { ProtocolVersion
|
|
24
|
+
export type { ProtocolVersion } from "./protocolVersion.js"
|
|
25
|
+
export { ProtocolV1 } from "./protocolVersion.js"
|
package/src/messages.ts
CHANGED
|
@@ -5,12 +5,6 @@ import type {
|
|
|
5
5
|
} from "@automerge/automerge-repo/slim"
|
|
6
6
|
import type { ProtocolVersion } from "./protocolVersion.js"
|
|
7
7
|
|
|
8
|
-
/** The sender is disconnecting */
|
|
9
|
-
export type LeaveMessage = {
|
|
10
|
-
type: "leave"
|
|
11
|
-
senderId: PeerId
|
|
12
|
-
}
|
|
13
|
-
|
|
14
8
|
/** Sent by the client to the server to tell the server the clients PeerID */
|
|
15
9
|
export type JoinMessage = {
|
|
16
10
|
type: "join"
|
|
@@ -51,7 +45,7 @@ export type ErrorMessage = {
|
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
/** A message from the client to the server */
|
|
54
|
-
export type FromClientMessage = JoinMessage |
|
|
48
|
+
export type FromClientMessage = JoinMessage | Message
|
|
55
49
|
|
|
56
50
|
/** A message from the server to the client */
|
|
57
51
|
export type FromServerMessage = PeerMessage | ErrorMessage | Message
|
|
@@ -62,10 +56,6 @@ export const isJoinMessage = (
|
|
|
62
56
|
message: FromClientMessage
|
|
63
57
|
): message is JoinMessage => message.type === "join"
|
|
64
58
|
|
|
65
|
-
export const isLeaveMessage = (
|
|
66
|
-
message: FromClientMessage
|
|
67
|
-
): message is LeaveMessage => message.type === "leave"
|
|
68
|
-
|
|
69
59
|
export const isPeerMessage = (
|
|
70
60
|
message: FromServerMessage
|
|
71
61
|
): message is PeerMessage => message.type === "peer"
|
package/test/Websocket.test.ts
CHANGED
|
@@ -66,7 +66,7 @@ describe("Websocket adapters", () => {
|
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
68
|
|
|
69
|
-
it("should
|
|
69
|
+
it("should connect and emit peers", async () => {
|
|
70
70
|
const {
|
|
71
71
|
serverAdapter,
|
|
72
72
|
clients: [browserAdapter],
|
|
@@ -82,13 +82,9 @@ describe("Websocket adapters", () => {
|
|
|
82
82
|
peerId: serverPeerId,
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
await eventPromise(serverRepo.networkSubsystem, "peer")
|
|
86
|
-
|
|
87
|
-
browserAdapter.disconnect()
|
|
88
|
-
|
|
89
85
|
await Promise.all([
|
|
90
|
-
eventPromise(
|
|
91
|
-
eventPromise(
|
|
86
|
+
eventPromise(browserRepo.networkSubsystem, "peer"),
|
|
87
|
+
eventPromise(serverRepo.networkSubsystem, "peer"),
|
|
92
88
|
])
|
|
93
89
|
})
|
|
94
90
|
|