@trap_stevo/filetide 0.0.46 → 0.0.47

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.
@@ -26,8 +26,8 @@ class FileMessagerClient {
26
26
  parallelChunks: 3,
27
27
  maxRetries: 3
28
28
  }, messagerSettings = {
29
- maxReconnectionAttempts: 5,
30
- reconnectionAttempts: 5,
29
+ maxReconnectionAttempts: 15,
30
+ reconnectionAttempts: 15,
31
31
  maxReconnectionDelay: 10000
32
32
  }) {
33
33
  const {
@@ -151,7 +151,7 @@ class FileMessagerClient {
151
151
  if (fileInfo.largeFile) {
152
152
  return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize);
153
153
  }
154
- return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.fileData, fileDestinationPath, fileInfo.size, adjustedDestinationPath, index);
154
+ return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileInfo.size, fileDestinationPath, index, tideSize, minTideSize, maxTideSize);
155
155
  });
156
156
  Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
157
157
  } catch (error) {
@@ -163,12 +163,13 @@ class FileMessagerClient {
163
163
  if (index === 0) {
164
164
  initiatingTransfer = true;
165
165
  }
166
- return await this.sendLargeFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true);
166
+ return await this.sendFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true, true, true);
167
167
  }
168
- sendDirectoryFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize, directoryPath = null, index = 0) {
169
- if (!file) {
168
+ async sendDirectoryFile(clientID, recipientId, fileName, filePath = process.cwd(), fileSize, directoryPath = null, index = 0, tideSize = 200, minTideSize = 10, maxTideSize = 2000) {
169
+ if (!filePath) {
170
170
  return;
171
171
  }
172
+ let initiatingTransfer = false;
172
173
  if (index === 0) {
173
174
  this.clientTide.emitEvent(clientID, "transfer-start", {
174
175
  fileName,
@@ -177,53 +178,13 @@ class FileMessagerClient {
177
178
  path: directoryPath || filePath,
178
179
  fileSize
179
180
  });
181
+ initiatingTransfer = true;
180
182
  }
181
- this.transporter.sendFile(file, {
182
- onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
183
- return new Promise((resolve, reject) => {
184
- this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
185
- senderID: clientID,
186
- recipientId,
187
- fileName,
188
- fileChunk: chunkData,
189
- completedChunks,
190
- totalChunks,
191
- chunkIndex,
192
- chunkSize,
193
- filePath,
194
- fileSize
195
- });
196
- resolve();
197
- });
198
- },
199
- onComplete: () => {
200
- return new Promise((resolve, reject) => {
201
- FileTransferRecoveryManager.clearTransferState(clientID, recipientId, `${filePath}-${fileName}`);
202
- this.clientTide.emitEvent(clientID, "transfer-complete", {
203
- senderID: clientID,
204
- recipientId,
205
- fileName,
206
- filePath
207
- });
208
- resolve();
209
- });
210
- },
211
- originDetails: {
212
- recipientID: recipientId,
213
- senderID: clientID
214
- },
215
- recipientID: recipientId,
216
- fileDetails: {
217
- destinationPath: filePath,
218
- name: fileName,
219
- path: filePath,
220
- size: fileSize
221
- }
222
- }, this.clientTide).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer: ${error}`, errorMessageColors));
183
+ return await this.sendFile(clientID, recipientId, fileName, filePath, directoryPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true, true, false);
223
184
  }
224
- async sendLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false) {
185
+ async sendFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false, largeFile = false) {
225
186
  const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
226
- FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
187
+ FileNetUtilityManager.outputGradient(largeFile ? `[FileTide ~ File Messager] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!` : `[FileTide ~ File Messager] ~ Requesting to transfer ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
227
188
  const incomingType = this.activeTransferTypes.get(filePath);
228
189
  if (!inDirectory && initiatingTransfer) {
229
190
  const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
@@ -257,6 +218,7 @@ class FileMessagerClient {
257
218
  const maxBatchSize = maxTideSize;
258
219
  const minBatchSize = minTideSize;
259
220
  let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
221
+ let transferInitiated = false;
260
222
  const chunkBatch = [];
261
223
  await this.transporter.sendLargeFile(fileHandle, {
262
224
  recipientID: recipientId,
@@ -279,6 +241,13 @@ class FileMessagerClient {
279
241
  filePath: destination,
280
242
  fileSize
281
243
  });
244
+ if (!transferInitiated) {
245
+ this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
246
+ chunkBatch
247
+ });
248
+ transferInitiated = true;
249
+ chunkBatch.length = 0;
250
+ }
282
251
  if (chunkBatch.length >= batchSize) {
283
252
  const now = Date.now();
284
253
  const rtt = now - lastSendTime;
@@ -321,76 +290,13 @@ class FileMessagerClient {
321
290
  });
322
291
  }
323
292
  }, this.clientTide);
324
- FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!`, significantMessageColors);
293
+ FileNetUtilityManager.outputGradient(largeFile ? `[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!` : `[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors);
325
294
  } catch (error) {
326
- FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}`, errorMessageColors);
295
+ FileNetUtilityManager.outputGradient(largeFile ? `[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}` : `[FileTide ~ File Messager] ~ Error transferring file ~ ${error.message}`, errorMessageColors);
327
296
  } finally {
328
297
  await fileHandle.close();
329
298
  }
330
299
  }
331
- async sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize) {
332
- if (!file) {
333
- return;
334
- }
335
- const destinationPath = FileUtilityManager.normalizePath(path.join(filePath, fileName));
336
- FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
337
- const incomingType = this.activeTransferTypes.get(filePath);
338
- const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
339
- if (incomingType) {
340
- this.activeTransferTypes.delete(filePath);
341
- }
342
- if (!transferAllowed) {
343
- return;
344
- }
345
- this.clientTide.emitEvent(clientID, "transfer-start", {
346
- fileName,
347
- senderID: clientID,
348
- recipientID: recipientId,
349
- path: filePath,
350
- fileSize
351
- });
352
- await this.transporter.sendFile(file, {
353
- onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
354
- return new Promise((resolve, reject) => {
355
- this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
356
- senderID: clientID,
357
- recipientId,
358
- fileName,
359
- fileChunk: chunkData,
360
- completedChunks,
361
- totalChunks,
362
- chunkIndex,
363
- chunkSize,
364
- filePath,
365
- fileSize
366
- });
367
- resolve();
368
- });
369
- },
370
- onComplete: () => {
371
- return new Promise((resolve, reject) => {
372
- FileTransferRecoveryManager.clearTransferState(clientID, recipientId, `${filePath}-${fileName}`);
373
- this.clientTide.emitEvent(clientID, "transfer-complete", {
374
- senderID: clientID,
375
- recipientId,
376
- fileName,
377
- filePath
378
- });
379
- resolve();
380
- });
381
- },
382
- originDetails: {
383
- recipientID: recipientId,
384
- senderID: clientID
385
- },
386
- fileDetails: {
387
- destinationPath,
388
- name: fileName,
389
- path: filePath,
390
- size: fileSize
391
- }
392
- }, this.clientTide).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer ~ ${error}`, errorMessageColors));
393
- }
394
300
  }
395
301
  ;
396
302
  module.exports = FileMessagerClient;
@@ -180,46 +180,47 @@ class FileTide {
180
180
  * @param {Buffer} fileData - The path of the data to send
181
181
  * @param {String} destinationPath - The destination path on the device
182
182
  * @param {Array} filterDirectoryContent - List of paths to filter
183
- * @param {Number} tideSize - The tide size in sending files (500)
183
+ * @param {Number} tideSize - The tide size in sending smaller to medium files (200)
184
+ * @param {Number} tidalSize - The tide size in sending large files (500)
184
185
  * @param {Number} minTideSize - The minimum tide size in sending files (10)
185
186
  * @param {Number} maxTideSize - The maximum tide size in sending files (2000)
186
187
  */
187
- async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
188
+ async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 200, tidalSize = 500, minTideSize = 10, maxTideSize = 2000) {
188
189
  const clientID = this.currentUserID;
189
190
  const clientMessager = this.clients.get(clientID);
190
191
  if (!clientMessager) {
191
192
  FileTide.outputGradient(`[FileTide] Client ~ ${clientID} not found.`, ["#F94144", "#F3722C"]);
192
- return;
193
+ return false;
193
194
  }
194
195
  const recipientOnline = await clientMessager.clientTide.emitEventWithResponse(clientID, "check-client-online", "retrieved-client-online", {
195
196
  clientID: recipientID
196
197
  }, 5000);
197
198
  if (!recipientOnline || !recipientOnline.online) {
198
199
  FileTide.outputGradient(`[FileTide] ${recipientID} currently not tiding.`, ["#F94144", "#F3722C"]);
199
- return;
200
+ return false;
200
201
  }
201
202
  const fileDetails = await this.getPathData(filePath, filterDirectoryContent);
202
203
  if (!fileDetails) {
203
204
  FileTide.outputGradient(`[${clientID}] File at path ${filePath} not found.`, ["#F94144", "#F3722C"]);
204
- return;
205
+ return false;
205
206
  }
206
207
  if (fileDetails.type === "file") {
207
208
  if (fileDetails.largeFile) {
208
209
  FileTide.outputGradient(`[${clientID}] Sending large file ~ ${fileDetails.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
209
- await clientMessager.sendLargeFile(clientID, recipientID, fileDetails.fileName, fileDetails.filePath, destinationPath, fileDetails.fileSize, tideSize, minTideSize, maxTideSize);
210
- return;
210
+ await clientMessager.sendFile(clientID, recipientID, fileDetails.fileName, fileDetails.filePath, destinationPath, fileDetails.fileSize, tidalSize, minTideSize, maxTideSize, true, false, true);
211
+ return true;
211
212
  }
212
213
  FileTide.outputGradient(`[${clientID}] Sending file ~ ${fileDetails.content.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
213
- clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.fileData, destinationPath, fileDetails.content.size);
214
- return;
214
+ await clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.filePath, destinationPath, fileDetails.content.size, tideSize, minTideSize, maxTideSize);
215
+ return true;
215
216
  }
216
217
  if (fileDetails.type === "directory") {
217
218
  FileTide.outputGradient(`[${clientID}] Sending ${fileDetails.content.length} files in directory ~ ${path.basename(filePath)} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
218
- clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
219
- return;
219
+ await clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
220
+ return true;
220
221
  }
221
222
  FileTide.outputGradient(`[FileTide] ~ No active client ~ ${recipientID} found.`, errorMessageColors);
222
- return;
223
+ return false;
223
224
  }
224
225
 
225
226
  /**
@@ -24,10 +24,11 @@ class FileTransferManager {
24
24
  onSendChunk,
25
25
  onComplete,
26
26
  onProgress,
27
- onStart
27
+ onStart,
28
+ onTiding
28
29
  }, clientTide) {
29
30
  const transferId = _assertClassBrand(_FileTransferManager_brand, this, _generateTransferId).call(this, fileDetails);
30
- return await _assertClassBrand(_FileTransferManager_brand, this, _startTransfer).call(this, file, transferId, fileDetails, originDetails, onSendChunk, onComplete, onProgress, onStart, clientTide);
31
+ return await _assertClassBrand(_FileTransferManager_brand, this, _startTransfer).call(this, file, transferId, fileDetails, originDetails, onSendChunk, onComplete, onProgress, onStart, onTiding, clientTide);
31
32
  }
32
33
  async sendLargeFile(fileHandle, {
33
34
  fileDetails,
@@ -107,31 +108,36 @@ class FileTransferManager {
107
108
  const keepAliveInterval = setInterval(() => {
108
109
  if (onTiding) onTiding();
109
110
  }, 5000);
110
- try {
111
- let adaptiveBatchSize = 100;
112
- while (currentBatchStart < totalChunks) {
113
- if (transferState.activeChunks < this.parallelChunks) {
114
- adaptiveBatchSize = Math.min(adaptiveBatchSize + 10, 100);
115
- } else {
116
- adaptiveBatchSize = Math.max(adaptiveBatchSize - 10, 10);
111
+ return new Promise(async (resolve, reject) => {
112
+ try {
113
+ let adaptiveBatchSize = 100;
114
+ while (currentBatchStart < totalChunks) {
115
+ if (transferState.activeChunks < this.parallelChunks) {
116
+ adaptiveBatchSize = Math.min(adaptiveBatchSize + 10, 100);
117
+ } else {
118
+ adaptiveBatchSize = Math.max(adaptiveBatchSize - 10, 10);
119
+ }
120
+ await sendChunkBatch(currentBatchStart, adaptiveBatchSize);
121
+ currentBatchStart += adaptiveBatchSize;
122
+ await new Promise(resolve => setTimeout(resolve, 30));
123
+ }
124
+ } finally {
125
+ clearInterval(keepAliveInterval);
126
+ fileHandle.on("close", resolve);
127
+ fileHandle.on("error", error => {
128
+ this.activeTransfers.delete(transferId);
129
+ reject(error);
130
+ });
131
+ try {
132
+ await fileHandle.close();
133
+ } catch (error) {
134
+ console.error(`[FileTide ~ Transporter] ~ Error closing file handle ~ ${error.message}`);
117
135
  }
118
- await sendChunkBatch(currentBatchStart, adaptiveBatchSize);
119
- currentBatchStart += adaptiveBatchSize;
120
- await new Promise(resolve => setTimeout(resolve, 30));
121
136
  }
122
- } finally {
123
- clearInterval(keepAliveInterval);
124
- }
125
- return new Promise((resolve, reject) => {
126
- fileHandle.on("close", resolve);
127
- fileHandle.on("error", error => {
128
- this.activeTransfers.delete(transferId);
129
- reject(error);
130
- });
131
137
  });
132
138
  }
133
139
  }
134
- async function _startTransfer(file, transferId, fileDetails, originDetails, onSendChunk, onComplete, onProgress, onStart, clientTide) {
140
+ async function _startTransfer(file, transferId, fileDetails, originDetails, onSendChunk, onComplete, onProgress, onStart, onTiding, clientTide) {
135
141
  const recoveredTransferState = (await clientTide.emitEventWithResponse(originDetails.senderID, "get-client-transfer-state", "sent-current-transfer-state", {
136
142
  recipientID: originDetails.recipientID,
137
143
  senderID: originDetails.senderID,
@@ -142,6 +148,8 @@ async function _startTransfer(file, transferId, fileDetails, originDetails, onSe
142
148
  lastChunkSent: 0
143
149
  };
144
150
  const totalChunks = Math.ceil(file.length / this.chunkSize);
151
+ let nextExpectedChunk = recoveredTransferState.lastChunkSent;
152
+ const chunkBuffer = new Map();
145
153
  this.activeTransfers.set(transferId, {
146
154
  totalChunks,
147
155
  transferredSize: recoveredTransferState.transferredSize,
@@ -151,64 +159,187 @@ async function _startTransfer(file, transferId, fileDetails, originDetails, onSe
151
159
  currentChunk: recoveredTransferState.lastChunkSent,
152
160
  size: fileDetails.size
153
161
  });
162
+ const transferState = this.activeTransfers.get(transferId);
154
163
  const updateProgress = () => {
155
- const transferState = this.activeTransfers.get(transferId);
156
164
  if (onProgress) {
157
165
  onProgress(transferState.completedChunks / transferState.totalChunks * 100, this.chunkSize);
158
166
  }
159
167
  };
160
168
  const exponentialBackoff = retryCount => Math.min(1000 * 2 ** retryCount, 10000);
161
- return new Promise((resolve, reject) => {
162
- const sendChunk = async chunkIndex => {
163
- const transferState = this.activeTransfers.get(transferId);
164
- if (chunkIndex >= transferState.totalChunks) {
165
- return;
166
- }
167
- const start = chunkIndex * this.chunkSize;
168
- const end = Math.min(start + this.chunkSize, file.length);
169
- const chunk = file.slice(start, end);
170
- if (onStart && chunkIndex === 0) {
171
- onStart({
172
- name: fileDetails.name,
173
- path: fileDetails.path,
174
- size: fileDetails.size,
175
- totalChunks: transferState.totalChunks
176
- });
177
- }
178
- transferState.activeChunks++;
179
- try {
180
- await onSendChunk(transferId, chunkIndex, this.chunkSize, chunk, transferState.totalChunks, transferState.completedChunks + 1);
181
- transferState.transferredSize += this.chunkSize;
169
+ const sendChunk = async chunkIndex => {
170
+ const start = chunkIndex * this.chunkSize;
171
+ const end = Math.min(start + this.chunkSize, file.length);
172
+ const chunk = file.slice(start, end);
173
+ transferState.activeChunks++;
174
+ try {
175
+ await onSendChunk(transferId, chunkIndex, this.chunkSize, chunk, totalChunks, transferState.completedChunks + 1);
176
+ chunkBuffer.set(chunkIndex, chunk);
177
+ while (chunkBuffer.has(nextExpectedChunk)) {
178
+ chunkBuffer.delete(nextExpectedChunk);
179
+ nextExpectedChunk++;
182
180
  transferState.completedChunks++;
183
- transferState.activeChunks--;
184
181
  updateProgress();
185
- if (transferState.activeChunks < this.parallelChunks && transferState.currentChunk < transferState.totalChunks) {
186
- sendChunk(transferState.currentChunk++);
187
- }
188
- if (transferState.completedChunks === transferState.totalChunks) {
189
- await onComplete(transferId);
190
- this.activeTransfers.delete(transferId);
191
- resolve();
192
- }
193
- } catch (error) {
194
- console.error(`[FileTide ~ File Messager] ~ Did not send chunk ${chunkIndex} ~ ${error.message}`);
195
- transferState.activeChunks--;
196
- const retryCount = (transferState.failedChunks.get(chunkIndex) || 0) + 1;
197
- if (retryCount > this.maxRetries) {
198
- this.activeTransfers.delete(transferId);
199
- reject(new Error(`Did not send chunk ${chunkIndex} after ${this.maxRetries} retries.`));
200
- } else {
201
- transferState.failedChunks.set(chunkIndex, retryCount);
202
- setTimeout(() => sendChunk(chunkIndex), exponentialBackoff(retryCount));
203
- }
204
182
  }
205
- };
206
- const transferState = this.activeTransfers.get(transferId);
207
- for (let i = 0; i < Math.min(this.parallelChunks, transferState.totalChunks); i++) {
208
- sendChunk(transferState.currentChunk++);
183
+ if (transferState.completedChunks === transferState.totalChunks) {
184
+ clearInterval(keepAliveInterval);
185
+ await onComplete(transferId);
186
+ this.activeTransfers.delete(transferId);
187
+ }
188
+ } catch (error) {
189
+ console.error(`[FileTide ~ Transporter] ~ Did not send chunk ${chunkIndex} ~ ${error.message}`);
190
+ const retryCount = (transferState.failedChunks.get(chunkIndex) || 0) + 1;
191
+ if (retryCount > this.maxRetries) {
192
+ clearInterval(keepAliveInterval);
193
+ this.activeTransfers.delete(transferId);
194
+ throw new Error(`[FileTide ~ Transporter] ~ Did not send chunk ${chunkIndex} after ${this.maxRetries} retries.`);
195
+ }
196
+ transferState.failedChunks.set(chunkIndex, retryCount);
197
+ setTimeout(() => sendChunk(chunkIndex), exponentialBackoff(retryCount));
198
+ } finally {
199
+ transferState.activeChunks--;
209
200
  }
210
- });
201
+ };
202
+ const sendChunkBatch = async (startChunkIndex, batchSize = 100, miniBatchSize = 10) => {
203
+ for (let i = 0; i < batchSize && startChunkIndex + i < totalChunks; i += miniBatchSize) {
204
+ const miniBatchPromises = [];
205
+ for (let j = 0; j < miniBatchSize && startChunkIndex + i + j < totalChunks; j++) {
206
+ const chunkIndex = startChunkIndex + i + j;
207
+ miniBatchPromises.push(sendChunk(chunkIndex));
208
+ }
209
+ await Promise.all(miniBatchPromises);
210
+ await new Promise(resolve => setTimeout(resolve, 5));
211
+ }
212
+ };
213
+ const keepAliveInterval = setInterval(() => {
214
+ if (onTiding) onTiding();
215
+ }, 5000);
216
+ let currentBatchStart = transferState.currentChunk;
217
+ let adaptiveBatchSize = 100;
218
+ try {
219
+ while (currentBatchStart < totalChunks) {
220
+ adaptiveBatchSize = transferState.activeChunks < this.parallelChunks ? Math.min(adaptiveBatchSize + 10, 100) : Math.max(adaptiveBatchSize - 10, 10);
221
+ await sendChunkBatch(currentBatchStart, adaptiveBatchSize);
222
+ currentBatchStart += adaptiveBatchSize;
223
+ await new Promise(resolve => setTimeout(resolve, 30));
224
+ }
225
+ } finally {
226
+ clearInterval(keepAliveInterval);
227
+ }
211
228
  }
229
+ /*async #startTransfer(file, transferId, fileDetails, originDetails, onSendChunk, onComplete, onProgress, onStart, onTiding, clientTide)
230
+ {
231
+ const recoveredTransferState = await clientTide.emitEventWithResponse(originDetails.senderID, "get-client-transfer-state", "sent-current-transfer-state", { recipientID : originDetails.recipientID, senderID : originDetails.senderID, filePath : fileDetails.destinationPath, fileName : fileDetails.name }, 30000) || { transferredSize : 0, lastChunkSent : 0 };
232
+
233
+ const totalChunks = Math.ceil(file.length / this.chunkSize);
234
+
235
+ this.activeTransfers.set(transferId, {
236
+ totalChunks,
237
+ transferredSize : recoveredTransferState.transferredSize,
238
+ completedChunks : recoveredTransferState.lastChunkSent,
239
+ activeChunks : 0,
240
+ failedChunks : new Map(),
241
+ currentChunk : recoveredTransferState.lastChunkSent,
242
+ size : fileDetails.size
243
+ });
244
+ const updateProgress = () => {
245
+ const transferState = this.activeTransfers.get(transferId);
246
+
247
+ if (onProgress)
248
+ {
249
+ onProgress((transferState.completedChunks / transferState.totalChunks) * 100, this.chunkSize);
250
+ }
251
+ };
252
+
253
+ const keepAliveInterval = setInterval(() => {
254
+ if (onTiding) onTiding();
255
+ }, 5000);
256
+
257
+ const exponentialBackoff = (retryCount) => Math.min(1000 * (2 ** retryCount), 10000);
258
+
259
+ return new Promise((resolve, reject) => {
260
+ const sendChunk = async (chunkIndex) => {
261
+ const transferState = this.activeTransfers.get(transferId);
262
+
263
+ if (chunkIndex >= transferState.totalChunks) { return; }
264
+ const start = chunkIndex * this.chunkSize;
265
+
266
+ const end = Math.min(start + this.chunkSize, file.length);
267
+
268
+ const chunk = file.slice(start, end);
269
+
270
+ if (onStart && chunkIndex === 0)
271
+ {
272
+ onStart({
273
+ name : fileDetails.name,
274
+ path : fileDetails.path,
275
+ size : fileDetails.size,
276
+ totalChunks : transferState.totalChunks
277
+ });
278
+ }
279
+
280
+ transferState.activeChunks++;
281
+
282
+ try
283
+ {
284
+ await onSendChunk(transferId, chunkIndex, this.chunkSize, chunk, transferState.totalChunks, transferState.completedChunks + 1);
285
+
286
+ transferState.transferredSize += this.chunkSize;
287
+
288
+ transferState.completedChunks++;
289
+
290
+ transferState.activeChunks--;
291
+
292
+ updateProgress();
293
+
294
+ if (transferState.activeChunks < this.parallelChunks && transferState.currentChunk < transferState.totalChunks)
295
+ {
296
+ sendChunk(transferState.currentChunk++);
297
+ }
298
+
299
+ if (transferState.completedChunks === transferState.totalChunks)
300
+ {
301
+ await onComplete(transferId);
302
+
303
+ this.activeTransfers.delete(transferId);
304
+
305
+ clearInterval(keepAliveInterval);
306
+
307
+ resolve();
308
+ }
309
+ }
310
+ catch (error)
311
+ {
312
+ console.error(`[FileTide ~ File Messager] ~ Did not send chunk ${chunkIndex} ~ ${error.message}`);
313
+
314
+ transferState.activeChunks--;
315
+
316
+ const retryCount = (transferState.failedChunks.get(chunkIndex) || 0) + 1;
317
+
318
+ if (retryCount > this.maxRetries)
319
+ {
320
+ this.activeTransfers.delete(transferId);
321
+
322
+ clearInterval(keepAliveInterval);
323
+
324
+ reject(new Error(`Did not send chunk ${chunkIndex} after ${this.maxRetries} retries.`));
325
+ }
326
+ else
327
+ {
328
+ transferState.failedChunks.set(chunkIndex, retryCount);
329
+
330
+ setTimeout(() => sendChunk(chunkIndex), exponentialBackoff(retryCount));
331
+ }
332
+ }
333
+ };
334
+
335
+ const transferState = this.activeTransfers.get(transferId);
336
+
337
+ for (let i = 0; i < Math.min(this.parallelChunks, transferState.totalChunks); i++)
338
+ {
339
+ sendChunk(transferState.currentChunk++);
340
+ }
341
+ });
342
+ }*/
212
343
  function _generateTransferId(file) {
213
344
  return `${file.name}-${Date.now()}`;
214
345
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trap_stevo/filetide",
3
- "version": "0.0.46",
3
+ "version": "0.0.47",
4
4
  "description": "Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities with a tool designed for precision, efficiency, and effortless connectivity.",
5
5
  "main": "dist/cjs/FileTide.js",
6
6
  "scripts": {