smoldot 1.0.0 → 1.0.2
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/cjs/index-browser.js +66 -19
- package/dist/cjs/index-deno.js +79 -56
- package/dist/cjs/index-nodejs.js +91 -40
- package/dist/cjs/instance/autogen/wasm0.js +1 -1
- package/dist/cjs/instance/autogen/wasm1.js +1 -1
- package/dist/cjs/instance/autogen/wasm2.js +1 -1
- package/dist/cjs/instance/bindings-smoldot-light.d.ts +42 -2
- package/dist/cjs/instance/bindings-smoldot-light.js +46 -26
- package/dist/cjs/instance/bindings.d.ts +8 -8
- package/dist/cjs/instance/instance.js +19 -25
- package/dist/cjs/instance/raw-instance.d.ts +1 -1
- package/dist/cjs/instance/raw-instance.js +3 -2
- package/dist/mjs/index-browser.js +66 -19
- package/dist/mjs/index-deno.js +79 -56
- package/dist/mjs/index-nodejs.js +91 -40
- package/dist/mjs/instance/autogen/wasm0.js +1 -1
- package/dist/mjs/instance/autogen/wasm1.js +1 -1
- package/dist/mjs/instance/autogen/wasm2.js +1 -1
- package/dist/mjs/instance/bindings-smoldot-light.d.ts +42 -2
- package/dist/mjs/instance/bindings-smoldot-light.js +46 -26
- package/dist/mjs/instance/bindings.d.ts +8 -8
- package/dist/mjs/instance/instance.js +19 -25
- package/dist/mjs/instance/raw-instance.d.ts +1 -1
- package/dist/mjs/instance/raw-instance.js +3 -2
- package/package.json +3 -3
|
@@ -49,6 +49,8 @@ function start(options) {
|
|
|
49
49
|
return Promise.resolve((0, pako_1.inflate)((0, base64_js_1.classicDecode)(input)));
|
|
50
50
|
},
|
|
51
51
|
registerShouldPeriodicallyYield: (callback) => {
|
|
52
|
+
if (typeof document === 'undefined') // We might be in a web worker.
|
|
53
|
+
return [false, () => { }];
|
|
52
54
|
const wrappedCallback = () => callback(document.visibilityState === 'visible');
|
|
53
55
|
document.addEventListener('visibilitychange', wrappedCallback);
|
|
54
56
|
return [document.visibilityState === 'visible', () => { document.removeEventListener('visibilitychange', wrappedCallback); }];
|
|
@@ -78,9 +80,8 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
78
80
|
// Attempt to parse the multiaddress.
|
|
79
81
|
// TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940)
|
|
80
82
|
const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/);
|
|
81
|
-
const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)$/);
|
|
83
|
+
const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc-direct\/certhash\/(.*?)$/);
|
|
82
84
|
if (wsParsed != null) {
|
|
83
|
-
let connection;
|
|
84
85
|
const proto = (wsParsed[4] == 'ws') ? 'ws' : 'wss';
|
|
85
86
|
if ((proto == 'ws' && forbidWs) ||
|
|
86
87
|
(proto == 'ws' && wsParsed[2] != 'localhost' && wsParsed[2] != '127.0.0.1' && forbidNonLocalWs) ||
|
|
@@ -90,10 +91,36 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
90
91
|
const url = (wsParsed[1] == 'ip6') ?
|
|
91
92
|
(proto + "://[" + wsParsed[2] + "]:" + wsParsed[3]) :
|
|
92
93
|
(proto + "://" + wsParsed[2] + ":" + wsParsed[3]);
|
|
93
|
-
connection = new WebSocket(url);
|
|
94
|
+
const connection = new WebSocket(url);
|
|
94
95
|
connection.binaryType = 'arraybuffer';
|
|
96
|
+
const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
|
|
97
|
+
const checkBufferedAmount = () => {
|
|
98
|
+
if (connection.readyState != 1)
|
|
99
|
+
return;
|
|
100
|
+
// Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
|
|
101
|
+
// of all the data that has been sent, but that might not be the case. For this
|
|
102
|
+
// reason, we use `bufferedAmount` as a hint rather than a correct value.
|
|
103
|
+
const bufferedAmount = connection.bufferedAmount;
|
|
104
|
+
let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
|
|
105
|
+
if (wasSent < 0)
|
|
106
|
+
wasSent = 0;
|
|
107
|
+
bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
|
|
108
|
+
if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
|
|
109
|
+
setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
|
|
110
|
+
bufferedAmountCheck.nextTimeout *= 2;
|
|
111
|
+
if (bufferedAmountCheck.nextTimeout > 500)
|
|
112
|
+
bufferedAmountCheck.nextTimeout = 500;
|
|
113
|
+
}
|
|
114
|
+
// Note: it is important to call `onWritableBytes` at the very end, as it might
|
|
115
|
+
// trigger a call to `send`.
|
|
116
|
+
if (wasSent != 0)
|
|
117
|
+
config.onWritableBytes(wasSent);
|
|
118
|
+
};
|
|
95
119
|
connection.onopen = () => {
|
|
96
|
-
config.onOpen({
|
|
120
|
+
config.onOpen({
|
|
121
|
+
type: 'single-stream', handshake: 'multistream-select-noise-yamux',
|
|
122
|
+
initialWritableBytes: 1024 * 1024, writeClosable: false,
|
|
123
|
+
});
|
|
97
124
|
};
|
|
98
125
|
connection.onclose = (event) => {
|
|
99
126
|
const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
|
|
@@ -112,7 +139,13 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
112
139
|
},
|
|
113
140
|
send: (data) => {
|
|
114
141
|
connection.send(data);
|
|
142
|
+
if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
|
|
143
|
+
bufferedAmountCheck.nextTimeout = 10;
|
|
144
|
+
setTimeout(checkBufferedAmount, 10);
|
|
145
|
+
}
|
|
146
|
+
bufferedAmountCheck.quenedUnreportedBytes += data.length;
|
|
115
147
|
},
|
|
148
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
116
149
|
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
117
150
|
};
|
|
118
151
|
}
|
|
@@ -162,16 +195,18 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
162
195
|
pc.onnegotiationneeded = null;
|
|
163
196
|
pc.ondatachannel = null;
|
|
164
197
|
for (const channel of Array.from(dataChannels.values())) {
|
|
165
|
-
channel.onopen = null;
|
|
166
|
-
channel.onerror = null;
|
|
167
|
-
channel.onclose = null;
|
|
168
|
-
channel.
|
|
198
|
+
channel.channel.onopen = null;
|
|
199
|
+
channel.channel.onerror = null;
|
|
200
|
+
channel.channel.onclose = null;
|
|
201
|
+
channel.channel.onbufferedamountlow = null;
|
|
202
|
+
channel.channel.onmessage = null;
|
|
169
203
|
}
|
|
170
204
|
dataChannels.clear();
|
|
171
205
|
if (handshakeDataChannel) {
|
|
172
206
|
handshakeDataChannel.onopen = null;
|
|
173
207
|
handshakeDataChannel.onerror = null;
|
|
174
208
|
handshakeDataChannel.onclose = null;
|
|
209
|
+
handshakeDataChannel.onbufferedamountlow = null;
|
|
175
210
|
handshakeDataChannel.onmessage = null;
|
|
176
211
|
}
|
|
177
212
|
handshakeDataChannel = undefined;
|
|
@@ -200,7 +235,7 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
200
235
|
}
|
|
201
236
|
else {
|
|
202
237
|
console.assert(direction !== 'outbound' || !handshakeDataChannel, "handshakeDataChannel still defined");
|
|
203
|
-
config.onStreamOpened(dataChannelId, direction);
|
|
238
|
+
config.onStreamOpened(dataChannelId, direction, 65536);
|
|
204
239
|
}
|
|
205
240
|
};
|
|
206
241
|
dataChannel.onerror = dataChannel.onclose = (_error) => {
|
|
@@ -222,6 +257,7 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
222
257
|
handshakeDataChannel.onopen = null;
|
|
223
258
|
handshakeDataChannel.onerror = null;
|
|
224
259
|
handshakeDataChannel.onclose = null;
|
|
260
|
+
handshakeDataChannel.onbufferedamountlow = null;
|
|
225
261
|
handshakeDataChannel.onmessage = null;
|
|
226
262
|
handshakeDataChannel = undefined;
|
|
227
263
|
}
|
|
@@ -238,12 +274,18 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
238
274
|
config.onStreamReset(dataChannelId);
|
|
239
275
|
}
|
|
240
276
|
};
|
|
277
|
+
dataChannel.onbufferedamountlow = () => {
|
|
278
|
+
const channel = dataChannels.get(dataChannelId);
|
|
279
|
+
const val = channel.bufferedBytes;
|
|
280
|
+
channel.bufferedBytes = 0;
|
|
281
|
+
config.onWritableBytes(val, dataChannelId);
|
|
282
|
+
};
|
|
241
283
|
dataChannel.onmessage = (m) => {
|
|
242
284
|
// The `data` field is an `ArrayBuffer`.
|
|
243
285
|
config.onMessage(new Uint8Array(m.data), dataChannelId);
|
|
244
286
|
};
|
|
245
287
|
if (direction !== 'first-outbound')
|
|
246
|
-
dataChannels.set(dataChannelId, dataChannel);
|
|
288
|
+
dataChannels.set(dataChannelId, { channel: dataChannel, bufferedBytes: 0 });
|
|
247
289
|
else
|
|
248
290
|
handshakeDataChannel = dataChannel;
|
|
249
291
|
};
|
|
@@ -385,7 +427,8 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
385
427
|
// (UDP or TCP)
|
|
386
428
|
"a=sctp-port:5000" + "\n" +
|
|
387
429
|
// The maximum SCTP user message size (in bytes) (RFC8841)
|
|
388
|
-
|
|
430
|
+
// Setting this field is part of the libp2p spec.
|
|
431
|
+
"a=max-message-size:16384" + "\n" +
|
|
389
432
|
// A transport address for a candidate that can be used for connectivity
|
|
390
433
|
// checks (RFC8839).
|
|
391
434
|
"a=candidate:1 1 UDP 1 " + targetIp + " " + targetPort + " typ host" + "\n";
|
|
@@ -414,17 +457,21 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
414
457
|
}
|
|
415
458
|
else {
|
|
416
459
|
const channel = dataChannels.get(streamId);
|
|
417
|
-
channel.onopen = null;
|
|
418
|
-
channel.onerror = null;
|
|
419
|
-
channel.onclose = null;
|
|
420
|
-
channel.
|
|
421
|
-
channel.
|
|
460
|
+
channel.channel.onopen = null;
|
|
461
|
+
channel.channel.onerror = null;
|
|
462
|
+
channel.channel.onclose = null;
|
|
463
|
+
channel.channel.onbufferedamountlow = null;
|
|
464
|
+
channel.channel.onmessage = null;
|
|
465
|
+
channel.channel.close();
|
|
422
466
|
dataChannels.delete(streamId);
|
|
423
467
|
}
|
|
424
468
|
},
|
|
425
469
|
send: (data, streamId) => {
|
|
426
|
-
dataChannels.get(streamId)
|
|
470
|
+
const channel = dataChannels.get(streamId);
|
|
471
|
+
channel.channel.send(data);
|
|
472
|
+
channel.bufferedBytes += data.length;
|
|
427
473
|
},
|
|
474
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
428
475
|
openOutSubstream: () => {
|
|
429
476
|
// `openOutSubstream` can only be called after we have called `config.onOpen`, therefore
|
|
430
477
|
// `pc` is guaranteed to be non-null.
|
|
@@ -436,8 +483,8 @@ function connect(config, forbidWs, forbidNonLocalWs, forbidWss, forbidWebRTC) {
|
|
|
436
483
|
// We need to check again if `handshakeDataChannel` is still defined, as the
|
|
437
484
|
// connection might have been closed.
|
|
438
485
|
if (handshakeDataChannel) {
|
|
439
|
-
config.onStreamOpened(handshakeDataChannel.id, 'outbound');
|
|
440
|
-
dataChannels.set(handshakeDataChannel.id, handshakeDataChannel);
|
|
486
|
+
config.onStreamOpened(handshakeDataChannel.id, 'outbound', 1024 * 1024);
|
|
487
|
+
dataChannels.set(handshakeDataChannel.id, { channel: handshakeDataChannel, bufferedBytes: 0 });
|
|
441
488
|
handshakeDataChannel = undefined;
|
|
442
489
|
}
|
|
443
490
|
}))();
|
package/dist/cjs/index-deno.js
CHANGED
|
@@ -109,7 +109,6 @@ function trustedBase64Decode(base64) {
|
|
|
109
109
|
* @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
|
|
110
110
|
*/
|
|
111
111
|
function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
112
|
-
let connection;
|
|
113
112
|
// Attempt to parse the multiaddress.
|
|
114
113
|
// TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940)
|
|
115
114
|
const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/);
|
|
@@ -124,24 +123,72 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
124
123
|
const url = (wsParsed[1] == 'ip6') ?
|
|
125
124
|
(proto + "://[" + wsParsed[2] + "]:" + wsParsed[3]) :
|
|
126
125
|
(proto + "://" + wsParsed[2] + ":" + wsParsed[3]);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
const socket = new WebSocket(url);
|
|
127
|
+
socket.binaryType = 'arraybuffer';
|
|
128
|
+
const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
|
|
129
|
+
const checkBufferedAmount = () => {
|
|
130
|
+
if (socket.readyState != 1)
|
|
131
|
+
return;
|
|
132
|
+
// Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
|
|
133
|
+
// of all the data that has been sent, but that might not be the case. For this
|
|
134
|
+
// reason, we use `bufferedAmount` as a hint rather than a correct value.
|
|
135
|
+
const bufferedAmount = socket.bufferedAmount;
|
|
136
|
+
let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
|
|
137
|
+
if (wasSent < 0)
|
|
138
|
+
wasSent = 0;
|
|
139
|
+
bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
|
|
140
|
+
if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
|
|
141
|
+
setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
|
|
142
|
+
bufferedAmountCheck.nextTimeout *= 2;
|
|
143
|
+
if (bufferedAmountCheck.nextTimeout > 500)
|
|
144
|
+
bufferedAmountCheck.nextTimeout = 500;
|
|
145
|
+
}
|
|
146
|
+
// Note: it is important to call `onWritableBytes` at the very end, as it might
|
|
147
|
+
// trigger a call to `send`.
|
|
148
|
+
if (wasSent != 0)
|
|
149
|
+
config.onWritableBytes(wasSent);
|
|
130
150
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
151
|
+
socket.onopen = () => {
|
|
152
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
|
|
134
153
|
};
|
|
135
|
-
|
|
154
|
+
socket.onclose = (event) => {
|
|
136
155
|
const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
|
|
137
156
|
config.onConnectionReset(message);
|
|
138
157
|
};
|
|
139
|
-
|
|
158
|
+
socket.onmessage = (msg) => {
|
|
140
159
|
config.onMessage(new Uint8Array(msg.data));
|
|
141
160
|
};
|
|
161
|
+
return {
|
|
162
|
+
reset: () => {
|
|
163
|
+
// We can't set these fields to null because the TypeScript definitions don't
|
|
164
|
+
// allow it, but we can set them to dummy values.
|
|
165
|
+
socket.onopen = () => { };
|
|
166
|
+
socket.onclose = () => { };
|
|
167
|
+
socket.onmessage = () => { };
|
|
168
|
+
socket.onerror = () => { };
|
|
169
|
+
socket.close();
|
|
170
|
+
},
|
|
171
|
+
send: (data) => {
|
|
172
|
+
// The WebSocket library that we use seems to spontaneously transition connections
|
|
173
|
+
// to the "closed" state but not call the `onclosed` callback immediately. Calling
|
|
174
|
+
// `send` on that object throws an exception. In order to avoid panicking smoldot,
|
|
175
|
+
// we thus absorb any exception thrown here.
|
|
176
|
+
// See also <https://github.com/paritytech/smoldot/issues/2937>.
|
|
177
|
+
try {
|
|
178
|
+
socket.send(data);
|
|
179
|
+
if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
|
|
180
|
+
bufferedAmountCheck.nextTimeout = 10;
|
|
181
|
+
setTimeout(checkBufferedAmount, 10);
|
|
182
|
+
}
|
|
183
|
+
bufferedAmountCheck.quenedUnreportedBytes += data.length;
|
|
184
|
+
}
|
|
185
|
+
catch (_error) { }
|
|
186
|
+
},
|
|
187
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
188
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
189
|
+
};
|
|
142
190
|
}
|
|
143
191
|
else if (tcpParsed != null) {
|
|
144
|
-
// `net` module will be missing when we're not in NodeJS.
|
|
145
192
|
if (forbidTcp) {
|
|
146
193
|
throw new instance_js_1.ConnectionError('TCP connections not available');
|
|
147
194
|
}
|
|
@@ -156,13 +203,12 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
156
203
|
return null;
|
|
157
204
|
})
|
|
158
205
|
};
|
|
159
|
-
connection = { ty: 'tcp', socket };
|
|
160
206
|
socket.inner = socket.inner.then((established) => {
|
|
161
207
|
// TODO: at the time of writing of this comment, `setNoDelay` is still unstable
|
|
162
208
|
//established.setNoDelay();
|
|
163
209
|
if (socket.destroyed)
|
|
164
210
|
return established;
|
|
165
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
211
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: true });
|
|
166
212
|
// Spawns an asynchronous task that continuously reads from the socket.
|
|
167
213
|
// Every time data is read, the task re-executes itself in order to continue reading.
|
|
168
214
|
// The task ends automatically if an EOF or error is detected, which should also happen
|
|
@@ -194,53 +240,21 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
194
240
|
read(new Uint8Array(1024));
|
|
195
241
|
return established;
|
|
196
242
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (connection.ty == 'websocket') {
|
|
204
|
-
// WebSocket
|
|
205
|
-
// We can't set these fields to null because the TypeScript definitions don't
|
|
206
|
-
// allow it, but we can set them to dummy values.
|
|
207
|
-
connection.socket.onopen = () => { };
|
|
208
|
-
connection.socket.onclose = () => { };
|
|
209
|
-
connection.socket.onmessage = () => { };
|
|
210
|
-
connection.socket.onerror = () => { };
|
|
211
|
-
connection.socket.close();
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
// TCP
|
|
215
|
-
connection.socket.destroyed = true;
|
|
216
|
-
connection.socket.inner.then((connec) => connec.close());
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
send: (data) => {
|
|
220
|
-
if (connection.ty == 'websocket') {
|
|
221
|
-
// WebSocket
|
|
222
|
-
// The WebSocket library that we use seems to spontaneously transition connections
|
|
223
|
-
// to the "closed" state but not call the `onclosed` callback immediately. Calling
|
|
224
|
-
// `send` on that object throws an exception. In order to avoid panicking smoldot,
|
|
225
|
-
// we thus absorb any exception thrown here.
|
|
226
|
-
// See also <https://github.com/paritytech/smoldot/issues/2937>.
|
|
227
|
-
try {
|
|
228
|
-
connection.socket.send(data);
|
|
229
|
-
}
|
|
230
|
-
catch (_error) { }
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
// TCP
|
|
234
|
-
// TODO: at the moment, sending data doesn't have any back-pressure mechanism; as such, we just buffer data indefinitely
|
|
243
|
+
return {
|
|
244
|
+
reset: () => {
|
|
245
|
+
socket.destroyed = true;
|
|
246
|
+
socket.inner.then((connec) => connec.close());
|
|
247
|
+
},
|
|
248
|
+
send: (data) => {
|
|
235
249
|
let dataCopy = Uint8Array.from(data); // Deep copy of the data
|
|
236
|
-
|
|
237
|
-
connection.socket.inner = connection.socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
250
|
+
socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
238
251
|
while (dataCopy.length > 0) {
|
|
239
252
|
if (socket.destroyed || c === null)
|
|
240
253
|
return c;
|
|
241
254
|
let outcome;
|
|
242
255
|
try {
|
|
243
256
|
outcome = yield c.write(dataCopy);
|
|
257
|
+
config.onWritableBytes(dataCopy.length);
|
|
244
258
|
}
|
|
245
259
|
catch (error) {
|
|
246
260
|
// The type of `error` is unclear, but we assume that it implements `Error`
|
|
@@ -260,8 +274,17 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
260
274
|
}
|
|
261
275
|
return c;
|
|
262
276
|
}));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
277
|
+
},
|
|
278
|
+
closeSend: () => {
|
|
279
|
+
socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
280
|
+
yield (c === null || c === void 0 ? void 0 : c.closeWrite());
|
|
281
|
+
return c;
|
|
282
|
+
}));
|
|
283
|
+
},
|
|
284
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
throw new instance_js_1.ConnectionError('Unrecognized multiaddr format');
|
|
289
|
+
}
|
|
267
290
|
}
|
package/dist/cjs/index-nodejs.js
CHANGED
|
@@ -51,7 +51,7 @@ function start(options) {
|
|
|
51
51
|
return node_perf_hooks_1.performance.now();
|
|
52
52
|
},
|
|
53
53
|
getRandomValues: (buffer) => {
|
|
54
|
-
if (buffer.length >=
|
|
54
|
+
if (buffer.length >= 1024 * 1024)
|
|
55
55
|
throw new Error('getRandomValues buffer too large');
|
|
56
56
|
(0, node_crypto_1.randomFillSync)(buffer);
|
|
57
57
|
},
|
|
@@ -68,7 +68,6 @@ exports.start = start;
|
|
|
68
68
|
* @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
|
|
69
69
|
*/
|
|
70
70
|
function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
71
|
-
let connection;
|
|
72
71
|
// Attempt to parse the multiaddress.
|
|
73
72
|
// TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940)
|
|
74
73
|
const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/);
|
|
@@ -85,8 +84,33 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
85
84
|
(proto + "://" + wsParsed[2] + ":" + wsParsed[3]);
|
|
86
85
|
const socket = new ws_1.WebSocket(url);
|
|
87
86
|
socket.binaryType = 'arraybuffer';
|
|
87
|
+
const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
|
|
88
|
+
const checkBufferedAmount = () => {
|
|
89
|
+
if (socket.readyState != 1)
|
|
90
|
+
return;
|
|
91
|
+
// Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
|
|
92
|
+
// of all the data that has been sent, but that seems to not be the case. It is
|
|
93
|
+
// unclear whether this is intended or a bug, but is is likely that `bufferedAmount`
|
|
94
|
+
// also includes WebSocket headers. For this reason, we use `bufferedAmount` as a hint
|
|
95
|
+
// rather than a correct value.
|
|
96
|
+
const bufferedAmount = socket.bufferedAmount;
|
|
97
|
+
let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
|
|
98
|
+
if (wasSent < 0)
|
|
99
|
+
wasSent = 0;
|
|
100
|
+
bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
|
|
101
|
+
if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
|
|
102
|
+
setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
|
|
103
|
+
bufferedAmountCheck.nextTimeout *= 2;
|
|
104
|
+
if (bufferedAmountCheck.nextTimeout > 500)
|
|
105
|
+
bufferedAmountCheck.nextTimeout = 500;
|
|
106
|
+
}
|
|
107
|
+
// Note: it is important to call `onWritableBytes` at the very end, as it might
|
|
108
|
+
// trigger a call to `send`.
|
|
109
|
+
if (wasSent != 0)
|
|
110
|
+
config.onWritableBytes(wasSent);
|
|
111
|
+
};
|
|
88
112
|
socket.onopen = () => {
|
|
89
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
113
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
|
|
90
114
|
};
|
|
91
115
|
socket.onclose = (event) => {
|
|
92
116
|
const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
|
|
@@ -106,7 +130,27 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
106
130
|
socket.onmessage = (msg) => {
|
|
107
131
|
config.onMessage(new Uint8Array(msg.data));
|
|
108
132
|
};
|
|
109
|
-
|
|
133
|
+
return {
|
|
134
|
+
reset: () => {
|
|
135
|
+
// We can't set these fields to null because the TypeScript definitions don't
|
|
136
|
+
// allow it, but we can set them to dummy values.
|
|
137
|
+
socket.onopen = () => { };
|
|
138
|
+
socket.onclose = () => { };
|
|
139
|
+
socket.onmessage = () => { };
|
|
140
|
+
socket.onerror = () => { };
|
|
141
|
+
socket.close();
|
|
142
|
+
},
|
|
143
|
+
send: (data) => {
|
|
144
|
+
socket.send(data);
|
|
145
|
+
if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
|
|
146
|
+
bufferedAmountCheck.nextTimeout = 10;
|
|
147
|
+
setTimeout(checkBufferedAmount, 10);
|
|
148
|
+
}
|
|
149
|
+
bufferedAmountCheck.quenedUnreportedBytes += data.length;
|
|
150
|
+
},
|
|
151
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
152
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
153
|
+
};
|
|
110
154
|
}
|
|
111
155
|
else if (tcpParsed != null) {
|
|
112
156
|
// `net` module will be missing when we're not in NodeJS.
|
|
@@ -117,14 +161,18 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
117
161
|
host: tcpParsed[2],
|
|
118
162
|
port: parseInt(tcpParsed[3], 10),
|
|
119
163
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
164
|
+
// Number of bytes queued using `socket.write` and where `write` has returned false.
|
|
165
|
+
const drainingBytes = { num: 0 };
|
|
166
|
+
socket.setNoDelay();
|
|
167
|
+
socket.on('connect', () => {
|
|
123
168
|
if (socket.destroyed)
|
|
124
169
|
return;
|
|
125
|
-
config.onOpen({
|
|
170
|
+
config.onOpen({
|
|
171
|
+
type: 'single-stream', handshake: 'multistream-select-noise-yamux',
|
|
172
|
+
initialWritableBytes: socket.writableHighWaterMark, writeClosable: true
|
|
173
|
+
});
|
|
126
174
|
});
|
|
127
|
-
|
|
175
|
+
socket.on('close', (hasError) => {
|
|
128
176
|
if (socket.destroyed)
|
|
129
177
|
return;
|
|
130
178
|
// NodeJS doesn't provide a reason why the closing happened, but only
|
|
@@ -132,43 +180,46 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
132
180
|
const message = hasError ? "Error" : "Closed gracefully";
|
|
133
181
|
config.onConnectionReset(message);
|
|
134
182
|
});
|
|
135
|
-
|
|
136
|
-
|
|
183
|
+
socket.on('error', () => { });
|
|
184
|
+
socket.on('data', (message) => {
|
|
137
185
|
if (socket.destroyed)
|
|
138
186
|
return;
|
|
139
187
|
config.onMessage(new Uint8Array(message.buffer));
|
|
140
188
|
});
|
|
189
|
+
socket.on('drain', () => {
|
|
190
|
+
// The bytes queued using `socket.write` and where `write` has returned false have now
|
|
191
|
+
// been sent. Notify the API that it can write more data.
|
|
192
|
+
if (socket.destroyed)
|
|
193
|
+
return;
|
|
194
|
+
const val = drainingBytes.num;
|
|
195
|
+
drainingBytes.num = 0;
|
|
196
|
+
config.onWritableBytes(val);
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
reset: () => {
|
|
200
|
+
socket.destroy();
|
|
201
|
+
},
|
|
202
|
+
send: (data) => {
|
|
203
|
+
const dataLen = data.length;
|
|
204
|
+
const allWritten = socket.write(data);
|
|
205
|
+
if (allWritten) {
|
|
206
|
+
setImmediate(() => {
|
|
207
|
+
if (!socket.writable)
|
|
208
|
+
return;
|
|
209
|
+
config.onWritableBytes(dataLen);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
drainingBytes.num += dataLen;
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
closeSend: () => {
|
|
217
|
+
socket.end();
|
|
218
|
+
},
|
|
219
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
220
|
+
};
|
|
141
221
|
}
|
|
142
222
|
else {
|
|
143
223
|
throw new instance_js_1.ConnectionError('Unrecognized multiaddr format');
|
|
144
224
|
}
|
|
145
|
-
return {
|
|
146
|
-
reset: () => {
|
|
147
|
-
if (connection.ty == 'websocket') {
|
|
148
|
-
// WebSocket
|
|
149
|
-
// We can't set these fields to null because the TypeScript definitions don't
|
|
150
|
-
// allow it, but we can set them to dummy values.
|
|
151
|
-
connection.socket.onopen = () => { };
|
|
152
|
-
connection.socket.onclose = () => { };
|
|
153
|
-
connection.socket.onmessage = () => { };
|
|
154
|
-
connection.socket.onerror = () => { };
|
|
155
|
-
connection.socket.close();
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// TCP
|
|
159
|
-
connection.socket.destroy();
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
send: (data) => {
|
|
163
|
-
if (connection.ty == 'websocket') {
|
|
164
|
-
// WebSocket
|
|
165
|
-
connection.socket.send(data);
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
// TCP
|
|
169
|
-
connection.socket.write(data);
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
173
|
-
};
|
|
174
225
|
}
|