cojson-transport-ws 0.9.23 → 0.10.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +22 -0
- package/dist/WebSocketPeerWithReconnection.js +78 -0
- package/dist/WebSocketPeerWithReconnection.js.map +1 -0
- package/dist/createWebSocketPeer.js +165 -0
- package/dist/createWebSocketPeer.js.map +1 -0
- package/dist/index.js +2 -164
- package/dist/index.js.map +1 -1
- package/dist/tests/BatchedOutgoingMessages.test.js.map +1 -1
- package/dist/tests/WebSocketPeerWithReconnection.test.js +105 -0
- package/dist/tests/WebSocketPeerWithReconnection.test.js.map +1 -0
- package/dist/tests/createWebSocketPeer.test.js +1 -1
- package/dist/tests/createWebSocketPeer.test.js.map +1 -1
- package/dist/tests/integration.test.js +3 -3
- package/dist/tests/integration.test.js.map +1 -1
- package/dist/tests/syncServer.js +3 -2
- package/dist/tests/syncServer.js.map +1 -1
- package/dist/tests/utils.js +25 -0
- package/dist/tests/utils.js.map +1 -0
- package/package.json +2 -2
- package/src/WebSocketPeerWithReconnection.ts +108 -0
- package/src/createWebSocketPeer.ts +239 -0
- package/src/index.ts +2 -239
- package/src/tests/BatchedOutgoingMessages.test.ts +3 -3
- package/src/tests/WebSocketPeerWithReconnection.test.ts +143 -0
- package/src/tests/createWebSocketPeer.test.ts +1 -1
- package/src/tests/integration.test.ts +3 -3
- package/src/tests/syncServer.ts +3 -2
- package/src/tests/utils.ts +27 -0
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# cojson-transport-nodejs-ws
|
|
2
2
|
|
|
3
|
+
## 0.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [5a63cba]
|
|
8
|
+
- cojson@0.10.1
|
|
9
|
+
|
|
10
|
+
## 0.10.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 498954f: Introducing the new auth system!
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [b426342]
|
|
19
|
+
- Updated dependencies [498954f]
|
|
20
|
+
- Updated dependencies [8217981]
|
|
21
|
+
- Updated dependencies [ac3d9fa]
|
|
22
|
+
- Updated dependencies [610543c]
|
|
23
|
+
- cojson@0.10.0
|
|
24
|
+
|
|
3
25
|
## 0.9.23
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { logger } from "cojson";
|
|
2
|
+
import { createWebSocketPeer } from "./createWebSocketPeer.js";
|
|
3
|
+
export class WebSocketPeerWithReconnection {
|
|
4
|
+
constructor(opts) {
|
|
5
|
+
this.state = "disabled";
|
|
6
|
+
this.currentPeer = undefined;
|
|
7
|
+
this.unsubscribeNetworkChange = undefined;
|
|
8
|
+
this.reconnectionAttempts = 0;
|
|
9
|
+
this.startConnection = async () => {
|
|
10
|
+
if (this.state !== "enabled")
|
|
11
|
+
return;
|
|
12
|
+
if (this.currentPeer) {
|
|
13
|
+
this.removePeer(this.currentPeer);
|
|
14
|
+
this.reconnectionAttempts++;
|
|
15
|
+
const timeout = this.reconnectionTimeout * this.reconnectionAttempts;
|
|
16
|
+
logger.debug("Websocket disconnected, trying to reconnect in " + timeout + "ms");
|
|
17
|
+
await this.waitForOnline(timeout);
|
|
18
|
+
}
|
|
19
|
+
if (this.state !== "enabled")
|
|
20
|
+
return;
|
|
21
|
+
this.currentPeer = createWebSocketPeer({
|
|
22
|
+
websocket: new WebSocket(this.peer),
|
|
23
|
+
id: this.peer,
|
|
24
|
+
role: "server",
|
|
25
|
+
onClose: this.startConnection,
|
|
26
|
+
onSuccess: () => {
|
|
27
|
+
logger.debug("Websocket connection successful");
|
|
28
|
+
this.reconnectionAttempts = 0;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
this.addPeer(this.currentPeer);
|
|
32
|
+
};
|
|
33
|
+
this.enable = () => {
|
|
34
|
+
if (this.state === "enabled")
|
|
35
|
+
return;
|
|
36
|
+
this.state = "enabled";
|
|
37
|
+
this.startConnection();
|
|
38
|
+
};
|
|
39
|
+
this.disable = () => {
|
|
40
|
+
if (this.state === "disabled")
|
|
41
|
+
return;
|
|
42
|
+
this.state = "disabled";
|
|
43
|
+
this.reconnectionAttempts = 0;
|
|
44
|
+
this.unsubscribeNetworkChange?.();
|
|
45
|
+
this.unsubscribeNetworkChange = undefined;
|
|
46
|
+
if (this.currentPeer) {
|
|
47
|
+
this.removePeer(this.currentPeer);
|
|
48
|
+
this.currentPeer = undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
this.peer = opts.peer;
|
|
52
|
+
this.reconnectionTimeout = opts.reconnectionTimeout || 500;
|
|
53
|
+
this.addPeer = opts.addPeer;
|
|
54
|
+
this.removePeer = opts.removePeer;
|
|
55
|
+
}
|
|
56
|
+
// Basic implementation for environments that don't support network change events (e.g. Node.js)
|
|
57
|
+
// Needs to be extended to handle platform specific APIs
|
|
58
|
+
onNetworkChange(callback) {
|
|
59
|
+
callback;
|
|
60
|
+
return () => { };
|
|
61
|
+
}
|
|
62
|
+
waitForOnline(timeout) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const unsubscribeNetworkChange = this.onNetworkChange((connected) => {
|
|
65
|
+
if (connected) {
|
|
66
|
+
handleTimeoutOrOnline();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
function handleTimeoutOrOnline() {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
unsubscribeNetworkChange();
|
|
72
|
+
resolve();
|
|
73
|
+
}
|
|
74
|
+
const timer = setTimeout(handleTimeoutOrOnline, timeout);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=WebSocketPeerWithReconnection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSocketPeerWithReconnection.js","sourceRoot":"","sources":["../src/WebSocketPeerWithReconnection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,OAAO,6BAA6B;IAMxC,YAAY,IAKX;QAOD,UAAK,GAA2B,UAAU,CAAC;QAC3C,gBAAW,GAAqB,SAAS,CAAC;QAC1C,6BAAwB,GAA6B,SAAS,CAAC;QA2B/D,yBAAoB,GAAG,CAAC,CAAC;QAEzB,oBAAe,GAAG,KAAK,IAAI,EAAE;YAC3B,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO;YAErC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAElC,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAE5B,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,CAAC;gBAErE,MAAM,CAAC,KAAK,CACV,iDAAiD,GAAG,OAAO,GAAG,IAAI,CACnE,CAAC;gBAEF,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACpC,CAAC;YAED,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO;YAErC,IAAI,CAAC,WAAW,GAAG,mBAAmB,CAAC;gBACrC,SAAS,EAAE,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;gBACnC,EAAE,EAAE,IAAI,CAAC,IAAI;gBACb,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,CAAC,eAAe;gBAC7B,SAAS,EAAE,GAAG,EAAE;oBACd,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBAEhD,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;gBAChC,CAAC;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC,CAAC;QAEF,WAAM,GAAG,GAAG,EAAE;YACZ,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO;YAErC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACvB,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC;QAEF,YAAO,GAAG,GAAG,EAAE;YACb,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU;gBAAE,OAAO;YAEtC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;YAExB,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,wBAAwB,GAAG,SAAS,CAAC;YAE1C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAClC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC;QA3FA,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,IAAI,GAAG,CAAC;QAC3D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IAMD,gGAAgG;IAChG,wDAAwD;IACxD,eAAe,CAAC,QAAsC;QACpD,QAAQ,CAAC;QACT,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,MAAM,wBAAwB,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,EAAE;gBAClE,IAAI,SAAS,EAAE,CAAC;oBACd,qBAAqB,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,SAAS,qBAAqB;gBAC5B,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,wBAAwB,EAAE,CAAC;gBAC3B,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;CA2DF"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { cojsonInternals, logger, } from "cojson";
|
|
2
|
+
import { BatchedOutgoingMessages } from "./BatchedOutgoingMessages.js";
|
|
3
|
+
import { deserializeMessages, getErrorMessage } from "./serialization.js";
|
|
4
|
+
export const BUFFER_LIMIT = 100000;
|
|
5
|
+
export const BUFFER_LIMIT_POLLING_INTERVAL = 10;
|
|
6
|
+
function createPingTimeoutListener(enabled, callback) {
|
|
7
|
+
if (!enabled) {
|
|
8
|
+
return {
|
|
9
|
+
reset() { },
|
|
10
|
+
clear() { },
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
let pingTimeout = null;
|
|
14
|
+
return {
|
|
15
|
+
reset() {
|
|
16
|
+
pingTimeout && clearTimeout(pingTimeout);
|
|
17
|
+
pingTimeout = setTimeout(() => {
|
|
18
|
+
callback();
|
|
19
|
+
}, 10000);
|
|
20
|
+
},
|
|
21
|
+
clear() {
|
|
22
|
+
pingTimeout && clearTimeout(pingTimeout);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function waitForWebSocketOpen(websocket) {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
if (websocket.readyState === 1) {
|
|
29
|
+
resolve();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
websocket.addEventListener("open", resolve, { once: true });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function createOutgoingMessagesManager(websocket, batchingByDefault) {
|
|
37
|
+
let closed = false;
|
|
38
|
+
const outgoingMessages = new BatchedOutgoingMessages((messages) => {
|
|
39
|
+
if (websocket.readyState === 1) {
|
|
40
|
+
websocket.send(messages);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
let batchingEnabled = batchingByDefault;
|
|
44
|
+
async function sendMessage(msg) {
|
|
45
|
+
if (closed) {
|
|
46
|
+
return Promise.reject(new Error("WebSocket closed"));
|
|
47
|
+
}
|
|
48
|
+
if (websocket.readyState !== 1) {
|
|
49
|
+
await waitForWebSocketOpen(websocket);
|
|
50
|
+
}
|
|
51
|
+
while (websocket.bufferedAmount > BUFFER_LIMIT &&
|
|
52
|
+
websocket.readyState === 1) {
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, BUFFER_LIMIT_POLLING_INTERVAL));
|
|
54
|
+
}
|
|
55
|
+
if (websocket.readyState !== 1) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!batchingEnabled) {
|
|
59
|
+
websocket.send(JSON.stringify(msg));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
outgoingMessages.push(msg);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
sendMessage,
|
|
67
|
+
setBatchingEnabled(enabled) {
|
|
68
|
+
batchingEnabled = enabled;
|
|
69
|
+
},
|
|
70
|
+
close() {
|
|
71
|
+
closed = true;
|
|
72
|
+
outgoingMessages.close();
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function createClosedEventEmitter(callback = () => { }) {
|
|
77
|
+
let disconnected = false;
|
|
78
|
+
return () => {
|
|
79
|
+
if (disconnected)
|
|
80
|
+
return;
|
|
81
|
+
disconnected = true;
|
|
82
|
+
callback();
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export function createWebSocketPeer({ id, websocket, role, expectPings = true, batchingByDefault = true, deletePeerStateOnClose = false, onSuccess, onClose, }) {
|
|
86
|
+
const incoming = new cojsonInternals.Channel();
|
|
87
|
+
const emitClosedEvent = createClosedEventEmitter(onClose);
|
|
88
|
+
function handleClose() {
|
|
89
|
+
incoming
|
|
90
|
+
.push("Disconnected")
|
|
91
|
+
.catch((e) => logger.error("Error while pushing disconnect msg", e));
|
|
92
|
+
emitClosedEvent();
|
|
93
|
+
}
|
|
94
|
+
websocket.addEventListener("close", handleClose);
|
|
95
|
+
websocket.addEventListener("error", (err) => {
|
|
96
|
+
if (err.message) {
|
|
97
|
+
logger.warn(err.message);
|
|
98
|
+
}
|
|
99
|
+
handleClose();
|
|
100
|
+
});
|
|
101
|
+
const pingTimeout = createPingTimeoutListener(expectPings, () => {
|
|
102
|
+
incoming
|
|
103
|
+
.push("PingTimeout")
|
|
104
|
+
.catch((e) => logger.error("Error while pushing ping timeout", e));
|
|
105
|
+
emitClosedEvent();
|
|
106
|
+
});
|
|
107
|
+
const outgoingMessages = createOutgoingMessagesManager(websocket, batchingByDefault);
|
|
108
|
+
let isFirstMessage = true;
|
|
109
|
+
function handleIncomingMsg(event) {
|
|
110
|
+
if (event.data === "") {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const result = deserializeMessages(event.data);
|
|
114
|
+
if (!result.ok) {
|
|
115
|
+
logger.warn("Error while deserializing messages: " + getErrorMessage(result.error));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (isFirstMessage) {
|
|
119
|
+
// The only way to know that the connection has been correctly established with our sync server
|
|
120
|
+
// is to track that we got a message from the server.
|
|
121
|
+
onSuccess?.();
|
|
122
|
+
isFirstMessage = false;
|
|
123
|
+
}
|
|
124
|
+
const { messages } = result;
|
|
125
|
+
if (messages.length > 1) {
|
|
126
|
+
// If more than one message is received, the other peer supports batching
|
|
127
|
+
outgoingMessages.setBatchingEnabled(true);
|
|
128
|
+
}
|
|
129
|
+
pingTimeout.reset();
|
|
130
|
+
for (const msg of messages) {
|
|
131
|
+
if (msg && "action" in msg) {
|
|
132
|
+
incoming
|
|
133
|
+
.push(msg)
|
|
134
|
+
.catch((e) => logger.error("Error while pushing incoming msg", e));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
websocket.addEventListener("message", handleIncomingMsg);
|
|
139
|
+
return {
|
|
140
|
+
id,
|
|
141
|
+
incoming,
|
|
142
|
+
outgoing: {
|
|
143
|
+
push: outgoingMessages.sendMessage,
|
|
144
|
+
close() {
|
|
145
|
+
outgoingMessages.close();
|
|
146
|
+
websocket.removeEventListener("message", handleIncomingMsg);
|
|
147
|
+
websocket.removeEventListener("close", handleClose);
|
|
148
|
+
pingTimeout.clear();
|
|
149
|
+
emitClosedEvent();
|
|
150
|
+
if (websocket.readyState === 0) {
|
|
151
|
+
websocket.addEventListener("open", function handleClose() {
|
|
152
|
+
websocket.close();
|
|
153
|
+
}, { once: true });
|
|
154
|
+
}
|
|
155
|
+
else if (websocket.readyState == 1) {
|
|
156
|
+
websocket.close();
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
role,
|
|
161
|
+
crashOnClose: false,
|
|
162
|
+
deletePeerStateOnClose,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=createWebSocketPeer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWebSocketPeer.js","sourceRoot":"","sources":["../src/createWebSocketPeer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,165 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { deserializeMessages, getErrorMessage } from "./serialization.js";
|
|
4
|
-
export const BUFFER_LIMIT = 100000;
|
|
5
|
-
export const BUFFER_LIMIT_POLLING_INTERVAL = 10;
|
|
6
|
-
function createPingTimeoutListener(enabled, callback) {
|
|
7
|
-
if (!enabled) {
|
|
8
|
-
return {
|
|
9
|
-
reset() { },
|
|
10
|
-
clear() { },
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
let pingTimeout = null;
|
|
14
|
-
return {
|
|
15
|
-
reset() {
|
|
16
|
-
pingTimeout && clearTimeout(pingTimeout);
|
|
17
|
-
pingTimeout = setTimeout(() => {
|
|
18
|
-
callback();
|
|
19
|
-
}, 10000);
|
|
20
|
-
},
|
|
21
|
-
clear() {
|
|
22
|
-
pingTimeout && clearTimeout(pingTimeout);
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function waitForWebSocketOpen(websocket) {
|
|
27
|
-
return new Promise((resolve) => {
|
|
28
|
-
if (websocket.readyState === 1) {
|
|
29
|
-
resolve();
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
websocket.addEventListener("open", resolve, { once: true });
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
function createOutgoingMessagesManager(websocket, batchingByDefault) {
|
|
37
|
-
let closed = false;
|
|
38
|
-
const outgoingMessages = new BatchedOutgoingMessages((messages) => {
|
|
39
|
-
if (websocket.readyState === 1) {
|
|
40
|
-
websocket.send(messages);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
let batchingEnabled = batchingByDefault;
|
|
44
|
-
async function sendMessage(msg) {
|
|
45
|
-
if (closed) {
|
|
46
|
-
return Promise.reject(new Error("WebSocket closed"));
|
|
47
|
-
}
|
|
48
|
-
if (websocket.readyState !== 1) {
|
|
49
|
-
await waitForWebSocketOpen(websocket);
|
|
50
|
-
}
|
|
51
|
-
while (websocket.bufferedAmount > BUFFER_LIMIT &&
|
|
52
|
-
websocket.readyState === 1) {
|
|
53
|
-
await new Promise((resolve) => setTimeout(resolve, BUFFER_LIMIT_POLLING_INTERVAL));
|
|
54
|
-
}
|
|
55
|
-
if (websocket.readyState !== 1) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (!batchingEnabled) {
|
|
59
|
-
websocket.send(JSON.stringify(msg));
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
outgoingMessages.push(msg);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
sendMessage,
|
|
67
|
-
setBatchingEnabled(enabled) {
|
|
68
|
-
batchingEnabled = enabled;
|
|
69
|
-
},
|
|
70
|
-
close() {
|
|
71
|
-
closed = true;
|
|
72
|
-
outgoingMessages.close();
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function createClosedEventEmitter(callback = () => { }) {
|
|
77
|
-
let disconnected = false;
|
|
78
|
-
return () => {
|
|
79
|
-
if (disconnected)
|
|
80
|
-
return;
|
|
81
|
-
disconnected = true;
|
|
82
|
-
callback();
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
export function createWebSocketPeer({ id, websocket, role, expectPings = true, batchingByDefault = true, deletePeerStateOnClose = false, onSuccess, onClose, }) {
|
|
86
|
-
const incoming = new cojsonInternals.Channel();
|
|
87
|
-
const emitClosedEvent = createClosedEventEmitter(onClose);
|
|
88
|
-
function handleClose() {
|
|
89
|
-
incoming
|
|
90
|
-
.push("Disconnected")
|
|
91
|
-
.catch((e) => logger.error("Error while pushing disconnect msg", e));
|
|
92
|
-
emitClosedEvent();
|
|
93
|
-
}
|
|
94
|
-
websocket.addEventListener("close", handleClose);
|
|
95
|
-
websocket.addEventListener("error", (err) => {
|
|
96
|
-
logger.warn(err.message);
|
|
97
|
-
if (err.message.includes("ECONNREFUSED")) {
|
|
98
|
-
websocket.close();
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
const pingTimeout = createPingTimeoutListener(expectPings, () => {
|
|
102
|
-
incoming
|
|
103
|
-
.push("PingTimeout")
|
|
104
|
-
.catch((e) => logger.error("Error while pushing ping timeout", e));
|
|
105
|
-
emitClosedEvent();
|
|
106
|
-
});
|
|
107
|
-
const outgoingMessages = createOutgoingMessagesManager(websocket, batchingByDefault);
|
|
108
|
-
let isFirstMessage = true;
|
|
109
|
-
function handleIncomingMsg(event) {
|
|
110
|
-
if (event.data === "") {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
const result = deserializeMessages(event.data);
|
|
114
|
-
if (!result.ok) {
|
|
115
|
-
logger.warn("Error while deserializing messages: " + getErrorMessage(result.error));
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
if (isFirstMessage) {
|
|
119
|
-
// The only way to know that the connection has been correctly established with our sync server
|
|
120
|
-
// is to track that we got a message from the server.
|
|
121
|
-
onSuccess?.();
|
|
122
|
-
isFirstMessage = false;
|
|
123
|
-
}
|
|
124
|
-
const { messages } = result;
|
|
125
|
-
if (messages.length > 1) {
|
|
126
|
-
// If more than one message is received, the other peer supports batching
|
|
127
|
-
outgoingMessages.setBatchingEnabled(true);
|
|
128
|
-
}
|
|
129
|
-
pingTimeout.reset();
|
|
130
|
-
for (const msg of messages) {
|
|
131
|
-
if (msg && "action" in msg) {
|
|
132
|
-
incoming
|
|
133
|
-
.push(msg)
|
|
134
|
-
.catch((e) => logger.error("Error while pushing incoming msg", e));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
websocket.addEventListener("message", handleIncomingMsg);
|
|
139
|
-
return {
|
|
140
|
-
id,
|
|
141
|
-
incoming,
|
|
142
|
-
outgoing: {
|
|
143
|
-
push: outgoingMessages.sendMessage,
|
|
144
|
-
close() {
|
|
145
|
-
outgoingMessages.close();
|
|
146
|
-
websocket.removeEventListener("message", handleIncomingMsg);
|
|
147
|
-
websocket.removeEventListener("close", handleClose);
|
|
148
|
-
pingTimeout.clear();
|
|
149
|
-
emitClosedEvent();
|
|
150
|
-
if (websocket.readyState === 0) {
|
|
151
|
-
websocket.addEventListener("open", function handleClose() {
|
|
152
|
-
websocket.close();
|
|
153
|
-
}, { once: true });
|
|
154
|
-
}
|
|
155
|
-
else if (websocket.readyState == 1) {
|
|
156
|
-
websocket.close();
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
role,
|
|
161
|
-
crashOnClose: false,
|
|
162
|
-
deletePeerStateOnClose,
|
|
163
|
-
};
|
|
164
|
-
}
|
|
1
|
+
export * from "./createWebSocketPeer.js";
|
|
2
|
+
export * from "./WebSocketPeerWithReconnection.js";
|
|
165
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BatchedOutgoingMessages.test.js","sourceRoot":"","sources":["../../src/tests/BatchedOutgoingMessages.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC3E,OAAO,EACL,uBAAuB,EACvB,iCAAiC,GAClC,MAAM,+BAA+B,CAAC;AAEvC,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,SAAS,KAAK;QACZ,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,eAAe,GAAG,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAC9D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;IACvC,CAAC;IAED,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC/D,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,KAAK,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAgB;YAC5B,MAAM,EAAE,OAAO;YACf,EAAE,EAAE,OAAO;YACX,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,EAAE;SACb,CAAC;QACF,MAAM,QAAQ,GAAgB;YAC5B,MAAM,EAAE,OAAO;YACf,EAAE,EAAE,OAAO;YACX,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE/B,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAExC,EAAE,CAAC,YAAY,EAAE,CAAC;QAElB,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAC3D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kFAAkF,EAAE,GAAG,EAAE;QAC5F,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,KAAK,EAAE,CAAC;QAC9C,MAAM,YAAY,GAAgB;YAChC,MAAM,EAAE,OAAO;YACf,EAAE,EAAE,YAAY;YAChB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE;gBACR,kEAAkE;gBAClE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"BatchedOutgoingMessages.test.js","sourceRoot":"","sources":["../../src/tests/BatchedOutgoingMessages.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { WebSocketPeerWithReconnection } from "../WebSocketPeerWithReconnection";
|
|
3
|
+
import { startSyncServer } from "./syncServer";
|
|
4
|
+
import { waitFor } from "./utils";
|
|
5
|
+
describe("WebSocketPeerWithReconnection", () => {
|
|
6
|
+
let server;
|
|
7
|
+
let syncServerUrl;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
const result = await startSyncServer();
|
|
10
|
+
server = result;
|
|
11
|
+
syncServerUrl = result.syncServer;
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
server.close();
|
|
15
|
+
});
|
|
16
|
+
test("should connect successfully to sync server", async () => {
|
|
17
|
+
const addPeer = vi.fn();
|
|
18
|
+
const removePeer = vi.fn();
|
|
19
|
+
const peer = new WebSocketPeerWithReconnection({
|
|
20
|
+
peer: syncServerUrl,
|
|
21
|
+
reconnectionTimeout: 100,
|
|
22
|
+
addPeer,
|
|
23
|
+
removePeer,
|
|
24
|
+
});
|
|
25
|
+
peer.enable();
|
|
26
|
+
// Wait for connection to establish
|
|
27
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
28
|
+
expect(addPeer).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(removePeer).not.toHaveBeenCalled();
|
|
30
|
+
peer.disable();
|
|
31
|
+
});
|
|
32
|
+
test("should attempt reconnection when server disconnects", async () => {
|
|
33
|
+
const addPeer = vi.fn();
|
|
34
|
+
const removePeer = vi.fn();
|
|
35
|
+
const peer = new WebSocketPeerWithReconnection({
|
|
36
|
+
peer: syncServerUrl,
|
|
37
|
+
reconnectionTimeout: 100,
|
|
38
|
+
addPeer,
|
|
39
|
+
removePeer,
|
|
40
|
+
});
|
|
41
|
+
peer.enable();
|
|
42
|
+
// Wait for initial connection
|
|
43
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
44
|
+
addPeer.mockClear();
|
|
45
|
+
// Close server to simulate disconnect
|
|
46
|
+
server.close();
|
|
47
|
+
// Wait for disconnect to be detected
|
|
48
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
49
|
+
expect(removePeer).toHaveBeenCalled();
|
|
50
|
+
expect(peer.reconnectionAttempts).toBeGreaterThan(0);
|
|
51
|
+
// Start server again
|
|
52
|
+
server = await startSyncServer(server.port);
|
|
53
|
+
// Wait for reconnection
|
|
54
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
55
|
+
expect(addPeer).toHaveBeenCalled();
|
|
56
|
+
peer.disable();
|
|
57
|
+
});
|
|
58
|
+
test("should stop reconnection attempts when disabled", async () => {
|
|
59
|
+
const addPeer = vi.fn();
|
|
60
|
+
const removePeer = vi.fn();
|
|
61
|
+
const peer = new WebSocketPeerWithReconnection({
|
|
62
|
+
peer: syncServerUrl,
|
|
63
|
+
reconnectionTimeout: 100,
|
|
64
|
+
addPeer,
|
|
65
|
+
removePeer,
|
|
66
|
+
});
|
|
67
|
+
peer.enable();
|
|
68
|
+
// Wait for initial connection
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
70
|
+
// Close server and disable peer
|
|
71
|
+
server.close();
|
|
72
|
+
peer.disable();
|
|
73
|
+
// Wait to ensure no reconnection attempts
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
75
|
+
expect(addPeer).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(removePeer).toHaveBeenCalledTimes(1);
|
|
77
|
+
expect(peer.reconnectionAttempts).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
test("should reset reconnection attempts when connection is successful", async () => {
|
|
80
|
+
const addPeer = vi.fn();
|
|
81
|
+
const removePeer = vi.fn();
|
|
82
|
+
const peer = new WebSocketPeerWithReconnection({
|
|
83
|
+
peer: syncServerUrl,
|
|
84
|
+
reconnectionTimeout: 10,
|
|
85
|
+
addPeer,
|
|
86
|
+
removePeer,
|
|
87
|
+
});
|
|
88
|
+
peer.enable();
|
|
89
|
+
// Wait for initial connection
|
|
90
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
91
|
+
// Close server to trigger reconnection attempts
|
|
92
|
+
server.close();
|
|
93
|
+
// Wait for some reconnection attempts
|
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
95
|
+
const previousAttempts = peer.reconnectionAttempts;
|
|
96
|
+
expect(previousAttempts).toBeGreaterThan(0);
|
|
97
|
+
// Start server again
|
|
98
|
+
server = await startSyncServer(server.port);
|
|
99
|
+
// Wait for successful reconnection
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
101
|
+
await waitFor(() => expect(peer.reconnectionAttempts).toBe(0));
|
|
102
|
+
peer.disable();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=WebSocketPeerWithReconnection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSocketPeerWithReconnection.test.js","sourceRoot":"","sources":["../../src/tests/WebSocketPeerWithReconnection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test, vi } from "vitest";
|
|
2
2
|
import { MAX_OUTGOING_MESSAGES_CHUNK_BYTES } from "../BatchedOutgoingMessages.js";
|
|
3
|
-
import { BUFFER_LIMIT, BUFFER_LIMIT_POLLING_INTERVAL, createWebSocketPeer, } from "../
|
|
3
|
+
import { BUFFER_LIMIT, BUFFER_LIMIT_POLLING_INTERVAL, createWebSocketPeer, } from "../createWebSocketPeer.js";
|
|
4
4
|
function setup(opts = {}) {
|
|
5
5
|
const listeners = new Map();
|
|
6
6
|
const mockWebSocket = {
|