@trap_stevo/filetide 0.0.46 → 0.0.48
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/FileMessager.js
CHANGED
|
@@ -325,7 +325,7 @@ class FileMessager {
|
|
|
325
325
|
...data,
|
|
326
326
|
transferType: "send"
|
|
327
327
|
});
|
|
328
|
-
this.transferQueue.waitForData(data.transferID, () => this.currentTransferBarrierTransfers.get(data.transferID), [true, false], 100, 50000).then(accepted => {
|
|
328
|
+
this.transferQueue.waitForData(data.transferID, () => this.currentTransferBarrierTransfers.get(data.transferID), [true, false], 100, data.transferExpirationTime ? data.transferExpirationTime : 50000).then(accepted => {
|
|
329
329
|
console.log(`[FileTide ~ Net Barrier] ~ Transfer ${accepted ? "accepted!" : "denied."}`);
|
|
330
330
|
this.fileNet.emitToTide(senderClient.tideID, "transfer-barrier-response", accepted);
|
|
331
331
|
this.currentTransferBarrierTransfers.delete(data.transferID);
|
|
@@ -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 {
|
|
@@ -67,8 +67,9 @@ class FileMessagerClient {
|
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
async requestTransfer(clientID, senderID, filePath, destinationPath, filterContent = []) {
|
|
71
|
-
const
|
|
70
|
+
async requestTransfer(clientID, senderID, filePath, destinationPath, filterContent = [], transferRequestExpirationTime = 30000) {
|
|
71
|
+
const transferContentType = FileUtilityManager.inferPathType(filePath);
|
|
72
|
+
const transferAllowed = await this.allowedTransfer(clientID, senderID, destinationPath, filePath, "N/A", transferContentType === "file" ? 1 : "N/A", transferContentType, "requestSend", transferRequestExpirationTime);
|
|
72
73
|
if (!transferAllowed) {
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
@@ -89,7 +90,7 @@ class FileMessagerClient {
|
|
|
89
90
|
});
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
|
-
async allowedTransfer(clientID, recipientID, filePath, fileSize, transferType = "send") {
|
|
93
|
+
async allowedTransfer(clientID, recipientID, filePath, originPath, fileSize, fileCount = 1, transferContentType = "file", transferType = "send", transferExpirationTime = 30000) {
|
|
93
94
|
try {
|
|
94
95
|
const currentDate = Date.now();
|
|
95
96
|
const transferID = `${clientID}_${filePath}_${currentDate}`;
|
|
@@ -97,10 +98,16 @@ class FileMessagerClient {
|
|
|
97
98
|
clientID,
|
|
98
99
|
recipientID,
|
|
99
100
|
transferID,
|
|
101
|
+
originPath,
|
|
100
102
|
path: filePath,
|
|
101
103
|
date: currentDate,
|
|
104
|
+
transferExpirationTime,
|
|
105
|
+
timeUntilTransferExpiration: transferExpirationTime,
|
|
106
|
+
itemCount: fileCount,
|
|
107
|
+
itemSize: fileSize,
|
|
108
|
+
transferContentType,
|
|
102
109
|
transferType
|
|
103
|
-
},
|
|
110
|
+
}, transferExpirationTime);
|
|
104
111
|
if (!transferAccepted) {
|
|
105
112
|
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ${recipientID} denied your transfer.`, errorMessageColors);
|
|
106
113
|
return false;
|
|
@@ -124,12 +131,13 @@ class FileMessagerClient {
|
|
|
124
131
|
* @param {string} recipientId - The ID of the recipient.
|
|
125
132
|
* @param {Array} filesData - Array of file data objects from the directory.
|
|
126
133
|
* @param {string} baseDirectory - The base directory path that contains the files.
|
|
127
|
-
* @param {string} destinationPath - The path to which the files should
|
|
128
|
-
* @param {Number} tideSize - The tide size in sending files (500)
|
|
129
|
-
* @param {Number} minTideSize - The minimum tide size in sending files (10)
|
|
130
|
-
* @param {Number} maxTideSize - The maximum tide size in sending files (2000)
|
|
134
|
+
* @param {string} destinationPath - The path to which the files should get sent.
|
|
135
|
+
* @param {Number} tideSize - The tide size in sending files (500).
|
|
136
|
+
* @param {Number} minTideSize - The minimum tide size in sending files (10).
|
|
137
|
+
* @param {Number} maxTideSize - The maximum tide size in sending files (2000).
|
|
138
|
+
* @param {Number} transferRequestExpirationTime - The maximum time until the transfer barrier times out the transfer request.
|
|
131
139
|
*/
|
|
132
|
-
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
140
|
+
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath, tideSize = 500, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000) {
|
|
133
141
|
try {
|
|
134
142
|
const baseDirectoryName = path.basename(baseDirectory);
|
|
135
143
|
const adjustedDestinationPath = FileUtilityManager.normalizePath(path.join(destinationPath, baseDirectoryName));
|
|
@@ -138,7 +146,7 @@ class FileMessagerClient {
|
|
|
138
146
|
totalSize += fileInfo.size;
|
|
139
147
|
});
|
|
140
148
|
const incomingType = this.activeTransferTypes.get(destinationPath);
|
|
141
|
-
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, adjustedDestinationPath, totalSize, "send");
|
|
149
|
+
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, adjustedDestinationPath, baseDirectory, totalSize, filesData.length, "directory", "send", transferRequestExpirationTime);
|
|
142
150
|
if (incomingType) {
|
|
143
151
|
this.activeTransferTypes.delete(destinationPath);
|
|
144
152
|
}
|
|
@@ -149,26 +157,27 @@ class FileMessagerClient {
|
|
|
149
157
|
const relativeFilePath = path.dirname(path.relative(baseDirectory, fileInfo.filePath));
|
|
150
158
|
const fileDestinationPath = FileUtilityManager.normalizePath(path.join(adjustedDestinationPath, relativeFilePath));
|
|
151
159
|
if (fileInfo.largeFile) {
|
|
152
|
-
return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize);
|
|
160
|
+
return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize, transferRequestExpirationTime);
|
|
153
161
|
}
|
|
154
|
-
return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.
|
|
162
|
+
return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileInfo.size, fileDestinationPath, index, tideSize, minTideSize, maxTideSize, transferRequestExpirationTime);
|
|
155
163
|
});
|
|
156
164
|
Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
|
|
157
165
|
} catch (error) {
|
|
158
166
|
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused directory transfer: ${error}`, errorMessageColors);
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
|
-
async sendDirectoryLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destinationPath = null, fileSize, index = 0, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
169
|
+
async sendDirectoryLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destinationPath = null, fileSize, index = 0, tideSize = 500, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000) {
|
|
162
170
|
let initiatingTransfer = false;
|
|
163
171
|
if (index === 0) {
|
|
164
172
|
initiatingTransfer = true;
|
|
165
173
|
}
|
|
166
|
-
return await this.
|
|
174
|
+
return await this.sendFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true, true, true, transferRequestExpirationTime);
|
|
167
175
|
}
|
|
168
|
-
sendDirectoryFile(clientID, recipientId, fileName,
|
|
169
|
-
if (!
|
|
176
|
+
async sendDirectoryFile(clientID, recipientId, fileName, filePath = process.cwd(), fileSize, directoryPath = null, index = 0, tideSize = 200, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000) {
|
|
177
|
+
if (!filePath) {
|
|
170
178
|
return;
|
|
171
179
|
}
|
|
180
|
+
let initiatingTransfer = false;
|
|
172
181
|
if (index === 0) {
|
|
173
182
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
174
183
|
fileName,
|
|
@@ -177,56 +186,16 @@ class FileMessagerClient {
|
|
|
177
186
|
path: directoryPath || filePath,
|
|
178
187
|
fileSize
|
|
179
188
|
});
|
|
189
|
+
initiatingTransfer = true;
|
|
180
190
|
}
|
|
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));
|
|
191
|
+
return await this.sendFile(clientID, recipientId, fileName, filePath, directoryPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true, true, false, transferRequestExpirationTime);
|
|
223
192
|
}
|
|
224
|
-
async
|
|
193
|
+
async sendFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false, largeFile = false, transferRequestExpirationTime = 30000) {
|
|
225
194
|
const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
|
|
226
|
-
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
|
|
195
|
+
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
196
|
const incomingType = this.activeTransferTypes.get(filePath);
|
|
228
197
|
if (!inDirectory && initiatingTransfer) {
|
|
229
|
-
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
|
|
198
|
+
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, filePath, fileSize, 1, "file", "send", transferRequestExpirationTime);
|
|
230
199
|
if (incomingType) {
|
|
231
200
|
this.activeTransferTypes.delete(filePath);
|
|
232
201
|
}
|
|
@@ -257,6 +226,7 @@ class FileMessagerClient {
|
|
|
257
226
|
const maxBatchSize = maxTideSize;
|
|
258
227
|
const minBatchSize = minTideSize;
|
|
259
228
|
let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
|
|
229
|
+
let transferInitiated = false;
|
|
260
230
|
const chunkBatch = [];
|
|
261
231
|
await this.transporter.sendLargeFile(fileHandle, {
|
|
262
232
|
recipientID: recipientId,
|
|
@@ -279,6 +249,13 @@ class FileMessagerClient {
|
|
|
279
249
|
filePath: destination,
|
|
280
250
|
fileSize
|
|
281
251
|
});
|
|
252
|
+
if (!transferInitiated) {
|
|
253
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
254
|
+
chunkBatch
|
|
255
|
+
});
|
|
256
|
+
transferInitiated = true;
|
|
257
|
+
chunkBatch.length = 0;
|
|
258
|
+
}
|
|
282
259
|
if (chunkBatch.length >= batchSize) {
|
|
283
260
|
const now = Date.now();
|
|
284
261
|
const rtt = now - lastSendTime;
|
|
@@ -321,76 +298,13 @@ class FileMessagerClient {
|
|
|
321
298
|
});
|
|
322
299
|
}
|
|
323
300
|
}, this.clientTide);
|
|
324
|
-
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!`, significantMessageColors);
|
|
301
|
+
FileNetUtilityManager.outputGradient(largeFile ? `[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!` : `[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors);
|
|
325
302
|
} catch (error) {
|
|
326
|
-
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}`, errorMessageColors);
|
|
303
|
+
FileNetUtilityManager.outputGradient(largeFile ? `[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}` : `[FileTide ~ File Messager] ~ Error transferring file ~ ${error.message}`, errorMessageColors);
|
|
327
304
|
} finally {
|
|
328
305
|
await fileHandle.close();
|
|
329
306
|
}
|
|
330
307
|
}
|
|
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
308
|
}
|
|
395
309
|
;
|
|
396
310
|
module.exports = FileMessagerClient;
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -176,50 +176,52 @@ class FileTide {
|
|
|
176
176
|
|
|
177
177
|
/**
|
|
178
178
|
* Send files / directories directly to a device.
|
|
179
|
-
* @param {String} recipientID - The ID of the client device to send the data to
|
|
180
|
-
* @param {Buffer} fileData - The path of the data to send
|
|
181
|
-
* @param {String} destinationPath - The destination path on the device
|
|
182
|
-
* @param {Array} filterDirectoryContent - List of paths to filter
|
|
183
|
-
* @param {Number} tideSize - The tide size in sending files (
|
|
184
|
-
* @param {Number}
|
|
185
|
-
* @param {Number}
|
|
179
|
+
* @param {String} recipientID - The ID of the client device to send the data to.
|
|
180
|
+
* @param {Buffer} fileData - The path of the data to send.
|
|
181
|
+
* @param {String} destinationPath - The destination path on the device.
|
|
182
|
+
* @param {Array} filterDirectoryContent - List of paths to filter.
|
|
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).
|
|
185
|
+
* @param {Number} minTideSize - The minimum tide size in sending files (10).
|
|
186
|
+
* @param {Number} maxTideSize - The maximum tide size in sending files (2000).
|
|
187
|
+
* @param {Number} transferRequestExpirationTime - The maximum time until the transfer barrier times out the transfer request.
|
|
186
188
|
*/
|
|
187
|
-
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
189
|
+
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 200, tidalSize = 500, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000) {
|
|
188
190
|
const clientID = this.currentUserID;
|
|
189
191
|
const clientMessager = this.clients.get(clientID);
|
|
190
192
|
if (!clientMessager) {
|
|
191
193
|
FileTide.outputGradient(`[FileTide] Client ~ ${clientID} not found.`, ["#F94144", "#F3722C"]);
|
|
192
|
-
return;
|
|
194
|
+
return false;
|
|
193
195
|
}
|
|
194
196
|
const recipientOnline = await clientMessager.clientTide.emitEventWithResponse(clientID, "check-client-online", "retrieved-client-online", {
|
|
195
197
|
clientID: recipientID
|
|
196
198
|
}, 5000);
|
|
197
199
|
if (!recipientOnline || !recipientOnline.online) {
|
|
198
200
|
FileTide.outputGradient(`[FileTide] ${recipientID} currently not tiding.`, ["#F94144", "#F3722C"]);
|
|
199
|
-
return;
|
|
201
|
+
return false;
|
|
200
202
|
}
|
|
201
203
|
const fileDetails = await this.getPathData(filePath, filterDirectoryContent);
|
|
202
204
|
if (!fileDetails) {
|
|
203
205
|
FileTide.outputGradient(`[${clientID}] File at path ${filePath} not found.`, ["#F94144", "#F3722C"]);
|
|
204
|
-
return;
|
|
206
|
+
return false;
|
|
205
207
|
}
|
|
206
208
|
if (fileDetails.type === "file") {
|
|
207
209
|
if (fileDetails.largeFile) {
|
|
208
210
|
FileTide.outputGradient(`[${clientID}] Sending large file ~ ${fileDetails.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
209
|
-
await clientMessager.
|
|
210
|
-
return;
|
|
211
|
+
await clientMessager.sendFile(clientID, recipientID, fileDetails.fileName, fileDetails.filePath, destinationPath, fileDetails.fileSize, tidalSize, minTideSize, maxTideSize, true, false, true, transferRequestExpirationTime);
|
|
212
|
+
return true;
|
|
211
213
|
}
|
|
212
214
|
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;
|
|
215
|
+
await clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.filePath, destinationPath, fileDetails.content.size, tideSize, minTideSize, maxTideSize, transferRequestExpirationTime);
|
|
216
|
+
return true;
|
|
215
217
|
}
|
|
216
218
|
if (fileDetails.type === "directory") {
|
|
217
219
|
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;
|
|
220
|
+
await clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize, transferRequestExpirationTime);
|
|
221
|
+
return true;
|
|
220
222
|
}
|
|
221
223
|
FileTide.outputGradient(`[FileTide] ~ No active client ~ ${recipientID} found.`, errorMessageColors);
|
|
222
|
-
return;
|
|
224
|
+
return false;
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
/**
|
|
@@ -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
|
}
|
|
@@ -211,6 +211,19 @@ class FileUtilityManager {
|
|
|
211
211
|
return stats.isDirectory();
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Determines the type of a given path (directory or file) based on conventions.
|
|
216
|
+
* @param {string} inputPath - The path to infer.
|
|
217
|
+
* @returns {string} - Returns "directory" if the path has no extension, "file" if it contains an extension.
|
|
218
|
+
*/
|
|
219
|
+
static inferPathType(inputPath) {
|
|
220
|
+
const parsedPath = path.parse(inputPath);
|
|
221
|
+
if (parsedPath.ext) {
|
|
222
|
+
return "file";
|
|
223
|
+
}
|
|
224
|
+
return "directory";
|
|
225
|
+
}
|
|
226
|
+
|
|
214
227
|
/**
|
|
215
228
|
* Helper function to check if a path exists.
|
|
216
229
|
* @param {string} inputPath - The path to check.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trap_stevo/filetide",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.48",
|
|
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": {
|