tasmota-webserial-esptool 7.1.0 → 7.2.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/README.md +1 -1
- package/css/style.css +95 -0
- package/dist/const.js +0 -24
- package/dist/esp_loader.d.ts +2 -0
- package/dist/esp_loader.js +40 -46
- package/dist/web/index.js +1 -1
- package/index.html +12 -1
- package/js/modules/esptool.js +1 -1
- package/js/script.js +64 -1
- package/package.json +7 -7
- package/src/const.ts +0 -24
- package/src/esp_loader.ts +51 -58
- package/.prettierignore +0 -1
- package/rollup.config.js +0 -27
- package/tsconfig.json +0 -20
package/README.md
CHANGED
package/css/style.css
CHANGED
|
@@ -70,6 +70,24 @@
|
|
|
70
70
|
color: #000;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
.header button.highlight {
|
|
74
|
+
background-color: #ff6b00;
|
|
75
|
+
border-color: #ff6b00;
|
|
76
|
+
color: #fff;
|
|
77
|
+
animation: pulse 1.5s infinite;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@keyframes pulse {
|
|
81
|
+
0%, 100% {
|
|
82
|
+
transform: scale(1);
|
|
83
|
+
box-shadow: 0 0 0 0 rgba(255, 107, 0, 0.7);
|
|
84
|
+
}
|
|
85
|
+
50% {
|
|
86
|
+
transform: scale(1.05);
|
|
87
|
+
box-shadow: 0 0 0 10px rgba(255, 107, 0, 0);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
73
91
|
.header select {
|
|
74
92
|
height: 30px;
|
|
75
93
|
}
|
|
@@ -550,3 +568,80 @@ div.clear {
|
|
|
550
568
|
.center {
|
|
551
569
|
text-align: center;
|
|
552
570
|
}
|
|
571
|
+
|
|
572
|
+
/* ESP32-S2 Reconnect Modal */
|
|
573
|
+
.modal {
|
|
574
|
+
display: flex;
|
|
575
|
+
position: fixed;
|
|
576
|
+
z-index: 9999;
|
|
577
|
+
left: 0;
|
|
578
|
+
top: 0;
|
|
579
|
+
width: 100%;
|
|
580
|
+
height: 100%;
|
|
581
|
+
background-color: rgba(0, 0, 0, 0.7);
|
|
582
|
+
align-items: center;
|
|
583
|
+
justify-content: center;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.modal.hidden {
|
|
587
|
+
display: none;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.modal-content {
|
|
591
|
+
background-color: #fff;
|
|
592
|
+
padding: 40px;
|
|
593
|
+
border-radius: 15px;
|
|
594
|
+
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.3);
|
|
595
|
+
text-align: center;
|
|
596
|
+
max-width: 500px;
|
|
597
|
+
animation: modalSlideIn 0.3s ease-out;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
@keyframes modalSlideIn {
|
|
601
|
+
from {
|
|
602
|
+
transform: translateY(-50px);
|
|
603
|
+
opacity: 0;
|
|
604
|
+
}
|
|
605
|
+
to {
|
|
606
|
+
transform: translateY(0);
|
|
607
|
+
opacity: 1;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.modal-content h2 {
|
|
612
|
+
color: #4a4a4a;
|
|
613
|
+
margin-top: 0;
|
|
614
|
+
font-size: 24px;
|
|
615
|
+
margin-bottom: 20px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.modal-content p {
|
|
619
|
+
font-size: 16px;
|
|
620
|
+
line-height: 1.6;
|
|
621
|
+
margin: 15px 0;
|
|
622
|
+
color: #333;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.modal-button {
|
|
626
|
+
background-color: #fff;
|
|
627
|
+
color: #6b6b6b;
|
|
628
|
+
border: 2px solid #6b6b6b;
|
|
629
|
+
padding: 12px 40px;
|
|
630
|
+
font-size: 18px;
|
|
631
|
+
font-weight: 600;
|
|
632
|
+
border-radius: 25px;
|
|
633
|
+
cursor: pointer;
|
|
634
|
+
margin-top: 20px;
|
|
635
|
+
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
|
|
636
|
+
display: inline-flex;
|
|
637
|
+
align-items: center;
|
|
638
|
+
justify-content: center;
|
|
639
|
+
line-height: normal;
|
|
640
|
+
text-align: center;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.modal-button:hover {
|
|
644
|
+
background-color: #71ae1e;
|
|
645
|
+
color: #fff;
|
|
646
|
+
border-color: #71ae1e;
|
|
647
|
+
}
|
package/dist/const.js
CHANGED
|
@@ -244,30 +244,6 @@ export const CHIP_DETECT_MAGIC_VALUES = {
|
|
|
244
244
|
0xfff0c101: { name: "ESP8266", family: CHIP_FAMILY_ESP8266 },
|
|
245
245
|
0x00f01d83: { name: "ESP32", family: CHIP_FAMILY_ESP32 },
|
|
246
246
|
0x000007c6: { name: "ESP32-S2", family: CHIP_FAMILY_ESP32S2 },
|
|
247
|
-
0x9: { name: "ESP32-S3", family: CHIP_FAMILY_ESP32S3 },
|
|
248
|
-
0x0c21e06f: { name: "ESP32-C2", family: CHIP_FAMILY_ESP32C2 },
|
|
249
|
-
0x6f51306f: { name: "ESP32-C2", family: CHIP_FAMILY_ESP32C2 },
|
|
250
|
-
0x7c41a06f: { name: "ESP32-C2", family: CHIP_FAMILY_ESP32C2 },
|
|
251
|
-
0x1b31506f: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 },
|
|
252
|
-
0x4361606f: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 },
|
|
253
|
-
0x4881606f: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 },
|
|
254
|
-
0x6921506f: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 },
|
|
255
|
-
0x1101406f: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 },
|
|
256
|
-
0x5fd1406f: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 },
|
|
257
|
-
0x5c501458: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 },
|
|
258
|
-
0x63e1406f: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 },
|
|
259
|
-
0x2ce0806f: { name: "ESP32-C6", family: CHIP_FAMILY_ESP32C6 },
|
|
260
|
-
0x2421606f: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 },
|
|
261
|
-
0x33f0206f: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 },
|
|
262
|
-
0x4f81606f: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 },
|
|
263
|
-
0x7211606f: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 },
|
|
264
|
-
0x97e30068: { name: "ESP32-H2", family: CHIP_FAMILY_ESP32H2 },
|
|
265
|
-
0xd7b73e80: { name: "ESP32-H2", family: CHIP_FAMILY_ESP32H2 },
|
|
266
|
-
// ESP32-P4 old revisions (< Rev. 300) - use magic value detection
|
|
267
|
-
// Rev. 300+ uses IMAGE_CHIP_ID detection instead
|
|
268
|
-
0x0: { name: "ESP32-P4", family: CHIP_FAMILY_ESP32P4 },
|
|
269
|
-
0x7039ad9: { name: "ESP32-P4", family: CHIP_FAMILY_ESP32P4 },
|
|
270
|
-
0x0addbad0: { name: "ESP32-P4", family: CHIP_FAMILY_ESP32P4 },
|
|
271
247
|
};
|
|
272
248
|
// Commands supported by ESP8266 ROM bootloader
|
|
273
249
|
export const ESP_FLASH_BEGIN = 0x02;
|
package/dist/esp_loader.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare class ESPLoader extends EventTarget {
|
|
|
18
18
|
private _currentBaudRate;
|
|
19
19
|
private _maxUSBSerialBaudrate?;
|
|
20
20
|
private _reader?;
|
|
21
|
+
private _isESP32S2NativeUSB;
|
|
22
|
+
private _initializationSucceeded;
|
|
21
23
|
constructor(port: SerialPort, logger: Logger, _parent?: ESPLoader | undefined);
|
|
22
24
|
private get _inputBuffer();
|
|
23
25
|
private get _totalBytesRead();
|
package/dist/esp_loader.js
CHANGED
|
@@ -21,6 +21,8 @@ export class ESPLoader extends EventTarget {
|
|
|
21
21
|
this.connected = true;
|
|
22
22
|
this.flashSize = null;
|
|
23
23
|
this._currentBaudRate = ESP_ROM_BAUD;
|
|
24
|
+
this._isESP32S2NativeUSB = false;
|
|
25
|
+
this._initializationSucceeded = false;
|
|
24
26
|
this.state_DTR = false;
|
|
25
27
|
}
|
|
26
28
|
get _inputBuffer() {
|
|
@@ -44,8 +46,13 @@ export class ESPLoader extends EventTarget {
|
|
|
44
46
|
const chips = {
|
|
45
47
|
0x1a86: {
|
|
46
48
|
// QinHeng Electronics
|
|
49
|
+
0x7522: { name: "CH340", maxBaudrate: 460800 },
|
|
47
50
|
0x7523: { name: "CH340", maxBaudrate: 460800 },
|
|
51
|
+
0x7584: { name: "CH340", maxBaudrate: 460800 },
|
|
52
|
+
0x5523: { name: "CH341", maxBaudrate: 2000000 },
|
|
53
|
+
0x55d3: { name: "CH343", maxBaudrate: 6000000 },
|
|
48
54
|
0x55d4: { name: "CH9102", maxBaudrate: 6000000 },
|
|
55
|
+
0x55d8: { name: "CH9101", maxBaudrate: 3000000 },
|
|
49
56
|
},
|
|
50
57
|
0x10c4: {
|
|
51
58
|
// Silicon Labs
|
|
@@ -92,6 +99,13 @@ export class ESPLoader extends EventTarget {
|
|
|
92
99
|
this._maxUSBSerialBaudrate = chipInfo.maxBaudrate;
|
|
93
100
|
this.logger.log(`Max baudrate: ${chipInfo.maxBaudrate}`);
|
|
94
101
|
}
|
|
102
|
+
// Detect ESP32-S2 Native USB
|
|
103
|
+
// PID 0x0002 = TinyUSB CDC (after flash)
|
|
104
|
+
// PID 0x1001 = ROM Bootloader (before flash)
|
|
105
|
+
if (portInfo.usbVendorId === 0x303a &&
|
|
106
|
+
(portInfo.usbProductId === 0x2 || portInfo.usbProductId === 0x1001)) {
|
|
107
|
+
this._isESP32S2NativeUSB = true;
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
// Don't await this promise so it doesn't block rest of method.
|
|
97
111
|
this.readLoop();
|
|
@@ -109,6 +123,8 @@ export class ESPLoader extends EventTarget {
|
|
|
109
123
|
}
|
|
110
124
|
this.logger.log(`Chip type ${this.chipName}`);
|
|
111
125
|
this.logger.debug(`Bootloader flash offset: 0x${FlAddr.flashOffs.toString(16)}`);
|
|
126
|
+
// Mark initialization as successful
|
|
127
|
+
this._initializationSucceeded = true;
|
|
112
128
|
}
|
|
113
129
|
/**
|
|
114
130
|
* Detect chip type using GET_SECURITY_INFO (for newer chips) or magic value (for older chips)
|
|
@@ -154,7 +170,7 @@ export class ESPLoader extends EventTarget {
|
|
|
154
170
|
this.logger.debug(`Re-sync after GET_SECURITY_INFO failure: ${syncErr}`);
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
|
-
// Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2
|
|
173
|
+
// Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2
|
|
158
174
|
const chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR);
|
|
159
175
|
const chip = CHIP_DETECT_MAGIC_VALUES[chipMagicValue >>> 0];
|
|
160
176
|
if (chip === undefined) {
|
|
@@ -162,7 +178,6 @@ export class ESPLoader extends EventTarget {
|
|
|
162
178
|
}
|
|
163
179
|
this.chipName = chip.name;
|
|
164
180
|
this.chipFamily = chip.family;
|
|
165
|
-
// For ESP32-P4 detected via magic value (old revisions), set variant
|
|
166
181
|
if (this.chipFamily === CHIP_FAMILY_ESP32P4) {
|
|
167
182
|
this.chipRevision = await this.getChipRevision();
|
|
168
183
|
this.logger.debug(`ESP32-P4 revision: ${this.chipRevision}`);
|
|
@@ -256,6 +271,14 @@ export class ESPLoader extends EventTarget {
|
|
|
256
271
|
}
|
|
257
272
|
// Disconnected!
|
|
258
273
|
this.connected = false;
|
|
274
|
+
// Check if this is ESP32-S2 Native USB that needs port reselection
|
|
275
|
+
// Only trigger reconnect if initialization did NOT succeed (wrong port)
|
|
276
|
+
if (this._isESP32S2NativeUSB && !this._initializationSucceeded) {
|
|
277
|
+
this.logger.log("ESP32-S2 Native USB detected - requesting port reselection");
|
|
278
|
+
this.dispatchEvent(new CustomEvent("esp32s2-usb-reconnect", {
|
|
279
|
+
detail: { message: "ESP32-S2 Native USB requires port reselection" },
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
259
282
|
this.dispatchEvent(new Event("disconnect"));
|
|
260
283
|
this.logger.debug("Finished read loop");
|
|
261
284
|
}
|
|
@@ -907,7 +930,7 @@ export class ESPLoader extends EventTarget {
|
|
|
907
930
|
}
|
|
908
931
|
async setDataLengths(spiAddresses, mosiBits, misoBits) {
|
|
909
932
|
if (spiAddresses.mosiDlenOffs != -1) {
|
|
910
|
-
//
|
|
933
|
+
// Actual MCUs have a more sophisticated way to set up "user" commands
|
|
911
934
|
const SPI_MOSI_DLEN_REG = spiAddresses.regBase + spiAddresses.mosiDlenOffs;
|
|
912
935
|
const SPI_MISO_DLEN_REG = spiAddresses.regBase + spiAddresses.misoDlenOffs;
|
|
913
936
|
if (mosiBits > 0) {
|
|
@@ -948,7 +971,7 @@ export class ESPLoader extends EventTarget {
|
|
|
948
971
|
const SPI_USR_COMMAND = 1 << 31;
|
|
949
972
|
const SPI_USR_MISO = 1 << 28;
|
|
950
973
|
const SPI_USR_MOSI = 1 << 27;
|
|
951
|
-
// SPI registers, base address differs
|
|
974
|
+
// SPI registers, base address differs
|
|
952
975
|
const spiAddresses = getSpiFlashAddresses(this.getChipFamily());
|
|
953
976
|
const base = spiAddresses.regBase;
|
|
954
977
|
const SPI_CMD_REG = base;
|
|
@@ -1100,6 +1123,10 @@ export class ESPLoader extends EventTarget {
|
|
|
1100
1123
|
return espStubLoader;
|
|
1101
1124
|
}
|
|
1102
1125
|
async writeToStream(data) {
|
|
1126
|
+
if (!this.port.writable) {
|
|
1127
|
+
this.logger.debug("Port writable stream not available, skipping write");
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1103
1130
|
const writer = this.port.writable.getWriter();
|
|
1104
1131
|
await writer.write(new Uint8Array(data));
|
|
1105
1132
|
try {
|
|
@@ -1114,6 +1141,10 @@ export class ESPLoader extends EventTarget {
|
|
|
1114
1141
|
await this._parent.disconnect();
|
|
1115
1142
|
return;
|
|
1116
1143
|
}
|
|
1144
|
+
if (!this.port.writable) {
|
|
1145
|
+
this.logger.debug("Port already closed, skipping disconnect");
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1117
1148
|
await this.port.writable.getWriter().close();
|
|
1118
1149
|
await new Promise((resolve) => {
|
|
1119
1150
|
if (!this._reader) {
|
|
@@ -1146,7 +1177,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1146
1177
|
}
|
|
1147
1178
|
this._reader = undefined;
|
|
1148
1179
|
}
|
|
1149
|
-
await sleep(SYNC_TIMEOUT);
|
|
1150
1180
|
// Close port
|
|
1151
1181
|
try {
|
|
1152
1182
|
await this.port.close();
|
|
@@ -1155,8 +1185,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1155
1185
|
catch (err) {
|
|
1156
1186
|
this.logger.debug(`Port close error: ${err}`);
|
|
1157
1187
|
}
|
|
1158
|
-
// Wait for port to fully close
|
|
1159
|
-
await sleep(SYNC_TIMEOUT);
|
|
1160
1188
|
// Open the port
|
|
1161
1189
|
this.logger.debug("Opening port...");
|
|
1162
1190
|
try {
|
|
@@ -1166,8 +1194,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1166
1194
|
catch (err) {
|
|
1167
1195
|
throw new Error(`Failed to open port: ${err}`);
|
|
1168
1196
|
}
|
|
1169
|
-
// Wait for port to be fully ready
|
|
1170
|
-
await sleep(SYNC_TIMEOUT);
|
|
1171
1197
|
// Verify port streams are available
|
|
1172
1198
|
if (!this.port.readable || !this.port.writable) {
|
|
1173
1199
|
throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);
|
|
@@ -1178,7 +1204,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1178
1204
|
const savedChipRevision = this.chipRevision;
|
|
1179
1205
|
const savedChipVariant = this.chipVariant;
|
|
1180
1206
|
const savedFlashSize = this.flashSize;
|
|
1181
|
-
// Reinitialize
|
|
1207
|
+
// Reinitialize
|
|
1182
1208
|
await this.hardReset(true);
|
|
1183
1209
|
if (!this._parent) {
|
|
1184
1210
|
this.__inputBuffer = [];
|
|
@@ -1187,7 +1213,7 @@ export class ESPLoader extends EventTarget {
|
|
|
1187
1213
|
}
|
|
1188
1214
|
await this.flushSerialBuffers();
|
|
1189
1215
|
await this.sync();
|
|
1190
|
-
// Restore chip info
|
|
1216
|
+
// Restore chip info
|
|
1191
1217
|
this.chipFamily = savedChipFamily;
|
|
1192
1218
|
this.chipName = savedChipName;
|
|
1193
1219
|
this.chipRevision = savedChipRevision;
|
|
@@ -1198,14 +1224,12 @@ export class ESPLoader extends EventTarget {
|
|
|
1198
1224
|
if (!this.port.writable || !this.port.readable) {
|
|
1199
1225
|
throw new Error("Port not ready after reconnect");
|
|
1200
1226
|
}
|
|
1201
|
-
// Load stub
|
|
1227
|
+
// Load stub
|
|
1202
1228
|
const stubLoader = await this.runStub(true);
|
|
1203
1229
|
this.logger.debug("Stub loaded");
|
|
1204
1230
|
// Restore baudrate if it was changed
|
|
1205
1231
|
if (this._currentBaudRate !== ESP_ROM_BAUD) {
|
|
1206
1232
|
await stubLoader.setBaudrate(this._currentBaudRate);
|
|
1207
|
-
// Wait for port to be ready after baudrate change
|
|
1208
|
-
await sleep(SYNC_TIMEOUT);
|
|
1209
1233
|
// Verify port is still ready after baudrate change
|
|
1210
1234
|
if (!this.port.writable || !this.port.readable) {
|
|
1211
1235
|
throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);
|
|
@@ -1223,18 +1247,12 @@ export class ESPLoader extends EventTarget {
|
|
|
1223
1247
|
* This clears both the application RX buffer and waits for hardware buffers to drain
|
|
1224
1248
|
*/
|
|
1225
1249
|
async flushSerialBuffers() {
|
|
1226
|
-
// Clear application
|
|
1250
|
+
// Clear application buffer
|
|
1227
1251
|
if (!this._parent) {
|
|
1228
1252
|
this.__inputBuffer = [];
|
|
1229
1253
|
}
|
|
1230
|
-
// Wait for any pending
|
|
1254
|
+
// Wait for any pending data
|
|
1231
1255
|
await sleep(SYNC_TIMEOUT);
|
|
1232
|
-
// Clear RX buffer again
|
|
1233
|
-
if (!this._parent) {
|
|
1234
|
-
this.__inputBuffer = [];
|
|
1235
|
-
}
|
|
1236
|
-
// Wait longer to ensure all stale data has been received and discarded
|
|
1237
|
-
await sleep(SYNC_TIMEOUT * 2);
|
|
1238
1256
|
// Final clear
|
|
1239
1257
|
if (!this._parent) {
|
|
1240
1258
|
this.__inputBuffer = [];
|
|
@@ -1253,20 +1271,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1253
1271
|
if (!this.IS_STUB) {
|
|
1254
1272
|
throw new Error("Reading flash is only supported in stub mode. Please run runStub() first.");
|
|
1255
1273
|
}
|
|
1256
|
-
// Check if we should reconnect BEFORE starting the read
|
|
1257
|
-
// Reconnect if total bytes read >= 4MB to ensure clean state
|
|
1258
|
-
if (this._totalBytesRead >= 4 * 1024 * 1024) {
|
|
1259
|
-
this.logger.log(
|
|
1260
|
-
// `Total bytes read: ${this._totalBytesRead}. Reconnecting before new read...`,
|
|
1261
|
-
`Reconnecting before new read...`);
|
|
1262
|
-
try {
|
|
1263
|
-
await this.reconnect();
|
|
1264
|
-
}
|
|
1265
|
-
catch (err) {
|
|
1266
|
-
// If reconnect fails, throw error - don't continue with potentially broken state
|
|
1267
|
-
throw new Error(`Reconnect failed: ${err}`);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
1274
|
// Flush serial buffers before flash read operation
|
|
1271
1275
|
await this.flushSerialBuffers();
|
|
1272
1276
|
this.logger.log(`Reading ${size} bytes from flash at address 0x${addr.toString(16)}...`);
|
|
@@ -1275,16 +1279,6 @@ export class ESPLoader extends EventTarget {
|
|
|
1275
1279
|
let currentAddr = addr;
|
|
1276
1280
|
let remainingSize = size;
|
|
1277
1281
|
while (remainingSize > 0) {
|
|
1278
|
-
// Reconnect every 4MB to prevent browser buffer issues
|
|
1279
|
-
if (allData.length > 0 && allData.length % (4 * 1024 * 1024) === 0) {
|
|
1280
|
-
this.logger.debug(`Read ${allData.length} bytes. Reconnecting to clear buffers...`);
|
|
1281
|
-
try {
|
|
1282
|
-
await this.reconnect();
|
|
1283
|
-
}
|
|
1284
|
-
catch (err) {
|
|
1285
|
-
throw new Error(`Reconnect failed during read: ${err}`);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
1282
|
const chunkSize = Math.min(CHUNK_SIZE, remainingSize);
|
|
1289
1283
|
let chunkSuccess = false;
|
|
1290
1284
|
let retryCount = 0;
|