@libp2p/interface-compliance-tests 6.4.16 → 6.5.0-8484de8a2
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/src/connection-encryption/index.d.ts.map +1 -1
- package/dist/src/connection-encryption/index.js +24 -15
- package/dist/src/connection-encryption/index.js.map +1 -1
- package/dist/src/stream-muxer/base-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/base-test.js +62 -341
- package/dist/src/stream-muxer/base-test.js.map +1 -1
- package/dist/src/stream-muxer/close-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/close-test.js +254 -305
- package/dist/src/stream-muxer/close-test.js.map +1 -1
- package/dist/src/stream-muxer/index.js +2 -2
- package/dist/src/stream-muxer/index.js.map +1 -1
- package/dist/src/stream-muxer/{mega-stress-test.d.ts → stream-test.d.ts} +2 -2
- package/dist/src/stream-muxer/stream-test.d.ts.map +1 -0
- package/dist/src/stream-muxer/stream-test.js +289 -0
- package/dist/src/stream-muxer/stream-test.js.map +1 -0
- package/dist/src/stream-muxer/stress-test.d.ts.map +1 -1
- package/dist/src/stream-muxer/stress-test.js +70 -16
- package/dist/src/stream-muxer/stress-test.js.map +1 -1
- package/dist/src/transport/index.d.ts.map +1 -1
- package/dist/src/transport/index.js +232 -203
- package/dist/src/transport/index.js.map +1 -1
- package/dist/src/transport/utils.js +2 -2
- package/dist/src/transport/utils.js.map +1 -1
- package/package.json +23 -51
- package/src/connection-encryption/index.ts +27 -20
- package/src/stream-muxer/base-test.ts +75 -409
- package/src/stream-muxer/close-test.ts +304 -327
- package/src/stream-muxer/index.ts +2 -2
- package/src/stream-muxer/stream-test.ts +380 -0
- package/src/stream-muxer/stress-test.ts +92 -18
- package/src/transport/index.ts +280 -241
- package/src/transport/utils.ts +2 -2
- package/dist/src/connection-encryption/utils/index.d.ts +0 -3
- package/dist/src/connection-encryption/utils/index.d.ts.map +0 -1
- package/dist/src/connection-encryption/utils/index.js +0 -21
- package/dist/src/connection-encryption/utils/index.js.map +0 -1
- package/dist/src/matchers.d.ts +0 -12
- package/dist/src/matchers.d.ts.map +0 -1
- package/dist/src/matchers.js +0 -14
- package/dist/src/matchers.js.map +0 -1
- package/dist/src/mocks/connection-manager.d.ts +0 -27
- package/dist/src/mocks/connection-manager.d.ts.map +0 -1
- package/dist/src/mocks/connection-manager.js +0 -147
- package/dist/src/mocks/connection-manager.js.map +0 -1
- package/dist/src/mocks/connection.d.ts +0 -41
- package/dist/src/mocks/connection.d.ts.map +0 -1
- package/dist/src/mocks/connection.js +0 -234
- package/dist/src/mocks/connection.js.map +0 -1
- package/dist/src/mocks/duplex.d.ts +0 -4
- package/dist/src/mocks/duplex.d.ts.map +0 -1
- package/dist/src/mocks/duplex.js +0 -9
- package/dist/src/mocks/duplex.js.map +0 -1
- package/dist/src/mocks/index.d.ts +0 -12
- package/dist/src/mocks/index.d.ts.map +0 -1
- package/dist/src/mocks/index.js +0 -8
- package/dist/src/mocks/index.js.map +0 -1
- package/dist/src/mocks/multiaddr-connection.d.ts +0 -17
- package/dist/src/mocks/multiaddr-connection.d.ts.map +0 -1
- package/dist/src/mocks/multiaddr-connection.js +0 -64
- package/dist/src/mocks/multiaddr-connection.js.map +0 -1
- package/dist/src/mocks/muxer.d.ts +0 -36
- package/dist/src/mocks/muxer.d.ts.map +0 -1
- package/dist/src/mocks/muxer.js +0 -234
- package/dist/src/mocks/muxer.js.map +0 -1
- package/dist/src/mocks/registrar.d.ts +0 -16
- package/dist/src/mocks/registrar.d.ts.map +0 -1
- package/dist/src/mocks/registrar.js +0 -66
- package/dist/src/mocks/registrar.js.map +0 -1
- package/dist/src/mocks/upgrader.d.ts +0 -9
- package/dist/src/mocks/upgrader.d.ts.map +0 -1
- package/dist/src/mocks/upgrader.js +0 -46
- package/dist/src/mocks/upgrader.js.map +0 -1
- package/dist/src/pubsub/api.d.ts +0 -6
- package/dist/src/pubsub/api.d.ts.map +0 -1
- package/dist/src/pubsub/api.js +0 -88
- package/dist/src/pubsub/api.js.map +0 -1
- package/dist/src/pubsub/connection-handlers.d.ts +0 -6
- package/dist/src/pubsub/connection-handlers.d.ts.map +0 -1
- package/dist/src/pubsub/connection-handlers.js +0 -329
- package/dist/src/pubsub/connection-handlers.js.map +0 -1
- package/dist/src/pubsub/emit-self.d.ts +0 -6
- package/dist/src/pubsub/emit-self.d.ts.map +0 -1
- package/dist/src/pubsub/emit-self.js +0 -80
- package/dist/src/pubsub/emit-self.js.map +0 -1
- package/dist/src/pubsub/index.d.ts +0 -18
- package/dist/src/pubsub/index.d.ts.map +0 -1
- package/dist/src/pubsub/index.js +0 -17
- package/dist/src/pubsub/index.js.map +0 -1
- package/dist/src/pubsub/messages.d.ts +0 -6
- package/dist/src/pubsub/messages.d.ts.map +0 -1
- package/dist/src/pubsub/messages.js +0 -48
- package/dist/src/pubsub/messages.js.map +0 -1
- package/dist/src/pubsub/multiple-nodes.d.ts +0 -6
- package/dist/src/pubsub/multiple-nodes.d.ts.map +0 -1
- package/dist/src/pubsub/multiple-nodes.js +0 -350
- package/dist/src/pubsub/multiple-nodes.js.map +0 -1
- package/dist/src/pubsub/two-nodes.d.ts +0 -6
- package/dist/src/pubsub/two-nodes.d.ts.map +0 -1
- package/dist/src/pubsub/two-nodes.js +0 -216
- package/dist/src/pubsub/two-nodes.js.map +0 -1
- package/dist/src/pubsub/utils.d.ts +0 -5
- package/dist/src/pubsub/utils.d.ts.map +0 -1
- package/dist/src/pubsub/utils.js +0 -27
- package/dist/src/pubsub/utils.js.map +0 -1
- package/dist/src/stream-muxer/mega-stress-test.d.ts.map +0 -1
- package/dist/src/stream-muxer/mega-stress-test.js +0 -11
- package/dist/src/stream-muxer/mega-stress-test.js.map +0 -1
- package/dist/src/stream-muxer/spawner.d.ts +0 -4
- package/dist/src/stream-muxer/spawner.d.ts.map +0 -1
- package/dist/src/stream-muxer/spawner.js +0 -37
- package/dist/src/stream-muxer/spawner.js.map +0 -1
- package/dist/typedoc-urls.json +0 -44
- package/src/connection-encryption/utils/index.ts +0 -27
- package/src/matchers.ts +0 -18
- package/src/mocks/connection-manager.ts +0 -216
- package/src/mocks/connection.ts +0 -307
- package/src/mocks/duplex.ts +0 -11
- package/src/mocks/index.ts +0 -11
- package/src/mocks/multiaddr-connection.ts +0 -80
- package/src/mocks/muxer.ts +0 -331
- package/src/mocks/registrar.ts +0 -86
- package/src/mocks/upgrader.ts +0 -65
- package/src/pubsub/api.ts +0 -116
- package/src/pubsub/connection-handlers.ts +0 -413
- package/src/pubsub/emit-self.ts +0 -99
- package/src/pubsub/index.ts +0 -34
- package/src/pubsub/messages.ts +0 -59
- package/src/pubsub/multiple-nodes.ts +0 -440
- package/src/pubsub/two-nodes.ts +0 -272
- package/src/pubsub/utils.ts +0 -34
- package/src/stream-muxer/mega-stress-test.ts +0 -14
- package/src/stream-muxer/spawner.ts +0 -55
|
@@ -1,40 +1,102 @@
|
|
|
1
|
-
import { stop } from '@libp2p/interface';
|
|
1
|
+
import { stop, TimeoutError } from '@libp2p/interface';
|
|
2
|
+
import { prefixLogger } from '@libp2p/logger';
|
|
2
3
|
import { expect } from 'aegir/chai';
|
|
3
4
|
import delay from 'delay';
|
|
5
|
+
import all from 'it-all';
|
|
4
6
|
import drain from 'it-drain';
|
|
5
7
|
import { pushable } from 'it-pushable';
|
|
6
|
-
import pDefer from 'p-defer';
|
|
7
8
|
import { pEvent } from 'p-event';
|
|
8
9
|
import pRetry from 'p-retry';
|
|
9
10
|
import pWaitFor from 'p-wait-for';
|
|
10
11
|
import { raceSignal } from 'race-signal';
|
|
12
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
11
13
|
import { isValidTick } from '../is-valid-tick.js';
|
|
12
14
|
import { createPeer, getTransportManager, getUpgrader } from './utils.js';
|
|
13
15
|
async function getSetup(common) {
|
|
14
16
|
const setup = await common.setup();
|
|
15
|
-
const dialer = await createPeer(
|
|
17
|
+
const dialer = await createPeer({
|
|
18
|
+
logger: prefixLogger('dialer'),
|
|
19
|
+
...setup.dialer
|
|
20
|
+
});
|
|
16
21
|
let listener;
|
|
17
22
|
if (setup.listener != null) {
|
|
18
|
-
listener = await createPeer(
|
|
23
|
+
listener = await createPeer({
|
|
24
|
+
logger: prefixLogger('listener'),
|
|
25
|
+
...setup.listener
|
|
26
|
+
});
|
|
19
27
|
}
|
|
20
|
-
|
|
28
|
+
let dialAddrs = listener?.getMultiaddrs() ?? setup.dialAddrs;
|
|
21
29
|
if (dialAddrs == null) {
|
|
22
30
|
throw new Error('Listener config or dial addresses must be specified');
|
|
23
31
|
}
|
|
32
|
+
dialAddrs = dialAddrs.filter(ma => setup.dialMultiaddrMatcher.exactMatch(ma));
|
|
33
|
+
if (dialAddrs.length === 0) {
|
|
34
|
+
throw new Error('Listener was not listening on any addresses that the dialMultiaddrMatcher matched');
|
|
35
|
+
}
|
|
24
36
|
return {
|
|
25
37
|
dialer,
|
|
26
38
|
listener,
|
|
27
|
-
dialAddrs
|
|
39
|
+
dialAddrs,
|
|
28
40
|
dialMultiaddrMatcher: setup.dialMultiaddrMatcher,
|
|
29
41
|
listenMultiaddrMatcher: setup.listenMultiaddrMatcher
|
|
30
42
|
};
|
|
31
43
|
}
|
|
32
44
|
export default (common) => {
|
|
45
|
+
describe('transport events', () => {
|
|
46
|
+
let dialer;
|
|
47
|
+
let listener;
|
|
48
|
+
let listenMultiaddrMatcher;
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
await stop(dialer, listener);
|
|
51
|
+
await common.teardown();
|
|
52
|
+
});
|
|
53
|
+
it('emits listening', async function () {
|
|
54
|
+
({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common));
|
|
55
|
+
if (listener == null) {
|
|
56
|
+
return this.skip();
|
|
57
|
+
}
|
|
58
|
+
await listener.stop();
|
|
59
|
+
const transportListeningPromise = Promise.withResolvers();
|
|
60
|
+
listener.addEventListener('transport:listening', (event) => {
|
|
61
|
+
const transportListener = event.detail;
|
|
62
|
+
if (transportListener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma))) {
|
|
63
|
+
transportListeningPromise.resolve();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
await listener.start();
|
|
67
|
+
await raceSignal(transportListeningPromise.promise, AbortSignal.timeout(1000), {
|
|
68
|
+
translateError: () => {
|
|
69
|
+
return new TimeoutError('Did not emit listening event');
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it('emits close', async function () {
|
|
74
|
+
({ dialer, listener } = await getSetup(common));
|
|
75
|
+
if (listener == null) {
|
|
76
|
+
return this.skip();
|
|
77
|
+
}
|
|
78
|
+
const transportManager = getTransportManager(listener);
|
|
79
|
+
const transportListener = transportManager.getListeners()
|
|
80
|
+
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
81
|
+
.pop();
|
|
82
|
+
if (transportListener == null) {
|
|
83
|
+
throw new Error('Could not find address listener');
|
|
84
|
+
}
|
|
85
|
+
const p = pEvent(transportListener, 'close');
|
|
86
|
+
await listener.stop();
|
|
87
|
+
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
88
|
+
translateError: () => {
|
|
89
|
+
return new TimeoutError('Did not emit close event');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
33
94
|
describe('interface-transport', () => {
|
|
34
95
|
let dialer;
|
|
35
96
|
let listener;
|
|
36
97
|
let dialAddrs;
|
|
37
98
|
let dialMultiaddrMatcher;
|
|
99
|
+
let listenMultiaddrMatcher;
|
|
38
100
|
afterEach(async () => {
|
|
39
101
|
await stop(dialer, listener);
|
|
40
102
|
await common.teardown();
|
|
@@ -45,17 +107,20 @@ export default (common) => {
|
|
|
45
107
|
const output = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
46
108
|
signal: AbortSignal.timeout(5000)
|
|
47
109
|
});
|
|
48
|
-
expect(output).to.equalBytes(input);
|
|
110
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
49
111
|
});
|
|
50
112
|
it('should listen on multiple addresses', async () => {
|
|
51
113
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
52
114
|
const input = Uint8Array.from([0, 1, 2, 3, 4]);
|
|
53
|
-
await
|
|
54
|
-
signal: AbortSignal.timeout(5000)
|
|
55
|
-
})).to.eventually.deep.equal(input);
|
|
56
|
-
await expect(dialer.services.echo.echo(dialAddrs[1], input, {
|
|
115
|
+
const output1 = await dialer.services.echo.echo(dialAddrs[0], input, {
|
|
57
116
|
signal: AbortSignal.timeout(5000)
|
|
58
|
-
})
|
|
117
|
+
});
|
|
118
|
+
expect(output1.subarray()).to.equalBytes(input);
|
|
119
|
+
const output2 = await dialer.services.echo.echo(dialAddrs[1], input, {
|
|
120
|
+
signal: AbortSignal.timeout(5000),
|
|
121
|
+
force: true
|
|
122
|
+
});
|
|
123
|
+
expect(output2.subarray()).to.equalBytes(input);
|
|
59
124
|
});
|
|
60
125
|
it('can close connections', async () => {
|
|
61
126
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
@@ -75,12 +140,15 @@ export default (common) => {
|
|
|
75
140
|
.with.property('name', 'AbortError');
|
|
76
141
|
});
|
|
77
142
|
it('should close all streams when the connection closes', async () => {
|
|
78
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
143
|
+
({ dialer, listener, dialAddrs, listenMultiaddrMatcher } = await getSetup(common));
|
|
79
144
|
let incomingConnectionPromise;
|
|
80
145
|
if (listener != null) {
|
|
81
|
-
incomingConnectionPromise =
|
|
146
|
+
incomingConnectionPromise = Promise.withResolvers();
|
|
82
147
|
listener.addEventListener('connection:open', (event) => {
|
|
83
148
|
const conn = event.detail;
|
|
149
|
+
if (!listenMultiaddrMatcher.matches(conn.remoteAddr)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
84
152
|
if (conn.remotePeer.equals(dialer.peerId)) {
|
|
85
153
|
incomingConnectionPromise?.resolve(conn);
|
|
86
154
|
}
|
|
@@ -96,18 +164,24 @@ export default (common) => {
|
|
|
96
164
|
maxOutboundStreams: 5
|
|
97
165
|
});
|
|
98
166
|
}
|
|
99
|
-
|
|
100
|
-
// Close the connection and verify all streams have been closed
|
|
101
|
-
await connection.close();
|
|
102
|
-
await pWaitFor(() => connection.streams.length === 0, {
|
|
103
|
-
timeout: 5000
|
|
104
|
-
});
|
|
167
|
+
expect(connection).to.have.property('streams').that.has.lengthOf(5);
|
|
105
168
|
if (remoteConn != null) {
|
|
106
|
-
await pWaitFor(() => remoteConn.streams.length ===
|
|
169
|
+
await pWaitFor(() => remoteConn.streams.length === 5, {
|
|
107
170
|
timeout: 5000
|
|
108
171
|
});
|
|
109
172
|
}
|
|
110
|
-
|
|
173
|
+
// Close the connection and verify all streams have been closed
|
|
174
|
+
await Promise.all([
|
|
175
|
+
pEvent(connection, 'close'),
|
|
176
|
+
pEvent(remoteConn ?? connection, 'close'),
|
|
177
|
+
connection.close()
|
|
178
|
+
]);
|
|
179
|
+
expect(connection).to.have.property('status', 'closed');
|
|
180
|
+
expect(connection).to.have.property('streams').that.is.empty();
|
|
181
|
+
if (remoteConn != null) {
|
|
182
|
+
expect(remoteConn).to.have.property('status', 'closed');
|
|
183
|
+
expect(remoteConn).to.have.property('streams').that.is.empty();
|
|
184
|
+
}
|
|
111
185
|
});
|
|
112
186
|
it('should not handle connection if upgradeInbound rejects', async function () {
|
|
113
187
|
({ dialer, listener, dialAddrs, dialMultiaddrMatcher } = await getSetup(common));
|
|
@@ -148,262 +222,219 @@ export default (common) => {
|
|
|
148
222
|
}
|
|
149
223
|
}
|
|
150
224
|
});
|
|
151
|
-
it('should handle one
|
|
225
|
+
it('should handle one small write', async function () {
|
|
152
226
|
const timeout = 120_000;
|
|
153
227
|
this.timeout(timeout);
|
|
154
228
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
229
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
230
|
+
const input = new Uint8Array(1024).fill(5);
|
|
231
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
232
|
+
signal: AbortSignal.timeout(timeout)
|
|
233
|
+
});
|
|
234
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
235
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty();
|
|
236
|
+
});
|
|
237
|
+
it('should handle one big write', async function () {
|
|
238
|
+
const timeout = 540_000;
|
|
239
|
+
this.timeout(timeout);
|
|
240
|
+
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
241
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
155
242
|
const input = new Uint8Array(1024 * 1024 * 10).fill(5);
|
|
156
|
-
const output = await dialer.services.echo.echo(
|
|
243
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
157
244
|
signal: AbortSignal.timeout(timeout)
|
|
158
245
|
});
|
|
159
|
-
expect(output).to.equalBytes(input);
|
|
246
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
247
|
+
expect(connection.streams.filter(s => s.protocol === dialer.services.echo.protocol)).to.be.empty();
|
|
160
248
|
});
|
|
161
249
|
it('should handle many small writes', async function () {
|
|
162
250
|
const timeout = 360_000;
|
|
163
251
|
this.timeout(timeout);
|
|
164
252
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
253
|
+
const connection = await dialer.dial(dialAddrs[0]);
|
|
254
|
+
const echoProtocol = dialer.services.echo.protocol;
|
|
165
255
|
for (let i = 0; i < 2000; i++) {
|
|
166
256
|
const input = new Uint8Array(1024).fill(5);
|
|
167
|
-
const output = await dialer.services.echo.echo(
|
|
257
|
+
const output = await dialer.services.echo.echo(connection.remotePeer, input, {
|
|
168
258
|
signal: AbortSignal.timeout(timeout)
|
|
169
259
|
});
|
|
170
|
-
expect(output).to.equalBytes(input);
|
|
171
|
-
|
|
172
|
-
});
|
|
173
|
-
it('can close a stream for reading but send a large amount of data', async function () {
|
|
174
|
-
const timeout = 120_000;
|
|
175
|
-
this.timeout(timeout);
|
|
176
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
177
|
-
if (listener == null) {
|
|
178
|
-
return this.skip();
|
|
179
|
-
}
|
|
180
|
-
const protocol = '/send-data/1.0.0';
|
|
181
|
-
const chunkSize = 1024;
|
|
182
|
-
const bytes = chunkSize * 1024 * 10;
|
|
183
|
-
const deferred = pDefer();
|
|
184
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
185
|
-
Promise.resolve().then(async () => {
|
|
186
|
-
let read = 0;
|
|
187
|
-
for await (const buf of stream.source) {
|
|
188
|
-
read += buf.byteLength;
|
|
189
|
-
if (read === bytes) {
|
|
190
|
-
deferred.resolve();
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
.catch(err => {
|
|
196
|
-
deferred.reject(err);
|
|
197
|
-
stream.abort(err);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
201
|
-
await stream.closeRead();
|
|
202
|
-
await stream.sink((async function* () {
|
|
203
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
204
|
-
yield new Uint8Array(chunkSize);
|
|
205
|
-
}
|
|
206
|
-
})());
|
|
207
|
-
await stream.close();
|
|
208
|
-
await deferred.promise;
|
|
209
|
-
});
|
|
210
|
-
it('can close a stream for writing but receive a large amount of data', async function () {
|
|
211
|
-
const timeout = 120_000;
|
|
212
|
-
this.timeout(timeout);
|
|
213
|
-
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
214
|
-
if (listener == null) {
|
|
215
|
-
return this.skip();
|
|
216
|
-
}
|
|
217
|
-
const protocol = '/receive-data/1.0.0';
|
|
218
|
-
const chunkSize = 1024;
|
|
219
|
-
const bytes = chunkSize * 1024 * 10;
|
|
220
|
-
const deferred = pDefer();
|
|
221
|
-
await listener.handle(protocol, ({ stream }) => {
|
|
222
|
-
Promise.resolve().then(async () => {
|
|
223
|
-
await stream.sink((async function* () {
|
|
224
|
-
for (let i = 0; i < bytes; i += chunkSize) {
|
|
225
|
-
yield new Uint8Array(chunkSize);
|
|
226
|
-
}
|
|
227
|
-
})());
|
|
228
|
-
await stream.close();
|
|
229
|
-
})
|
|
230
|
-
.catch(err => {
|
|
231
|
-
deferred.reject(err);
|
|
232
|
-
stream.abort(err);
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
236
|
-
await stream.closeWrite();
|
|
237
|
-
let read = 0;
|
|
238
|
-
for await (const buf of stream.source) {
|
|
239
|
-
read += buf.byteLength;
|
|
260
|
+
expect(output.subarray()).to.equalBytes(input);
|
|
261
|
+
expect(connection.streams.filter(s => s.protocol === echoProtocol)).to.be.empty();
|
|
240
262
|
}
|
|
241
|
-
expect(read).to.equal(bytes);
|
|
242
263
|
});
|
|
243
|
-
it('can close local stream
|
|
264
|
+
it('can close local stream while a remote stream is writing', async function () {
|
|
244
265
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
245
266
|
if (listener == null) {
|
|
246
267
|
return this.skip();
|
|
247
268
|
}
|
|
269
|
+
// 1. remote stream close read
|
|
270
|
+
// 2. local stream close write
|
|
271
|
+
// 3. remote stream close write
|
|
248
272
|
/**
|
|
249
273
|
* NodeA NodeB
|
|
250
274
|
* | <--- STOP_SENDING |
|
|
251
275
|
* | FIN ---> |
|
|
276
|
+
* | <--- DATA |
|
|
252
277
|
* | <--- FIN |
|
|
253
278
|
* | FIN_ACK ---> |
|
|
254
279
|
* | <--- FIN_ACK |
|
|
255
280
|
*/
|
|
256
|
-
const getRemoteStream =
|
|
281
|
+
const getRemoteStream = Promise.withResolvers();
|
|
257
282
|
const protocol = '/close-local-while-remote-writes/1.0.0';
|
|
258
|
-
const streamHandler = (
|
|
259
|
-
|
|
260
|
-
getRemoteStream.resolve(stream);
|
|
261
|
-
});
|
|
283
|
+
const streamHandler = (stream) => {
|
|
284
|
+
getRemoteStream.resolve(stream);
|
|
262
285
|
};
|
|
263
|
-
await listener.handle(protocol,
|
|
264
|
-
streamHandler(info);
|
|
265
|
-
}, {
|
|
286
|
+
await listener.handle(protocol, streamHandler, {
|
|
266
287
|
runOnLimitedConnection: true
|
|
267
288
|
});
|
|
268
289
|
const connection = await dialer.dial(dialAddrs[0]);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
//
|
|
290
|
+
const [localStream, remoteStream] = await Promise.all([
|
|
291
|
+
// open a stream on the echo protocol
|
|
292
|
+
connection.newStream(protocol, {
|
|
293
|
+
runOnLimitedConnection: true
|
|
294
|
+
}),
|
|
295
|
+
getRemoteStream.promise
|
|
296
|
+
]);
|
|
297
|
+
// ignore incoming data
|
|
298
|
+
void drain(localStream);
|
|
299
|
+
// close the remote readable end
|
|
277
300
|
await remoteStream.closeRead();
|
|
278
|
-
//
|
|
301
|
+
// send data from the remote to the local
|
|
279
302
|
const remoteInputStream = pushable();
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
303
|
+
Promise.resolve().then(async () => {
|
|
304
|
+
for await (const buf of remoteInputStream) {
|
|
305
|
+
const sendMore = remoteStream.send(buf);
|
|
306
|
+
if (sendMore === false) {
|
|
307
|
+
await pEvent(remoteStream, 'drain', {
|
|
308
|
+
rejectionEvents: [
|
|
309
|
+
'close'
|
|
310
|
+
]
|
|
311
|
+
});
|
|
312
|
+
}
|
|
285
313
|
}
|
|
286
|
-
|
|
287
|
-
|
|
314
|
+
// close the remote writable end
|
|
315
|
+
await remoteStream.close();
|
|
288
316
|
});
|
|
289
|
-
|
|
317
|
+
await Promise.all([
|
|
318
|
+
// wait for remote to receive local FIN
|
|
319
|
+
pEvent(remoteStream, 'remoteCloseWrite'),
|
|
320
|
+
// wait to receive FIN_ACK
|
|
321
|
+
localStream.close()
|
|
322
|
+
]);
|
|
323
|
+
// stop sending remote -> local
|
|
290
324
|
remoteInputStream.end();
|
|
291
|
-
// wait to receive FIN_ACK
|
|
292
|
-
await p;
|
|
293
325
|
// wait for remote to notice closure
|
|
294
326
|
await pRetry(() => {
|
|
295
327
|
if (remoteStream.status !== 'closed') {
|
|
296
328
|
throw new Error('Remote stream not closed');
|
|
297
329
|
}
|
|
298
330
|
});
|
|
299
|
-
|
|
331
|
+
// both ends should be closed
|
|
332
|
+
assertStreamClosed(localStream);
|
|
300
333
|
assertStreamClosed(remoteStream);
|
|
301
334
|
});
|
|
302
|
-
it('can close local stream for writing
|
|
335
|
+
it('can close local stream for writing while a remote stream is reading', async function () {
|
|
303
336
|
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
304
337
|
if (listener == null) {
|
|
305
338
|
return this.skip();
|
|
306
339
|
}
|
|
307
340
|
/**
|
|
308
341
|
* NodeA NodeB
|
|
342
|
+
* | DATA ---> |
|
|
309
343
|
* | FIN ---> |
|
|
310
344
|
* | <--- FIN |
|
|
311
345
|
* | FIN_ACK ---> |
|
|
312
346
|
* | <--- FIN_ACK |
|
|
313
347
|
*/
|
|
314
|
-
const getRemoteStream =
|
|
348
|
+
const getRemoteStream = Promise.withResolvers();
|
|
315
349
|
const protocol = '/close-local-while-remote-reads/1.0.0';
|
|
316
|
-
const streamHandler = (
|
|
317
|
-
|
|
318
|
-
getRemoteStream.resolve(stream);
|
|
319
|
-
});
|
|
350
|
+
const streamHandler = (stream) => {
|
|
351
|
+
getRemoteStream.resolve(stream);
|
|
320
352
|
};
|
|
321
|
-
await listener.handle(protocol,
|
|
322
|
-
streamHandler(info);
|
|
323
|
-
}, {
|
|
353
|
+
await listener.handle(protocol, streamHandler, {
|
|
324
354
|
runOnLimitedConnection: true
|
|
325
355
|
});
|
|
326
356
|
const connection = await dialer.dial(dialAddrs[0]);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
//
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
}, {
|
|
344
|
-
minTimeout: 100
|
|
357
|
+
const [localStream, remoteStream] = await Promise.all([
|
|
358
|
+
// open a stream on the echo protocol
|
|
359
|
+
connection.newStream(protocol, {
|
|
360
|
+
runOnLimitedConnection: true
|
|
361
|
+
}),
|
|
362
|
+
getRemoteStream.promise
|
|
363
|
+
]);
|
|
364
|
+
// ignore incoming data
|
|
365
|
+
void drain(remoteStream);
|
|
366
|
+
// close the remote stream writable end when the local sends a FIN
|
|
367
|
+
remoteStream.addEventListener('remoteCloseWrite', () => {
|
|
368
|
+
remoteStream.close()
|
|
369
|
+
.catch(err => {
|
|
370
|
+
remoteStream.abort(err);
|
|
371
|
+
});
|
|
345
372
|
});
|
|
346
|
-
// remote
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
373
|
+
// send data to the remote then close the stream
|
|
374
|
+
const data = [
|
|
375
|
+
Uint8Array.from([0, 1, 2, 3]),
|
|
376
|
+
Uint8Array.from([4, 5, 6, 7]),
|
|
377
|
+
Uint8Array.from([8, 9, 0, 1])
|
|
378
|
+
];
|
|
379
|
+
const [remoteCloseEvent, localCloseEvent] = await Promise.all([
|
|
380
|
+
// wait for the remote to close
|
|
381
|
+
pEvent(remoteStream, 'close'),
|
|
382
|
+
pEvent(localStream, 'close'),
|
|
383
|
+
(async () => {
|
|
384
|
+
for (const buf of data) {
|
|
385
|
+
if (!localStream.send(buf)) {
|
|
386
|
+
await pEvent(localStream, 'drain', {
|
|
387
|
+
rejectionEvents: [
|
|
388
|
+
'close'
|
|
389
|
+
]
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// close the local writable end
|
|
394
|
+
await localStream.close();
|
|
395
|
+
})()
|
|
396
|
+
]);
|
|
397
|
+
expect(remoteCloseEvent).to.not.have.property('error', 'remote stream did not close cleanly');
|
|
398
|
+
expect(localCloseEvent).to.not.have.property('error', 'local stream did not close cleanly');
|
|
354
399
|
// wait for remote to notice closure
|
|
355
400
|
await pRetry(() => {
|
|
356
401
|
if (remoteStream.status !== 'closed') {
|
|
357
402
|
throw new Error('Remote stream not closed');
|
|
358
403
|
}
|
|
359
404
|
});
|
|
360
|
-
|
|
405
|
+
// both ends should be closed
|
|
406
|
+
assertStreamClosed(localStream);
|
|
361
407
|
assertStreamClosed(remoteStream);
|
|
362
408
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
let listenMultiaddrMatcher;
|
|
368
|
-
afterEach(async () => {
|
|
369
|
-
await stop(dialer, listener);
|
|
370
|
-
await common.teardown();
|
|
371
|
-
});
|
|
372
|
-
it('emits listening', async function () {
|
|
373
|
-
({ dialer, listener, listenMultiaddrMatcher } = await getSetup(common));
|
|
409
|
+
it('can close a stream for writing but receive a large amount of data', async function () {
|
|
410
|
+
const timeout = 120_000;
|
|
411
|
+
this.timeout(timeout);
|
|
412
|
+
({ dialer, listener, dialAddrs } = await getSetup(common));
|
|
374
413
|
if (listener == null) {
|
|
375
414
|
return this.skip();
|
|
376
415
|
}
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
416
|
+
const protocol = '/receive-data/1.0.0';
|
|
417
|
+
const chunkSize = 1024;
|
|
418
|
+
const bytes = chunkSize * 1024 * 10;
|
|
419
|
+
await listener.handle(protocol, async (stream) => {
|
|
420
|
+
for (let i = 0; i < bytes; i += chunkSize) {
|
|
421
|
+
const sendMore = stream.send(new Uint8Array(chunkSize));
|
|
422
|
+
if (!sendMore) {
|
|
423
|
+
await pEvent(stream, 'drain', {
|
|
424
|
+
rejectionEvents: [
|
|
425
|
+
'close'
|
|
426
|
+
]
|
|
427
|
+
});
|
|
428
|
+
}
|
|
383
429
|
}
|
|
430
|
+
await stream.close();
|
|
384
431
|
});
|
|
385
|
-
await
|
|
386
|
-
await
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
({ dialer, listener } = await getSetup(common));
|
|
392
|
-
if (listener == null) {
|
|
393
|
-
return this.skip();
|
|
394
|
-
}
|
|
395
|
-
const transportManager = getTransportManager(listener);
|
|
396
|
-
const transportListener = transportManager.getListeners()
|
|
397
|
-
.filter(listener => listener.getAddrs().some(ma => listenMultiaddrMatcher.exactMatch(ma)))
|
|
398
|
-
.pop();
|
|
399
|
-
if (transportListener == null) {
|
|
400
|
-
throw new Error('Could not find address listener');
|
|
401
|
-
}
|
|
402
|
-
const p = pEvent(transportListener, 'close');
|
|
403
|
-
await listener.stop();
|
|
404
|
-
await raceSignal(p, AbortSignal.timeout(1000), {
|
|
405
|
-
errorMessage: 'Did not emit close event'
|
|
406
|
-
});
|
|
432
|
+
const stream = await dialer.dialProtocol(dialAddrs[0], protocol);
|
|
433
|
+
const [output] = await Promise.all([
|
|
434
|
+
all(stream),
|
|
435
|
+
stream.close()
|
|
436
|
+
]);
|
|
437
|
+
expect(new Uint8ArrayList(...output).byteLength).to.equal(bytes);
|
|
407
438
|
});
|
|
408
439
|
});
|
|
409
440
|
};
|
|
@@ -412,7 +443,5 @@ function assertStreamClosed(stream) {
|
|
|
412
443
|
expect(stream.readStatus).to.equal('closed');
|
|
413
444
|
expect(stream.writeStatus).to.equal('closed');
|
|
414
445
|
expect(stream.timeline.close).to.be.a('number');
|
|
415
|
-
expect(stream.timeline.closeRead).to.be.a('number');
|
|
416
|
-
expect(stream.timeline.closeWrite).to.be.a('number');
|
|
417
446
|
}
|
|
418
447
|
//# sourceMappingURL=index.js.map
|