@trap_stevo/filetide 0.0.45 → 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 +29 -114
- package/dist/cjs/FileTide.js +30 -17
- package/dist/cjs/HUDManagers/FileTransferManager.js +200 -69
- package/package.json +2 -2
|
@@ -25,11 +25,20 @@ class FileMessagerClient {
|
|
|
25
25
|
constructor(options = {}, transportOptions = {
|
|
26
26
|
parallelChunks: 3,
|
|
27
27
|
maxRetries: 3
|
|
28
|
+
}, messagerSettings = {
|
|
29
|
+
maxReconnectionAttempts: 15,
|
|
30
|
+
reconnectionAttempts: 15,
|
|
31
|
+
maxReconnectionDelay: 10000
|
|
28
32
|
}) {
|
|
33
|
+
const {
|
|
34
|
+
maxReconnectionAttempts = 15,
|
|
35
|
+
reconnectionAttempts = 15,
|
|
36
|
+
maxReconnectionDelay = 10000
|
|
37
|
+
} = messagerSettings;
|
|
29
38
|
this.clientOptions = FileMessagerConfigManager.getClientOptions(options);
|
|
30
39
|
this.transporter = new FileTransferManager(transportOptions);
|
|
31
40
|
this.activeTransferTypes = new Map();
|
|
32
|
-
this.clientTide = new HUDIoTide();
|
|
41
|
+
this.clientTide = new HUDIoTide(maxReconnectionAttempts, reconnectionAttempts, maxReconnectionDelay);
|
|
33
42
|
this.clients = new Map();
|
|
34
43
|
}
|
|
35
44
|
createClientInstance(clientID, clientOptions, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
@@ -142,7 +151,7 @@ class FileMessagerClient {
|
|
|
142
151
|
if (fileInfo.largeFile) {
|
|
143
152
|
return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize);
|
|
144
153
|
}
|
|
145
|
-
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);
|
|
146
155
|
});
|
|
147
156
|
Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
|
|
148
157
|
} catch (error) {
|
|
@@ -154,12 +163,13 @@ class FileMessagerClient {
|
|
|
154
163
|
if (index === 0) {
|
|
155
164
|
initiatingTransfer = true;
|
|
156
165
|
}
|
|
157
|
-
return await this.
|
|
166
|
+
return await this.sendFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true, true, true);
|
|
158
167
|
}
|
|
159
|
-
sendDirectoryFile(clientID, recipientId, fileName,
|
|
160
|
-
if (!
|
|
168
|
+
async sendDirectoryFile(clientID, recipientId, fileName, filePath = process.cwd(), fileSize, directoryPath = null, index = 0, tideSize = 200, minTideSize = 10, maxTideSize = 2000) {
|
|
169
|
+
if (!filePath) {
|
|
161
170
|
return;
|
|
162
171
|
}
|
|
172
|
+
let initiatingTransfer = false;
|
|
163
173
|
if (index === 0) {
|
|
164
174
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
165
175
|
fileName,
|
|
@@ -168,53 +178,13 @@ class FileMessagerClient {
|
|
|
168
178
|
path: directoryPath || filePath,
|
|
169
179
|
fileSize
|
|
170
180
|
});
|
|
181
|
+
initiatingTransfer = true;
|
|
171
182
|
}
|
|
172
|
-
this.
|
|
173
|
-
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
174
|
-
return new Promise((resolve, reject) => {
|
|
175
|
-
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
176
|
-
senderID: clientID,
|
|
177
|
-
recipientId,
|
|
178
|
-
fileName,
|
|
179
|
-
fileChunk: chunkData,
|
|
180
|
-
completedChunks,
|
|
181
|
-
totalChunks,
|
|
182
|
-
chunkIndex,
|
|
183
|
-
chunkSize,
|
|
184
|
-
filePath,
|
|
185
|
-
fileSize
|
|
186
|
-
});
|
|
187
|
-
resolve();
|
|
188
|
-
});
|
|
189
|
-
},
|
|
190
|
-
onComplete: () => {
|
|
191
|
-
return new Promise((resolve, reject) => {
|
|
192
|
-
FileTransferRecoveryManager.clearTransferState(clientID, recipientId, `${filePath}-${fileName}`);
|
|
193
|
-
this.clientTide.emitEvent(clientID, "transfer-complete", {
|
|
194
|
-
senderID: clientID,
|
|
195
|
-
recipientId,
|
|
196
|
-
fileName,
|
|
197
|
-
filePath
|
|
198
|
-
});
|
|
199
|
-
resolve();
|
|
200
|
-
});
|
|
201
|
-
},
|
|
202
|
-
originDetails: {
|
|
203
|
-
recipientID: recipientId,
|
|
204
|
-
senderID: clientID
|
|
205
|
-
},
|
|
206
|
-
recipientID: recipientId,
|
|
207
|
-
fileDetails: {
|
|
208
|
-
destinationPath: filePath,
|
|
209
|
-
name: fileName,
|
|
210
|
-
path: filePath,
|
|
211
|
-
size: fileSize
|
|
212
|
-
}
|
|
213
|
-
}, 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);
|
|
214
184
|
}
|
|
215
|
-
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) {
|
|
216
186
|
const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
|
|
217
|
-
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);
|
|
218
188
|
const incomingType = this.activeTransferTypes.get(filePath);
|
|
219
189
|
if (!inDirectory && initiatingTransfer) {
|
|
220
190
|
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
|
|
@@ -248,6 +218,7 @@ class FileMessagerClient {
|
|
|
248
218
|
const maxBatchSize = maxTideSize;
|
|
249
219
|
const minBatchSize = minTideSize;
|
|
250
220
|
let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
|
|
221
|
+
let transferInitiated = false;
|
|
251
222
|
const chunkBatch = [];
|
|
252
223
|
await this.transporter.sendLargeFile(fileHandle, {
|
|
253
224
|
recipientID: recipientId,
|
|
@@ -270,6 +241,13 @@ class FileMessagerClient {
|
|
|
270
241
|
filePath: destination,
|
|
271
242
|
fileSize
|
|
272
243
|
});
|
|
244
|
+
if (!transferInitiated) {
|
|
245
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
246
|
+
chunkBatch
|
|
247
|
+
});
|
|
248
|
+
transferInitiated = true;
|
|
249
|
+
chunkBatch.length = 0;
|
|
250
|
+
}
|
|
273
251
|
if (chunkBatch.length >= batchSize) {
|
|
274
252
|
const now = Date.now();
|
|
275
253
|
const rtt = now - lastSendTime;
|
|
@@ -312,76 +290,13 @@ class FileMessagerClient {
|
|
|
312
290
|
});
|
|
313
291
|
}
|
|
314
292
|
}, this.clientTide);
|
|
315
|
-
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);
|
|
316
294
|
} catch (error) {
|
|
317
|
-
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);
|
|
318
296
|
} finally {
|
|
319
297
|
await fileHandle.close();
|
|
320
298
|
}
|
|
321
299
|
}
|
|
322
|
-
async sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize) {
|
|
323
|
-
if (!file) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
const destinationPath = FileUtilityManager.normalizePath(path.join(filePath, fileName));
|
|
327
|
-
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
|
|
328
|
-
const incomingType = this.activeTransferTypes.get(filePath);
|
|
329
|
-
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
|
|
330
|
-
if (incomingType) {
|
|
331
|
-
this.activeTransferTypes.delete(filePath);
|
|
332
|
-
}
|
|
333
|
-
if (!transferAllowed) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
337
|
-
fileName,
|
|
338
|
-
senderID: clientID,
|
|
339
|
-
recipientID: recipientId,
|
|
340
|
-
path: filePath,
|
|
341
|
-
fileSize
|
|
342
|
-
});
|
|
343
|
-
await this.transporter.sendFile(file, {
|
|
344
|
-
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
345
|
-
return new Promise((resolve, reject) => {
|
|
346
|
-
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
347
|
-
senderID: clientID,
|
|
348
|
-
recipientId,
|
|
349
|
-
fileName,
|
|
350
|
-
fileChunk: chunkData,
|
|
351
|
-
completedChunks,
|
|
352
|
-
totalChunks,
|
|
353
|
-
chunkIndex,
|
|
354
|
-
chunkSize,
|
|
355
|
-
filePath,
|
|
356
|
-
fileSize
|
|
357
|
-
});
|
|
358
|
-
resolve();
|
|
359
|
-
});
|
|
360
|
-
},
|
|
361
|
-
onComplete: () => {
|
|
362
|
-
return new Promise((resolve, reject) => {
|
|
363
|
-
FileTransferRecoveryManager.clearTransferState(clientID, recipientId, `${filePath}-${fileName}`);
|
|
364
|
-
this.clientTide.emitEvent(clientID, "transfer-complete", {
|
|
365
|
-
senderID: clientID,
|
|
366
|
-
recipientId,
|
|
367
|
-
fileName,
|
|
368
|
-
filePath
|
|
369
|
-
});
|
|
370
|
-
resolve();
|
|
371
|
-
});
|
|
372
|
-
},
|
|
373
|
-
originDetails: {
|
|
374
|
-
recipientID: recipientId,
|
|
375
|
-
senderID: clientID
|
|
376
|
-
},
|
|
377
|
-
fileDetails: {
|
|
378
|
-
destinationPath,
|
|
379
|
-
name: fileName,
|
|
380
|
-
path: filePath,
|
|
381
|
-
size: fileSize
|
|
382
|
-
}
|
|
383
|
-
}, 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));
|
|
384
|
-
}
|
|
385
300
|
}
|
|
386
301
|
;
|
|
387
302
|
module.exports = FileMessagerClient;
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -4,6 +4,9 @@ var _FileTide;
|
|
|
4
4
|
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
|
|
5
5
|
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
|
|
6
6
|
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
7
|
+
const {
|
|
8
|
+
HUDUtilityManager
|
|
9
|
+
} = require("@trap_stevo/legendarybuilderpronodejs-utilities");
|
|
7
10
|
const chalk = require("chalk");
|
|
8
11
|
const path = require("path");
|
|
9
12
|
const fs = require("fs");
|
|
@@ -68,6 +71,8 @@ class FileTide {
|
|
|
68
71
|
* Initialize and start a new client for each user.
|
|
69
72
|
* @param {Object} clientOptions - Configuration for client (e.g., serverUrl)
|
|
70
73
|
* @param {Object} connectionOptions - Configuration for the client connection
|
|
74
|
+
* @param {Object} transportOptions - Configuration for the file transporter
|
|
75
|
+
* @param {Object} messagerSettings - Configuration for the messager
|
|
71
76
|
* @param {String} roomName - The name of the room to join
|
|
72
77
|
* @param {String} userID - The ID of the client user
|
|
73
78
|
* @param {Function} onLaunch - Callback for when a file messager launches
|
|
@@ -85,11 +90,18 @@ class FileTide {
|
|
|
85
90
|
* @param {Boolean} [useAuthentication=true] - Whether to enable connection authentication
|
|
86
91
|
* @param {Boolean} [queryAuthToken=false] - Whether to enable connection authentication tokens
|
|
87
92
|
*/
|
|
88
|
-
launchMessager(clientOptions = {}, connectionOptions = {},
|
|
93
|
+
launchMessager(clientOptions = {}, connectionOptions = {}, transportOptions = {
|
|
94
|
+
parallelChunks: 3,
|
|
95
|
+
maxRetries: 3
|
|
96
|
+
}, messagerSettings = {
|
|
97
|
+
maxReconnectionAttempts: 15,
|
|
98
|
+
reconnectionAttempts: 15,
|
|
99
|
+
maxReconnectionDelay: 10000
|
|
100
|
+
}, roomName, userID, onLaunch, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, enableTransferBarrier = true, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
89
101
|
if (this.clients.has(userID)) {
|
|
90
102
|
this.stopMessager(userID);
|
|
91
103
|
}
|
|
92
|
-
const newClient = new FileMessagerClient(clientOptions);
|
|
104
|
+
const newClient = new FileMessagerClient(clientOptions, transportOptions, messagerSettings);
|
|
93
105
|
const enterRoom = newClient.joinRoom(userID, roomName, connectionOptions, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
94
106
|
this.transferBarrier = enableTransferBarrier;
|
|
95
107
|
this.clientShorePolicies.set(userID, [FileUtilityManager.getTidePath(">CurrentUser"), FileUtilityManager.getTidePath(">Downloads"), FileUtilityManager.getTidePath(">Documents")]);
|
|
@@ -168,46 +180,47 @@ class FileTide {
|
|
|
168
180
|
* @param {Buffer} fileData - The path of the data to send
|
|
169
181
|
* @param {String} destinationPath - The destination path on the device
|
|
170
182
|
* @param {Array} filterDirectoryContent - List of paths to filter
|
|
171
|
-
* @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)
|
|
172
185
|
* @param {Number} minTideSize - The minimum tide size in sending files (10)
|
|
173
186
|
* @param {Number} maxTideSize - The maximum tide size in sending files (2000)
|
|
174
187
|
*/
|
|
175
|
-
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) {
|
|
176
189
|
const clientID = this.currentUserID;
|
|
177
190
|
const clientMessager = this.clients.get(clientID);
|
|
178
191
|
if (!clientMessager) {
|
|
179
192
|
FileTide.outputGradient(`[FileTide] Client ~ ${clientID} not found.`, ["#F94144", "#F3722C"]);
|
|
180
|
-
return;
|
|
193
|
+
return false;
|
|
181
194
|
}
|
|
182
195
|
const recipientOnline = await clientMessager.clientTide.emitEventWithResponse(clientID, "check-client-online", "retrieved-client-online", {
|
|
183
196
|
clientID: recipientID
|
|
184
197
|
}, 5000);
|
|
185
198
|
if (!recipientOnline || !recipientOnline.online) {
|
|
186
199
|
FileTide.outputGradient(`[FileTide] ${recipientID} currently not tiding.`, ["#F94144", "#F3722C"]);
|
|
187
|
-
return;
|
|
200
|
+
return false;
|
|
188
201
|
}
|
|
189
202
|
const fileDetails = await this.getPathData(filePath, filterDirectoryContent);
|
|
190
203
|
if (!fileDetails) {
|
|
191
204
|
FileTide.outputGradient(`[${clientID}] File at path ${filePath} not found.`, ["#F94144", "#F3722C"]);
|
|
192
|
-
return;
|
|
205
|
+
return false;
|
|
193
206
|
}
|
|
194
207
|
if (fileDetails.type === "file") {
|
|
195
208
|
if (fileDetails.largeFile) {
|
|
196
209
|
FileTide.outputGradient(`[${clientID}] Sending large file ~ ${fileDetails.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
197
|
-
await clientMessager.
|
|
198
|
-
return;
|
|
210
|
+
await clientMessager.sendFile(clientID, recipientID, fileDetails.fileName, fileDetails.filePath, destinationPath, fileDetails.fileSize, tidalSize, minTideSize, maxTideSize, true, false, true);
|
|
211
|
+
return true;
|
|
199
212
|
}
|
|
200
213
|
FileTide.outputGradient(`[${clientID}] Sending file ~ ${fileDetails.content.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
201
|
-
clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.
|
|
202
|
-
return;
|
|
214
|
+
await clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.filePath, destinationPath, fileDetails.content.size, tideSize, minTideSize, maxTideSize);
|
|
215
|
+
return true;
|
|
203
216
|
}
|
|
204
217
|
if (fileDetails.type === "directory") {
|
|
205
218
|
FileTide.outputGradient(`[${clientID}] Sending ${fileDetails.content.length} files in directory ~ ${path.basename(filePath)} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
206
|
-
clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
|
|
207
|
-
return;
|
|
219
|
+
await clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
|
|
220
|
+
return true;
|
|
208
221
|
}
|
|
209
222
|
FileTide.outputGradient(`[FileTide] ~ No active client ~ ${recipientID} found.`, errorMessageColors);
|
|
210
|
-
return;
|
|
223
|
+
return false;
|
|
211
224
|
}
|
|
212
225
|
|
|
213
226
|
/**
|
|
@@ -522,6 +535,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
522
535
|
const capacitor = new ChunkCapacitor(directoryContents, 100);
|
|
523
536
|
const contents = capacitor.getAllChunks();
|
|
524
537
|
for (let files of contents) {
|
|
538
|
+
totalFilesSent += files.length;
|
|
525
539
|
client.clientTide.emitEvent(userID, "send-file-list-to-client", {
|
|
526
540
|
senderID: data.recipientID,
|
|
527
541
|
recipientID: data.senderID,
|
|
@@ -529,7 +543,6 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
529
543
|
listedFiles: files
|
|
530
544
|
});
|
|
531
545
|
}
|
|
532
|
-
totalFilesSent += totalItems;
|
|
533
546
|
});
|
|
534
547
|
setTimeout(() => {
|
|
535
548
|
_FileTide.outputGradient(`[${userID}] Sent file list to ${data.senderID}!`, significantMessageColors);
|
|
@@ -544,13 +557,13 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
544
557
|
_FileTide.outputGradient(`[${userID} | FileTide Error] ${error}`, errorMessageColors);
|
|
545
558
|
});
|
|
546
559
|
client.clientTide.onEvent(userID, "client-file-list-received", async data => {
|
|
547
|
-
_FileTide.outputGradient(`[${userID}] Successfully received all ${data.totalItemsSent} contents in ${data.senderID}'s file list!`, significantMessageColors);
|
|
560
|
+
_FileTide.outputGradient(`[${userID}] Successfully received all ${HUDUtilityManager.convertNumberToMoneyFormat(data.totalItemsSent, false)} contents in ${data.senderID}'s file list!`, significantMessageColors);
|
|
548
561
|
if (onFileListReceived) {
|
|
549
562
|
onFileListReceived(data);
|
|
550
563
|
}
|
|
551
564
|
});
|
|
552
565
|
client.clientTide.onEvent(userID, "client-file-list", async data => {
|
|
553
|
-
_FileTide.outputGradient(`[${userID}] Received ${data.totalItems} directory contents from ${data.senderID}'s file list!`, significantMessageColors);
|
|
566
|
+
_FileTide.outputGradient(`[${userID}] Received ${HUDUtilityManager.convertNumberToMoneyFormat(data.totalItems, false)} directory contents from ${data.senderID}'s file list!`, significantMessageColors);
|
|
554
567
|
if (onListFiles) {
|
|
555
568
|
onListFiles(data);
|
|
556
569
|
}
|
|
@@ -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": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@trap_stevo/iotide": "^0.0.37",
|
|
33
33
|
"@trap_stevo/iotide-client": "^0.0.23",
|
|
34
|
-
"@trap_stevo/legendarybuilderpronodejs-utilities": "^1.0.
|
|
34
|
+
"@trap_stevo/legendarybuilderpronodejs-utilities": "^1.0.43",
|
|
35
35
|
"chalk": "^4.1.2",
|
|
36
36
|
"readline": "^1.3.0"
|
|
37
37
|
},
|