@automerge/automerge-repo-network-websocket 1.0.9 → 1.0.10
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 +1 -0
- package/dist/BrowserWebSocketClientAdapter.d.ts.map +1 -1
- package/dist/BrowserWebSocketClientAdapter.js +5 -0
- package/dist/NodeWSServerAdapter.js +1 -1
- package/package.json +3 -3
- package/src/BrowserWebSocketClientAdapter.ts +7 -0
- package/src/NodeWSServerAdapter.ts +1 -1
- package/test/Websocket.test.ts +163 -144
- package/test/utilities/CreateWebSocketServer.ts +0 -8
- package/test/utilities/WebSockets.ts +0 -34
|
@@ -8,6 +8,7 @@ declare abstract class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
|
8
8
|
export declare class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
9
9
|
#private;
|
|
10
10
|
timerId?: ReturnType<typeof setTimeout>;
|
|
11
|
+
remotePeerId?: PeerId;
|
|
11
12
|
url: string;
|
|
12
13
|
constructor(url: string);
|
|
13
14
|
connect(peerId: PeerId): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAQ,MAAM,2BAA2B,CAAA;AACxE,OAAO,SAAS,MAAM,eAAe,CAAA;AAIrC,OAAO,EACL,iBAAiB,EAGlB,MAAM,eAAe,CAAA;AAMtB,uBAAe,uBAAwB,SAAQ,cAAc;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,6BAA8B,SAAQ,uBAAuB;;IAGxE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,EAAQ,MAAM,2BAA2B,CAAA;AACxE,OAAO,SAAS,MAAM,eAAe,CAAA;AAIrC,OAAO,EACL,iBAAiB,EAGlB,MAAM,eAAe,CAAA;AAMtB,uBAAe,uBAAwB,SAAQ,cAAc;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,6BAA8B,SAAQ,uBAAuB;;IAGxE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;IACvC,YAAY,CAAC,EAAE,MAAM,CAAA;IAGrB,GAAG,EAAE,MAAM,CAAA;gBAEC,GAAG,EAAE,MAAM;IAKvB,OAAO,CAAC,MAAM,EAAE,MAAM;IAkCtB,MAAM,aAKL;IAGD,OAAO,aAYN;IAED,SAAS,UAAW,sBAAsB,UAEzC;IAED,IAAI;IAWJ,UAAU;IAOV,IAAI,CAAC,OAAO,EAAE,iBAAiB;IAwB/B,kBAAkB,CAAC,MAAM,EAAE,MAAM;IAcjC,cAAc,CAAC,OAAO,EAAE,UAAU;CA6BnC"}
|
|
@@ -11,6 +11,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
11
11
|
// Type trickery required for platform independence,
|
|
12
12
|
// see https://stackoverflow.com/questions/45802988/typescript-use-correct-version-of-settimeout-node-vs-window
|
|
13
13
|
timerId;
|
|
14
|
+
remotePeerId; // this adapter only connects to one remote client at a time
|
|
14
15
|
#startupComplete = false;
|
|
15
16
|
url;
|
|
16
17
|
constructor(url) {
|
|
@@ -54,6 +55,9 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
54
55
|
// When a socket closes, or disconnects, remove it from the array.
|
|
55
56
|
onClose = () => {
|
|
56
57
|
log(`${this.url}: close`);
|
|
58
|
+
if (this.remotePeerId) {
|
|
59
|
+
this.emit("peer-disconnected", { peerId: this.remotePeerId });
|
|
60
|
+
}
|
|
57
61
|
if (!this.timerId) {
|
|
58
62
|
if (this.peerId) {
|
|
59
63
|
this.connect(this.peerId);
|
|
@@ -106,6 +110,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
106
110
|
this.#startupComplete = true;
|
|
107
111
|
this.emit("ready", { network: this });
|
|
108
112
|
}
|
|
113
|
+
this.remotePeerId = peerId;
|
|
109
114
|
this.emit("peer-candidate", { peerId });
|
|
110
115
|
}
|
|
111
116
|
receiveMessage(message) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo-network-websocket",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "isomorphic node/browser Websocket network adapter for Automerge Repo",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@automerge/automerge": "^2.1.0"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"test": "vitest"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@automerge/automerge-repo": "^1.0.
|
|
19
|
+
"@automerge/automerge-repo": "^1.0.10",
|
|
20
20
|
"cbor-x": "^1.3.0",
|
|
21
21
|
"eventemitter3": "^5.0.1",
|
|
22
22
|
"isomorphic-ws": "^5.0.0",
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "a79cfa659547b7f4a12987bbbee0f4f2f7f219f4"
|
|
37
37
|
}
|
|
@@ -21,6 +21,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
21
21
|
// Type trickery required for platform independence,
|
|
22
22
|
// see https://stackoverflow.com/questions/45802988/typescript-use-correct-version-of-settimeout-node-vs-window
|
|
23
23
|
timerId?: ReturnType<typeof setTimeout>
|
|
24
|
+
remotePeerId?: PeerId // this adapter only connects to one remote client at a time
|
|
24
25
|
#startupComplete: boolean = false
|
|
25
26
|
|
|
26
27
|
url: string
|
|
@@ -74,6 +75,11 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
74
75
|
// When a socket closes, or disconnects, remove it from the array.
|
|
75
76
|
onClose = () => {
|
|
76
77
|
log(`${this.url}: close`)
|
|
78
|
+
|
|
79
|
+
if (this.remotePeerId) {
|
|
80
|
+
this.emit("peer-disconnected", { peerId: this.remotePeerId })
|
|
81
|
+
}
|
|
82
|
+
|
|
77
83
|
if (!this.timerId) {
|
|
78
84
|
if (this.peerId) {
|
|
79
85
|
this.connect(this.peerId)
|
|
@@ -137,6 +143,7 @@ export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
|
137
143
|
this.#startupComplete = true
|
|
138
144
|
this.emit("ready", { network: this })
|
|
139
145
|
}
|
|
146
|
+
this.remotePeerId = peerId
|
|
140
147
|
this.emit("peer-candidate", { peerId })
|
|
141
148
|
}
|
|
142
149
|
|
package/test/Websocket.test.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { runAdapterTests } from "../../automerge-repo/src/helpers/tests/network-adapter-tests.js"
|
|
2
|
-
import { BrowserWebSocketClientAdapter } from "../src/BrowserWebSocketClientAdapter.js"
|
|
3
|
-
import { NodeWSServerAdapter } from "../src/NodeWSServerAdapter.js"
|
|
4
|
-
import { startServer } from "./utilities/WebSockets.js"
|
|
5
|
-
import * as CBOR from "cbor-x"
|
|
6
|
-
import WebSocket, { AddressInfo } from "ws"
|
|
7
|
-
import assert from "assert"
|
|
8
1
|
import { PeerId, Repo } from "@automerge/automerge-repo"
|
|
2
|
+
import assert from "assert"
|
|
3
|
+
import * as CBOR from "cbor-x"
|
|
9
4
|
import { once } from "events"
|
|
5
|
+
import http from "http"
|
|
10
6
|
import { describe, it } from "vitest"
|
|
7
|
+
import WebSocket, { AddressInfo } from "ws"
|
|
8
|
+
import { runAdapterTests } from "../../automerge-repo/src/helpers/tests/network-adapter-tests.js"
|
|
9
|
+
import { BrowserWebSocketClientAdapter } from "../src/BrowserWebSocketClientAdapter.js"
|
|
10
|
+
import { NodeWSServerAdapter } from "../src/NodeWSServerAdapter.js"
|
|
11
11
|
|
|
12
|
-
describe("Websocket adapters",
|
|
13
|
-
|
|
12
|
+
describe("Websocket adapters", () => {
|
|
13
|
+
const setup = async (clientCount = 1) => {
|
|
14
|
+
const server = http.createServer()
|
|
15
|
+
const socket = new WebSocket.Server({ server })
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
while (socket === undefined) {
|
|
20
|
-
try {
|
|
21
|
-
;({ socket, server } = await startServer(port))
|
|
22
|
-
} catch (e: any) {
|
|
23
|
-
if (e.code === "EADDRINUSE") {
|
|
24
|
-
port++
|
|
25
|
-
} else {
|
|
26
|
-
throw e
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
17
|
+
await new Promise<void>(resolve => server.listen(0, resolve))
|
|
18
|
+
const { port } = server.address() as AddressInfo
|
|
19
|
+
const serverUrl = `ws://localhost:${port}`
|
|
30
20
|
|
|
31
|
-
const
|
|
21
|
+
const clients = [] as BrowserWebSocketClientAdapter[]
|
|
22
|
+
for (let i = 0; i < clientCount; i++) {
|
|
23
|
+
clients.push(new BrowserWebSocketClientAdapter(serverUrl))
|
|
24
|
+
}
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+
return { socket, server, port, serverUrl, clients }
|
|
27
|
+
}
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
// run adapter acceptance tests
|
|
30
|
+
runAdapterTests(async () => {
|
|
31
|
+
const {
|
|
32
|
+
clients: [aliceAdapter, bobAdapter],
|
|
33
|
+
socket,
|
|
34
|
+
server,
|
|
35
|
+
} = await setup(2)
|
|
36
|
+
const serverAdapter = new NodeWSServerAdapter(socket)
|
|
37
37
|
|
|
38
38
|
const teardown = () => {
|
|
39
39
|
server.close()
|
|
@@ -41,140 +41,159 @@ describe("Websocket adapters", async () => {
|
|
|
41
41
|
|
|
42
42
|
return { adapters: [aliceAdapter, serverAdapter, bobAdapter], teardown }
|
|
43
43
|
})
|
|
44
|
-
})
|
|
45
44
|
|
|
46
|
-
describe("
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
describe("BrowserWebSocketClientAdapter", () => {
|
|
46
|
+
const firstMessage = async (socket: WebSocket.Server<any>) =>
|
|
47
|
+
new Promise((resolve, reject) => {
|
|
48
|
+
socket.once("connection", ws => {
|
|
49
|
+
ws.once("message", (message: any) => resolve(message))
|
|
50
|
+
ws.once("error", (error: any) => reject(error))
|
|
51
|
+
})
|
|
52
|
+
socket.once("error", error => reject(error))
|
|
53
|
+
})
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
it("should advertise the protocol versions it supports in its join message", async () => {
|
|
56
|
+
const {
|
|
57
|
+
socket,
|
|
58
|
+
clients: [browser],
|
|
59
|
+
} = await setup()
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
const helloPromise = firstMessage(socket)
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
supportedProtocolVersions: ["1"],
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
})
|
|
63
|
+
const _repo = new Repo({
|
|
64
|
+
network: [browser],
|
|
65
|
+
peerId: "browser" as PeerId,
|
|
66
|
+
})
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
assert.deepEqual<any>(response, {
|
|
75
|
-
type: "peer",
|
|
76
|
-
senderId: "server",
|
|
77
|
-
targetId: "browser",
|
|
78
|
-
selectedProtocolVersion: "1",
|
|
68
|
+
const encodedMessage = await helloPromise
|
|
69
|
+
const message = CBOR.decode(encodedMessage as Uint8Array)
|
|
70
|
+
assert.deepEqual(message, {
|
|
71
|
+
type: "join",
|
|
72
|
+
senderId: "browser",
|
|
73
|
+
supportedProtocolVersions: ["1"],
|
|
74
|
+
})
|
|
79
75
|
})
|
|
80
|
-
})
|
|
81
76
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
it.skip("should announce disconnections", async () => {
|
|
78
|
+
const {
|
|
79
|
+
server,
|
|
80
|
+
socket,
|
|
81
|
+
clients: [browserAdapter],
|
|
82
|
+
} = await setup()
|
|
83
|
+
|
|
84
|
+
const _browserRepo = new Repo({
|
|
85
|
+
network: [browserAdapter],
|
|
86
|
+
peerId: "browser" as PeerId,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const serverAdapter = new NodeWSServerAdapter(socket)
|
|
90
|
+
const _serverRepo = new Repo({
|
|
91
|
+
network: [serverAdapter],
|
|
92
|
+
peerId: "server" as PeerId,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const disconnectPromise = new Promise<void>(resolve => {
|
|
96
|
+
browserAdapter.on("peer-disconnected", () => resolve())
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
server.close()
|
|
100
|
+
await disconnectPromise
|
|
87
101
|
})
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
102
|
+
|
|
103
|
+
it("should correctly clear event handlers on reconnect", async () => {
|
|
104
|
+
// This reproduces an issue where the BrowserWebSocketClientAdapter.connect
|
|
105
|
+
// call registered event handlers on the websocket but didn't clear them
|
|
106
|
+
// up again on a second call to connect. This combined with the reconnect
|
|
107
|
+
// timer to produce the following sequence of events:
|
|
108
|
+
//
|
|
109
|
+
// - first call to connect creates a socket and registers an "open"
|
|
110
|
+
// handler. The "open" handler will attempt to send a join message
|
|
111
|
+
// - The connection is slow, so the reconnect timer fires before "open",
|
|
112
|
+
// the reconnect timer calls connect again. this.socket is now a new socket
|
|
113
|
+
// - The other end replies to the first socket, "open"
|
|
114
|
+
// - The original "open" handler attempts to send a message, but on the new
|
|
115
|
+
// socket (because it uses `this.socket`), which isn't open yet, so we get an
|
|
116
|
+
// error that the socket is not ready
|
|
117
|
+
const {
|
|
118
|
+
clients: [browser],
|
|
119
|
+
} = await setup()
|
|
120
|
+
|
|
121
|
+
const peerId = "testclient" as PeerId
|
|
122
|
+
browser.connect(peerId)
|
|
123
|
+
|
|
124
|
+
// simulate the reconnect timer firing before the other end has responded
|
|
125
|
+
// (which works here because we haven't yielded to the event loop yet so
|
|
126
|
+
// the server, which is on the same event loop as us, can't respond)
|
|
127
|
+
browser.connect(peerId)
|
|
128
|
+
|
|
129
|
+
// Now yield, so the server responds on the first socket, if the listeners
|
|
130
|
+
// are cleaned up correctly we shouldn't throw
|
|
131
|
+
await pause(1)
|
|
93
132
|
})
|
|
94
133
|
})
|
|
95
134
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
135
|
+
describe("NodeWSServerAdapter", () => {
|
|
136
|
+
const serverResponse = async (clientHello: Object) => {
|
|
137
|
+
const { socket, serverUrl } = await setup(0)
|
|
138
|
+
const server = new NodeWSServerAdapter(socket)
|
|
139
|
+
const _serverRepo = new Repo({
|
|
140
|
+
network: [server],
|
|
141
|
+
peerId: "server" as PeerId,
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
const clientSocket = new WebSocket(serverUrl)
|
|
145
|
+
await once(clientSocket, "open")
|
|
146
|
+
const serverHelloPromise = once(clientSocket, "message")
|
|
147
|
+
|
|
148
|
+
clientSocket.send(CBOR.encode(clientHello))
|
|
149
|
+
|
|
150
|
+
const serverHello = await serverHelloPromise
|
|
151
|
+
const message = CBOR.decode(serverHello[0] as Uint8Array)
|
|
152
|
+
return message
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
it("should send the negotiated protocol version in its hello message", async () => {
|
|
156
|
+
const response = await serverResponse({
|
|
157
|
+
type: "join",
|
|
158
|
+
senderId: "browser",
|
|
159
|
+
supportedProtocolVersions: ["1"],
|
|
160
|
+
})
|
|
161
|
+
assert.deepEqual(response, {
|
|
162
|
+
type: "peer",
|
|
163
|
+
senderId: "server",
|
|
164
|
+
targetId: "browser",
|
|
165
|
+
selectedProtocolVersion: "1",
|
|
166
|
+
})
|
|
106
167
|
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it("should correctly clear event handlers on reconnect", async () => {
|
|
110
|
-
// This reproduces an issue where the BrowserWebSocketClientAdapter.connect
|
|
111
|
-
// call registered event handlers on the websocket but didn't clear them
|
|
112
|
-
// up again on a second call to connect. This combined with the reconnect
|
|
113
|
-
// timer to produce the following sequence of events:
|
|
114
|
-
//
|
|
115
|
-
// * first call to connect creates a socket and registers an "open"
|
|
116
|
-
// handler. The "open" handler will attempt to send a join message
|
|
117
|
-
// * The connection is slow, so the reconnect timer fires before "open",
|
|
118
|
-
// the reconnect timer calls connect again. this.socket is now a new socket
|
|
119
|
-
// * The other end replies to the first socket, "open"
|
|
120
|
-
// * The original "open" handler attempts to send a message, but on the new
|
|
121
|
-
// socket (because it uses this.socket), which isn't open yet, so we get an
|
|
122
|
-
// error that the socket is not ready
|
|
123
|
-
const { socket, server } = await startServer(0)
|
|
124
|
-
let port = (server.address()!! as AddressInfo).port
|
|
125
|
-
const serverUrl = `ws://localhost:${port}`
|
|
126
|
-
const serverAdapter = new NodeWSServerAdapter(socket)
|
|
127
|
-
const browserAdapter = new BrowserWebSocketClientAdapter(serverUrl)
|
|
128
|
-
|
|
129
|
-
const peerId = "testclient" as PeerId
|
|
130
|
-
browserAdapter.connect(peerId)
|
|
131
|
-
// simulate the reconnect timer firing before the other end has responded
|
|
132
|
-
// (which works here because we haven't yielded to the event loop yet so
|
|
133
|
-
// the server, which is on the same event loop as us, can't respond)
|
|
134
|
-
browserAdapter.connect(peerId)
|
|
135
|
-
// Now await, so the server responds on the first socket, if the listeners
|
|
136
|
-
// are cleaned up correctly we shouldn't throw
|
|
137
|
-
await pause(1)
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
168
|
|
|
141
|
-
async
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const serverUrl = `ws://localhost:${port}`
|
|
147
|
-
const adapter = new NodeWSServerAdapter(socket)
|
|
148
|
-
const repo = new Repo({ network: [adapter], peerId: "server" as PeerId })
|
|
149
|
-
|
|
150
|
-
const clientSocket = new WebSocket(serverUrl)
|
|
151
|
-
await once(clientSocket, "open")
|
|
152
|
-
const serverHelloPromise = once(clientSocket, "message")
|
|
153
|
-
|
|
154
|
-
clientSocket.send(CBOR.encode(clientHello))
|
|
155
|
-
|
|
156
|
-
const serverHello = await serverHelloPromise
|
|
157
|
-
const message = CBOR.decode(serverHello[0] as Uint8Array)
|
|
158
|
-
return message
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function firstMessage(
|
|
162
|
-
socket: WebSocket.Server<any>
|
|
163
|
-
): Promise<Object | null> {
|
|
164
|
-
return new Promise((resolve, reject) => {
|
|
165
|
-
socket.once("connection", ws => {
|
|
166
|
-
ws.once("message", (message: any) => {
|
|
167
|
-
resolve(message)
|
|
169
|
+
it("should return an error message if the protocol version is not supported", async () => {
|
|
170
|
+
const response = await serverResponse({
|
|
171
|
+
type: "join",
|
|
172
|
+
senderId: "browser",
|
|
173
|
+
supportedProtocolVersions: ["fake"],
|
|
168
174
|
})
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
assert.deepEqual(response, {
|
|
176
|
+
type: "error",
|
|
177
|
+
senderId: "server",
|
|
178
|
+
targetId: "browser",
|
|
179
|
+
message: "unsupported protocol version",
|
|
171
180
|
})
|
|
172
181
|
})
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
|
|
183
|
+
it("should respond with protocol v1 if no protocol version is specified", async () => {
|
|
184
|
+
const response = await serverResponse({
|
|
185
|
+
type: "join",
|
|
186
|
+
senderId: "browser",
|
|
187
|
+
})
|
|
188
|
+
assert.deepEqual(response, {
|
|
189
|
+
type: "peer",
|
|
190
|
+
senderId: "server",
|
|
191
|
+
targetId: "browser",
|
|
192
|
+
selectedProtocolVersion: "1",
|
|
193
|
+
})
|
|
175
194
|
})
|
|
176
195
|
})
|
|
177
|
-
}
|
|
196
|
+
})
|
|
178
197
|
|
|
179
198
|
export const pause = (t = 0) =>
|
|
180
199
|
new Promise<void>(resolve => setTimeout(() => resolve(), t))
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import http from "http"
|
|
2
|
-
import { createWebSocketServer } from "./CreateWebSocketServer.js"
|
|
3
|
-
import WebSocket from "ws"
|
|
4
|
-
|
|
5
|
-
function startServer(port: number) {
|
|
6
|
-
const server = http.createServer()
|
|
7
|
-
const socket = createWebSocketServer(server)
|
|
8
|
-
return new Promise<{
|
|
9
|
-
socket: WebSocket.Server
|
|
10
|
-
server: http.Server
|
|
11
|
-
}>(resolve => {
|
|
12
|
-
server.listen(port, () => resolve({ socket, server }))
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type WebSocketState =
|
|
17
|
-
| typeof WebSocket.CONNECTING
|
|
18
|
-
| typeof WebSocket.OPEN
|
|
19
|
-
| typeof WebSocket.CLOSING
|
|
20
|
-
| typeof WebSocket.CLOSED
|
|
21
|
-
|
|
22
|
-
function waitForSocketState(socket: WebSocket, state: WebSocketState) {
|
|
23
|
-
return new Promise<void>(function (resolve) {
|
|
24
|
-
setTimeout(function () {
|
|
25
|
-
if (socket.readyState === state) {
|
|
26
|
-
resolve()
|
|
27
|
-
} else {
|
|
28
|
-
waitForSocketState(socket, state).then(resolve)
|
|
29
|
-
}
|
|
30
|
-
}, 5)
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export { startServer, waitForSocketState }
|