@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.
- package/dist/cjs/FileMessagerClient.js +21 -115
- package/dist/cjs/FileTide.js +13 -12
- package/dist/cjs/HUDManagers/FileTransferManager.js +200 -69
- package/package.json +1 -1
|
@@ -26,8 +26,8 @@ class FileMessagerClient {
|
|
|
26
26
|
parallelChunks: 3,
|
|
27
27
|
maxRetries: 3
|
|
28
28
|
}, messagerSettings = {
|
|
29
|
-
maxReconnectionAttempts:
|
|
30
|
-
reconnectionAttempts:
|
|
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.
|
|
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.
|
|
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,
|
|
169
|
-
if (!
|
|
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.
|
|
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
|
|
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;
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -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 (
|
|
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.
|
|
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.
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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.
|
|
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": {
|