smoldot 0.7.13 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client.d.ts +61 -28
- package/dist/cjs/index-browser.js +66 -19
- package/dist/cjs/index-deno.js +85 -58
- 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 +36 -2
- package/dist/cjs/instance/bindings-smoldot-light.js +18 -4
- package/dist/cjs/instance/bindings.d.ts +3 -2
- package/dist/mjs/client.d.ts +61 -28
- package/dist/mjs/index-browser.js +66 -19
- package/dist/mjs/index-deno.js +85 -58
- 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 +36 -2
- package/dist/mjs/instance/bindings-smoldot-light.js +18 -4
- package/dist/mjs/instance/bindings.d.ts +3 -2
- package/package.json +2 -2
package/dist/mjs/index-deno.js
CHANGED
|
@@ -99,7 +99,6 @@ function trustedBase64Decode(base64) {
|
|
|
99
99
|
* @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
|
|
100
100
|
*/
|
|
101
101
|
function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
102
|
-
let connection;
|
|
103
102
|
// Attempt to parse the multiaddress.
|
|
104
103
|
// TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940)
|
|
105
104
|
const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/);
|
|
@@ -114,24 +113,72 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
114
113
|
const url = (wsParsed[1] == 'ip6') ?
|
|
115
114
|
(proto + "://[" + wsParsed[2] + "]:" + wsParsed[3]) :
|
|
116
115
|
(proto + "://" + wsParsed[2] + ":" + wsParsed[3]);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
const socket = new WebSocket(url);
|
|
117
|
+
socket.binaryType = 'arraybuffer';
|
|
118
|
+
const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
|
|
119
|
+
const checkBufferedAmount = () => {
|
|
120
|
+
if (socket.readyState != 1)
|
|
121
|
+
return;
|
|
122
|
+
// Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
|
|
123
|
+
// of all the data that has been sent, but that might not be the case. For this
|
|
124
|
+
// reason, we use `bufferedAmount` as a hint rather than a correct value.
|
|
125
|
+
const bufferedAmount = socket.bufferedAmount;
|
|
126
|
+
let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
|
|
127
|
+
if (wasSent < 0)
|
|
128
|
+
wasSent = 0;
|
|
129
|
+
bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
|
|
130
|
+
if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
|
|
131
|
+
setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
|
|
132
|
+
bufferedAmountCheck.nextTimeout *= 2;
|
|
133
|
+
if (bufferedAmountCheck.nextTimeout > 500)
|
|
134
|
+
bufferedAmountCheck.nextTimeout = 500;
|
|
135
|
+
}
|
|
136
|
+
// Note: it is important to call `onWritableBytes` at the very end, as it might
|
|
137
|
+
// trigger a call to `send`.
|
|
138
|
+
if (wasSent != 0)
|
|
139
|
+
config.onWritableBytes(wasSent);
|
|
120
140
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
141
|
+
socket.onopen = () => {
|
|
142
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
|
|
124
143
|
};
|
|
125
|
-
|
|
144
|
+
socket.onclose = (event) => {
|
|
126
145
|
const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
|
|
127
146
|
config.onConnectionReset(message);
|
|
128
147
|
};
|
|
129
|
-
|
|
148
|
+
socket.onmessage = (msg) => {
|
|
130
149
|
config.onMessage(new Uint8Array(msg.data));
|
|
131
150
|
};
|
|
151
|
+
return {
|
|
152
|
+
reset: () => {
|
|
153
|
+
// We can't set these fields to null because the TypeScript definitions don't
|
|
154
|
+
// allow it, but we can set them to dummy values.
|
|
155
|
+
socket.onopen = () => { };
|
|
156
|
+
socket.onclose = () => { };
|
|
157
|
+
socket.onmessage = () => { };
|
|
158
|
+
socket.onerror = () => { };
|
|
159
|
+
socket.close();
|
|
160
|
+
},
|
|
161
|
+
send: (data) => {
|
|
162
|
+
// The WebSocket library that we use seems to spontaneously transition connections
|
|
163
|
+
// to the "closed" state but not call the `onclosed` callback immediately. Calling
|
|
164
|
+
// `send` on that object throws an exception. In order to avoid panicking smoldot,
|
|
165
|
+
// we thus absorb any exception thrown here.
|
|
166
|
+
// See also <https://github.com/paritytech/smoldot/issues/2937>.
|
|
167
|
+
try {
|
|
168
|
+
socket.send(data);
|
|
169
|
+
if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
|
|
170
|
+
bufferedAmountCheck.nextTimeout = 10;
|
|
171
|
+
setTimeout(checkBufferedAmount, 10);
|
|
172
|
+
}
|
|
173
|
+
bufferedAmountCheck.quenedUnreportedBytes += data.length;
|
|
174
|
+
}
|
|
175
|
+
catch (_error) { }
|
|
176
|
+
},
|
|
177
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
178
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
179
|
+
};
|
|
132
180
|
}
|
|
133
181
|
else if (tcpParsed != null) {
|
|
134
|
-
// `net` module will be missing when we're not in NodeJS.
|
|
135
182
|
if (forbidTcp) {
|
|
136
183
|
throw new ConnectionError('TCP connections not available');
|
|
137
184
|
}
|
|
@@ -140,21 +187,24 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
140
187
|
inner: Deno.connect({
|
|
141
188
|
hostname: tcpParsed[2],
|
|
142
189
|
port: parseInt(tcpParsed[3], 10),
|
|
190
|
+
}).catch((error) => {
|
|
191
|
+
socket.destroyed = true;
|
|
192
|
+
config.onConnectionReset(error.toString());
|
|
193
|
+
return null;
|
|
143
194
|
})
|
|
144
195
|
};
|
|
145
|
-
connection = { ty: 'tcp', socket };
|
|
146
196
|
socket.inner = socket.inner.then((established) => {
|
|
147
197
|
// TODO: at the time of writing of this comment, `setNoDelay` is still unstable
|
|
148
198
|
//established.setNoDelay();
|
|
149
199
|
if (socket.destroyed)
|
|
150
200
|
return established;
|
|
151
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
201
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: true });
|
|
152
202
|
// Spawns an asynchronous task that continuously reads from the socket.
|
|
153
203
|
// Every time data is read, the task re-executes itself in order to continue reading.
|
|
154
204
|
// The task ends automatically if an EOF or error is detected, which should also happen
|
|
155
205
|
// if the user calls `close()`.
|
|
156
206
|
const read = (readBuffer) => __awaiter(this, void 0, void 0, function* () {
|
|
157
|
-
if (socket.destroyed)
|
|
207
|
+
if (socket.destroyed || established === null)
|
|
158
208
|
return;
|
|
159
209
|
let outcome = null;
|
|
160
210
|
try {
|
|
@@ -180,53 +230,21 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
180
230
|
read(new Uint8Array(1024));
|
|
181
231
|
return established;
|
|
182
232
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (connection.ty == 'websocket') {
|
|
190
|
-
// WebSocket
|
|
191
|
-
// We can't set these fields to null because the TypeScript definitions don't
|
|
192
|
-
// allow it, but we can set them to dummy values.
|
|
193
|
-
connection.socket.onopen = () => { };
|
|
194
|
-
connection.socket.onclose = () => { };
|
|
195
|
-
connection.socket.onmessage = () => { };
|
|
196
|
-
connection.socket.onerror = () => { };
|
|
197
|
-
connection.socket.close();
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
// TCP
|
|
201
|
-
connection.socket.destroyed = true;
|
|
202
|
-
connection.socket.inner.then((connec) => connec.close());
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
send: (data) => {
|
|
206
|
-
if (connection.ty == 'websocket') {
|
|
207
|
-
// WebSocket
|
|
208
|
-
// The WebSocket library that we use seems to spontaneously transition connections
|
|
209
|
-
// to the "closed" state but not call the `onclosed` callback immediately. Calling
|
|
210
|
-
// `send` on that object throws an exception. In order to avoid panicking smoldot,
|
|
211
|
-
// we thus absorb any exception thrown here.
|
|
212
|
-
// See also <https://github.com/paritytech/smoldot/issues/2937>.
|
|
213
|
-
try {
|
|
214
|
-
connection.socket.send(data);
|
|
215
|
-
}
|
|
216
|
-
catch (_error) { }
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
// TCP
|
|
220
|
-
// TODO: at the moment, sending data doesn't have any back-pressure mechanism; as such, we just buffer data indefinitely
|
|
233
|
+
return {
|
|
234
|
+
reset: () => {
|
|
235
|
+
socket.destroyed = true;
|
|
236
|
+
socket.inner.then((connec) => connec.close());
|
|
237
|
+
},
|
|
238
|
+
send: (data) => {
|
|
221
239
|
let dataCopy = Uint8Array.from(data); // Deep copy of the data
|
|
222
|
-
|
|
223
|
-
connection.socket.inner = connection.socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
240
|
+
socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
224
241
|
while (dataCopy.length > 0) {
|
|
225
|
-
if (socket.destroyed)
|
|
242
|
+
if (socket.destroyed || c === null)
|
|
226
243
|
return c;
|
|
227
244
|
let outcome;
|
|
228
245
|
try {
|
|
229
246
|
outcome = yield c.write(dataCopy);
|
|
247
|
+
config.onWritableBytes(dataCopy.length);
|
|
230
248
|
}
|
|
231
249
|
catch (error) {
|
|
232
250
|
// The type of `error` is unclear, but we assume that it implements `Error`
|
|
@@ -246,8 +264,17 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
246
264
|
}
|
|
247
265
|
return c;
|
|
248
266
|
}));
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
},
|
|
268
|
+
closeSend: () => {
|
|
269
|
+
socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
|
|
270
|
+
yield (c === null || c === void 0 ? void 0 : c.closeWrite());
|
|
271
|
+
return c;
|
|
272
|
+
}));
|
|
273
|
+
},
|
|
274
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
throw new ConnectionError('Unrecognized multiaddr format');
|
|
279
|
+
}
|
|
253
280
|
}
|
package/dist/mjs/index-nodejs.js
CHANGED
|
@@ -42,7 +42,7 @@ export function start(options) {
|
|
|
42
42
|
return performance.now();
|
|
43
43
|
},
|
|
44
44
|
getRandomValues: (buffer) => {
|
|
45
|
-
if (buffer.length >=
|
|
45
|
+
if (buffer.length >= 1024 * 1024)
|
|
46
46
|
throw new Error('getRandomValues buffer too large');
|
|
47
47
|
randomFillSync(buffer);
|
|
48
48
|
},
|
|
@@ -58,7 +58,6 @@ export function start(options) {
|
|
|
58
58
|
* @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
|
|
59
59
|
*/
|
|
60
60
|
function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
61
|
-
let connection;
|
|
62
61
|
// Attempt to parse the multiaddress.
|
|
63
62
|
// TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940)
|
|
64
63
|
const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/);
|
|
@@ -75,8 +74,33 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
75
74
|
(proto + "://" + wsParsed[2] + ":" + wsParsed[3]);
|
|
76
75
|
const socket = new WebSocket(url);
|
|
77
76
|
socket.binaryType = 'arraybuffer';
|
|
77
|
+
const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
|
|
78
|
+
const checkBufferedAmount = () => {
|
|
79
|
+
if (socket.readyState != 1)
|
|
80
|
+
return;
|
|
81
|
+
// Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
|
|
82
|
+
// of all the data that has been sent, but that seems to not be the case. It is
|
|
83
|
+
// unclear whether this is intended or a bug, but is is likely that `bufferedAmount`
|
|
84
|
+
// also includes WebSocket headers. For this reason, we use `bufferedAmount` as a hint
|
|
85
|
+
// rather than a correct value.
|
|
86
|
+
const bufferedAmount = socket.bufferedAmount;
|
|
87
|
+
let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
|
|
88
|
+
if (wasSent < 0)
|
|
89
|
+
wasSent = 0;
|
|
90
|
+
bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
|
|
91
|
+
if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
|
|
92
|
+
setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
|
|
93
|
+
bufferedAmountCheck.nextTimeout *= 2;
|
|
94
|
+
if (bufferedAmountCheck.nextTimeout > 500)
|
|
95
|
+
bufferedAmountCheck.nextTimeout = 500;
|
|
96
|
+
}
|
|
97
|
+
// Note: it is important to call `onWritableBytes` at the very end, as it might
|
|
98
|
+
// trigger a call to `send`.
|
|
99
|
+
if (wasSent != 0)
|
|
100
|
+
config.onWritableBytes(wasSent);
|
|
101
|
+
};
|
|
78
102
|
socket.onopen = () => {
|
|
79
|
-
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux' });
|
|
103
|
+
config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
|
|
80
104
|
};
|
|
81
105
|
socket.onclose = (event) => {
|
|
82
106
|
const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
|
|
@@ -96,7 +120,27 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
96
120
|
socket.onmessage = (msg) => {
|
|
97
121
|
config.onMessage(new Uint8Array(msg.data));
|
|
98
122
|
};
|
|
99
|
-
|
|
123
|
+
return {
|
|
124
|
+
reset: () => {
|
|
125
|
+
// We can't set these fields to null because the TypeScript definitions don't
|
|
126
|
+
// allow it, but we can set them to dummy values.
|
|
127
|
+
socket.onopen = () => { };
|
|
128
|
+
socket.onclose = () => { };
|
|
129
|
+
socket.onmessage = () => { };
|
|
130
|
+
socket.onerror = () => { };
|
|
131
|
+
socket.close();
|
|
132
|
+
},
|
|
133
|
+
send: (data) => {
|
|
134
|
+
socket.send(data);
|
|
135
|
+
if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
|
|
136
|
+
bufferedAmountCheck.nextTimeout = 10;
|
|
137
|
+
setTimeout(checkBufferedAmount, 10);
|
|
138
|
+
}
|
|
139
|
+
bufferedAmountCheck.quenedUnreportedBytes += data.length;
|
|
140
|
+
},
|
|
141
|
+
closeSend: () => { throw new Error('Wrong connection type'); },
|
|
142
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
143
|
+
};
|
|
100
144
|
}
|
|
101
145
|
else if (tcpParsed != null) {
|
|
102
146
|
// `net` module will be missing when we're not in NodeJS.
|
|
@@ -107,14 +151,18 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
107
151
|
host: tcpParsed[2],
|
|
108
152
|
port: parseInt(tcpParsed[3], 10),
|
|
109
153
|
});
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
154
|
+
// Number of bytes queued using `socket.write` and where `write` has returned false.
|
|
155
|
+
const drainingBytes = { num: 0 };
|
|
156
|
+
socket.setNoDelay();
|
|
157
|
+
socket.on('connect', () => {
|
|
113
158
|
if (socket.destroyed)
|
|
114
159
|
return;
|
|
115
|
-
config.onOpen({
|
|
160
|
+
config.onOpen({
|
|
161
|
+
type: 'single-stream', handshake: 'multistream-select-noise-yamux',
|
|
162
|
+
initialWritableBytes: socket.writableHighWaterMark, writeClosable: true
|
|
163
|
+
});
|
|
116
164
|
});
|
|
117
|
-
|
|
165
|
+
socket.on('close', (hasError) => {
|
|
118
166
|
if (socket.destroyed)
|
|
119
167
|
return;
|
|
120
168
|
// NodeJS doesn't provide a reason why the closing happened, but only
|
|
@@ -122,43 +170,46 @@ function connect(config, forbidTcp, forbidWs, forbidNonLocalWs, forbidWss) {
|
|
|
122
170
|
const message = hasError ? "Error" : "Closed gracefully";
|
|
123
171
|
config.onConnectionReset(message);
|
|
124
172
|
});
|
|
125
|
-
|
|
126
|
-
|
|
173
|
+
socket.on('error', () => { });
|
|
174
|
+
socket.on('data', (message) => {
|
|
127
175
|
if (socket.destroyed)
|
|
128
176
|
return;
|
|
129
177
|
config.onMessage(new Uint8Array(message.buffer));
|
|
130
178
|
});
|
|
179
|
+
socket.on('drain', () => {
|
|
180
|
+
// The bytes queued using `socket.write` and where `write` has returned false have now
|
|
181
|
+
// been sent. Notify the API that it can write more data.
|
|
182
|
+
if (socket.destroyed)
|
|
183
|
+
return;
|
|
184
|
+
const val = drainingBytes.num;
|
|
185
|
+
drainingBytes.num = 0;
|
|
186
|
+
config.onWritableBytes(val);
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
reset: () => {
|
|
190
|
+
socket.destroy();
|
|
191
|
+
},
|
|
192
|
+
send: (data) => {
|
|
193
|
+
const dataLen = data.length;
|
|
194
|
+
const allWritten = socket.write(data);
|
|
195
|
+
if (allWritten) {
|
|
196
|
+
setImmediate(() => {
|
|
197
|
+
if (!socket.writable)
|
|
198
|
+
return;
|
|
199
|
+
config.onWritableBytes(dataLen);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
drainingBytes.num += dataLen;
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
closeSend: () => {
|
|
207
|
+
socket.end();
|
|
208
|
+
},
|
|
209
|
+
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
210
|
+
};
|
|
131
211
|
}
|
|
132
212
|
else {
|
|
133
213
|
throw new ConnectionError('Unrecognized multiaddr format');
|
|
134
214
|
}
|
|
135
|
-
return {
|
|
136
|
-
reset: () => {
|
|
137
|
-
if (connection.ty == 'websocket') {
|
|
138
|
-
// WebSocket
|
|
139
|
-
// We can't set these fields to null because the TypeScript definitions don't
|
|
140
|
-
// allow it, but we can set them to dummy values.
|
|
141
|
-
connection.socket.onopen = () => { };
|
|
142
|
-
connection.socket.onclose = () => { };
|
|
143
|
-
connection.socket.onmessage = () => { };
|
|
144
|
-
connection.socket.onerror = () => { };
|
|
145
|
-
connection.socket.close();
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// TCP
|
|
149
|
-
connection.socket.destroy();
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
send: (data) => {
|
|
153
|
-
if (connection.ty == 'websocket') {
|
|
154
|
-
// WebSocket
|
|
155
|
-
connection.socket.send(data);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// TCP
|
|
159
|
-
connection.socket.write(data);
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
openOutSubstream: () => { throw new Error('Wrong connection type'); }
|
|
163
|
-
};
|
|
164
215
|
}
|