@trap_stevo/filetide 0.0.39 → 0.0.40
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/data.json +355185 -0
- package/dist/cjs/FileMessager.js +239 -76
- package/dist/cjs/FileMessagerClient.js +142 -38
- package/dist/cjs/FileTide.js +100 -16
- package/dist/cjs/HUDComponents/ChunkCapacitor.js +35 -0
- package/dist/cjs/HUDComponents/ConsoleProgressBarManager.js +5 -1
- package/dist/cjs/HUDManagers/FileTransferManager.js +133 -19
- package/dist/cjs/HUDManagers/FileTransferReceiverManager.js +1 -1
- package/dist/cjs/HUDManagers/FileTransferRecoveryManager.js +94 -0
- package/dist/cjs/HUDManagers/FileUtilityManager.js +118 -61
- package/package.json +2 -2
|
@@ -5,11 +5,13 @@ const {
|
|
|
5
5
|
} = require("@trap_stevo/iotide-client");
|
|
6
6
|
const chalk = require("chalk");
|
|
7
7
|
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
8
9
|
const {
|
|
9
10
|
FileNetUtilityManager,
|
|
10
11
|
significantMessageColors,
|
|
11
12
|
errorMessageColors
|
|
12
13
|
} = require("./HUDManagers/FileNetUtilityManager");
|
|
14
|
+
const FileTransferRecoveryManager = require("./HUDManagers/FileTransferRecoveryManager");
|
|
13
15
|
const {
|
|
14
16
|
FileMessagerConfigManager
|
|
15
17
|
} = require("./HUDManagers/FileMessagerConfigManager");
|
|
@@ -19,7 +21,6 @@ const {
|
|
|
19
21
|
const {
|
|
20
22
|
FileUtilityManager
|
|
21
23
|
} = require("./HUDManagers/FileUtilityManager");
|
|
22
|
-
const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager");
|
|
23
24
|
class FileMessagerClient {
|
|
24
25
|
constructor(options = {}, transportOptions = {
|
|
25
26
|
parallelChunks: 3,
|
|
@@ -27,25 +28,27 @@ class FileMessagerClient {
|
|
|
27
28
|
}) {
|
|
28
29
|
this.clientOptions = FileMessagerConfigManager.getClientOptions(options);
|
|
29
30
|
this.transporter = new FileTransferManager(transportOptions);
|
|
30
|
-
this.progressBarManager = new ConsoleProgressBarManager([], {
|
|
31
|
-
completionMessageColor: chalk.blue.bold
|
|
32
|
-
});
|
|
33
31
|
this.activeTransferTypes = new Map();
|
|
34
32
|
this.clientTide = new HUDIoTide();
|
|
35
33
|
this.clients = new Map();
|
|
36
34
|
}
|
|
37
|
-
createClientInstance(clientID, clientOptions, options = {}) {
|
|
35
|
+
createClientInstance(clientID, clientOptions, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
38
36
|
this.clientTide.createIO(clientID, clientOptions.url, {
|
|
39
37
|
transports: ["websocket"],
|
|
40
38
|
...options
|
|
39
|
+
}, headers, authURL, authHeaders, useAuthentication, queryAuthToken, onConnect, () => {
|
|
40
|
+
FileTransferRecoveryManager.flushToDisk();
|
|
41
|
+
if (onDisconnect) {
|
|
42
|
+
onDisconnect();
|
|
43
|
+
}
|
|
41
44
|
});
|
|
42
45
|
FileNetUtilityManager.outputGradient(`\n[FileTide ~ File Messager] ~ Created client with ID ${clientID} and socket ${clientID}!`, significantMessageColors);
|
|
43
46
|
return clientID;
|
|
44
47
|
}
|
|
45
|
-
joinRoom(userID, roomName, options = {}) {
|
|
48
|
+
joinRoom(userID, roomName, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
46
49
|
const socketName = this.createClientInstance(userID, {
|
|
47
50
|
url: this.clientOptions.url
|
|
48
|
-
}, options);
|
|
51
|
+
}, options, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
49
52
|
this.clientTide.joinChannel(socketName, roomName, userID, () => {
|
|
50
53
|
FileNetUtilityManager.outputGradient(`\n[FileTide ~ File Messager] ~ Client ~ ${userID} joined room ${roomName} successfully!`, significantMessageColors);
|
|
51
54
|
this.clients.set(userID, {
|
|
@@ -111,8 +114,11 @@ class FileMessagerClient {
|
|
|
111
114
|
* @param {Array} filesData - Array of file data objects from the directory.
|
|
112
115
|
* @param {string} baseDirectory - The base directory path that contains the files.
|
|
113
116
|
* @param {string} destinationPath - The path to which the files should be sent.
|
|
117
|
+
* @param {Number} tideSize - The tide size in sending files (500)
|
|
118
|
+
* @param {Number} minTideSize - The minimum tide size in sending files (10)
|
|
119
|
+
* @param {Number} maxTideSize - The maximum tide size in sending files (2000)
|
|
114
120
|
*/
|
|
115
|
-
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath) {
|
|
121
|
+
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
116
122
|
try {
|
|
117
123
|
const baseDirectoryName = path.basename(baseDirectory);
|
|
118
124
|
const adjustedDestinationPath = FileUtilityManager.normalizePath(path.join(destinationPath, baseDirectoryName));
|
|
@@ -131,6 +137,9 @@ class FileMessagerClient {
|
|
|
131
137
|
const sendFilePromises = filesData.map(async (fileInfo, index) => {
|
|
132
138
|
const relativeFilePath = path.dirname(path.relative(baseDirectory, fileInfo.filePath));
|
|
133
139
|
const fileDestinationPath = FileUtilityManager.normalizePath(path.join(adjustedDestinationPath, relativeFilePath));
|
|
140
|
+
if (fileInfo.largeFile) {
|
|
141
|
+
return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize);
|
|
142
|
+
}
|
|
134
143
|
return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.fileData, fileDestinationPath, fileInfo.size, adjustedDestinationPath, index);
|
|
135
144
|
});
|
|
136
145
|
Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
|
|
@@ -138,29 +147,28 @@ class FileMessagerClient {
|
|
|
138
147
|
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused directory transfer: ${error}`, errorMessageColors);
|
|
139
148
|
}
|
|
140
149
|
}
|
|
150
|
+
async sendDirectoryLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destinationPath = null, fileSize, index = 0, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
151
|
+
let initiatingTransfer = false;
|
|
152
|
+
if (index === 0) {
|
|
153
|
+
initiatingTransfer = true;
|
|
154
|
+
}
|
|
155
|
+
return await this.sendLargeFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true);
|
|
156
|
+
}
|
|
141
157
|
sendDirectoryFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize, directoryPath = null, index = 0) {
|
|
142
158
|
if (!file) {
|
|
143
159
|
return;
|
|
144
160
|
}
|
|
145
161
|
if (index === 0) {
|
|
146
|
-
this.progressBarManager.completionMessage = `Successfully sent to ${recipientId}!`;
|
|
147
|
-
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
148
|
-
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
149
162
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
150
163
|
fileName,
|
|
151
164
|
senderID: clientID,
|
|
152
165
|
recipientID: recipientId,
|
|
153
|
-
path: directoryPath || filePath
|
|
166
|
+
path: directoryPath || filePath,
|
|
167
|
+
fileSize
|
|
154
168
|
});
|
|
155
169
|
}
|
|
156
170
|
this.transporter.sendFile(file, {
|
|
157
171
|
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
158
|
-
if (chunkIndex === 0) {
|
|
159
|
-
this.progressBarManager.addTask({
|
|
160
|
-
name: fileName,
|
|
161
|
-
size: fileSize
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
172
|
return new Promise((resolve, reject) => {
|
|
165
173
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
166
174
|
senderID: clientID,
|
|
@@ -187,19 +195,124 @@ class FileMessagerClient {
|
|
|
187
195
|
resolve();
|
|
188
196
|
});
|
|
189
197
|
},
|
|
190
|
-
onProgress: (progress, chunkSize) => {
|
|
191
|
-
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
192
|
-
},
|
|
193
198
|
originDetails: {
|
|
194
199
|
recipientID: recipientId,
|
|
195
200
|
senderID: clientID
|
|
196
201
|
},
|
|
202
|
+
recipientID: recipientId,
|
|
197
203
|
fileDetails: {
|
|
204
|
+
destinationPath: filePath,
|
|
198
205
|
name: fileName,
|
|
199
206
|
path: filePath,
|
|
200
207
|
size: fileSize
|
|
201
208
|
}
|
|
202
|
-
}).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer: ${error}`, errorMessageColors));
|
|
209
|
+
}, 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));
|
|
210
|
+
}
|
|
211
|
+
async sendLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false) {
|
|
212
|
+
const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
|
|
213
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
|
|
214
|
+
const incomingType = this.activeTransferTypes.get(filePath);
|
|
215
|
+
if (!inDirectory && initiatingTransfer) {
|
|
216
|
+
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
|
|
217
|
+
if (incomingType) {
|
|
218
|
+
this.activeTransferTypes.delete(filePath);
|
|
219
|
+
}
|
|
220
|
+
if (!transferAllowed) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
224
|
+
fileName,
|
|
225
|
+
senderID: clientID,
|
|
226
|
+
recipientID: recipientId,
|
|
227
|
+
path: destination,
|
|
228
|
+
fileSize
|
|
229
|
+
});
|
|
230
|
+
} else if (inDirectory && !initiatingTransfer) {
|
|
231
|
+
if (incomingType) {
|
|
232
|
+
this.activeTransferTypes.delete(filePath);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const fileHandle = await fs.promises.open(filePath, "r");
|
|
236
|
+
const fileDetails = {
|
|
237
|
+
destinationPath,
|
|
238
|
+
name: fileName,
|
|
239
|
+
path: filePath,
|
|
240
|
+
size: fileSize
|
|
241
|
+
};
|
|
242
|
+
try {
|
|
243
|
+
let lastSendTime = Date.now();
|
|
244
|
+
const maxBatchSize = maxTideSize;
|
|
245
|
+
const minBatchSize = minTideSize;
|
|
246
|
+
let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
|
|
247
|
+
const chunkBatch = [];
|
|
248
|
+
await this.transporter.sendLargeFile(fileHandle, {
|
|
249
|
+
recipientID: recipientId,
|
|
250
|
+
originDetails: {
|
|
251
|
+
recipientID: recipientId,
|
|
252
|
+
senderID: clientID
|
|
253
|
+
},
|
|
254
|
+
fileDetails,
|
|
255
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
256
|
+
return new Promise(resolve => {
|
|
257
|
+
chunkBatch.push({
|
|
258
|
+
senderID: clientID,
|
|
259
|
+
recipientId,
|
|
260
|
+
fileName,
|
|
261
|
+
fileChunk: chunkData,
|
|
262
|
+
completedChunks,
|
|
263
|
+
totalChunks,
|
|
264
|
+
chunkIndex,
|
|
265
|
+
chunkSize,
|
|
266
|
+
filePath: destination,
|
|
267
|
+
fileSize
|
|
268
|
+
});
|
|
269
|
+
if (chunkBatch.length >= batchSize) {
|
|
270
|
+
const now = Date.now();
|
|
271
|
+
const rtt = now - lastSendTime;
|
|
272
|
+
lastSendTime = now;
|
|
273
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
274
|
+
chunkBatch
|
|
275
|
+
});
|
|
276
|
+
chunkBatch.length = 0;
|
|
277
|
+
if (rtt >= 200 && batchSize < maxBatchSize) {
|
|
278
|
+
batchSize = Math.min(batchSize + 50, maxBatchSize);
|
|
279
|
+
} else if (rtt < 200 && batchSize > minBatchSize) {
|
|
280
|
+
batchSize = Math.max(batchSize - 50, minBatchSize);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
resolve();
|
|
284
|
+
});
|
|
285
|
+
},
|
|
286
|
+
onComplete: transferId => {
|
|
287
|
+
return new Promise(resolve => {
|
|
288
|
+
if (chunkBatch.length > 0) {
|
|
289
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
290
|
+
chunkBatch
|
|
291
|
+
});
|
|
292
|
+
chunkBatch.length = 0;
|
|
293
|
+
}
|
|
294
|
+
this.clientTide.emitEvent(clientID, "transfer-complete", {
|
|
295
|
+
senderID: clientID,
|
|
296
|
+
recipientId,
|
|
297
|
+
fileName,
|
|
298
|
+
filePath: destination
|
|
299
|
+
});
|
|
300
|
+
resolve();
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
onTiding: () => {
|
|
304
|
+
this.clientTide.emitEvent(clientID, "client-tiding", {
|
|
305
|
+
senderID: clientID,
|
|
306
|
+
message: "Transfer ongoing..."
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}, this.clientTide);
|
|
310
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!`, significantMessageColors);
|
|
311
|
+
} catch (error) {
|
|
312
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}`, errorMessageColors);
|
|
313
|
+
} finally {
|
|
314
|
+
await fileHandle.close();
|
|
315
|
+
}
|
|
203
316
|
}
|
|
204
317
|
async sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize) {
|
|
205
318
|
if (!file) {
|
|
@@ -215,29 +328,22 @@ class FileMessagerClient {
|
|
|
215
328
|
if (!transferAllowed) {
|
|
216
329
|
return;
|
|
217
330
|
}
|
|
218
|
-
this.progressBarManager.completionMessage = `Successfully sent to ${recipientId}!`;
|
|
219
|
-
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
220
|
-
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
221
331
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
222
332
|
fileName,
|
|
223
333
|
senderID: clientID,
|
|
224
334
|
recipientID: recipientId,
|
|
225
|
-
path: filePath
|
|
335
|
+
path: filePath,
|
|
336
|
+
fileSize
|
|
226
337
|
});
|
|
227
|
-
this.transporter.sendFile(file, {
|
|
228
|
-
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
229
|
-
if (chunkIndex === 0) {
|
|
230
|
-
this.progressBarManager.addTask({
|
|
231
|
-
name: fileName,
|
|
232
|
-
size: fileSize
|
|
233
|
-
});
|
|
234
|
-
}
|
|
338
|
+
await this.transporter.sendFile(file, {
|
|
339
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
235
340
|
return new Promise((resolve, reject) => {
|
|
236
341
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
237
342
|
senderID: clientID,
|
|
238
343
|
recipientId,
|
|
239
344
|
fileName,
|
|
240
345
|
fileChunk: chunkData,
|
|
346
|
+
completedChunks,
|
|
241
347
|
totalChunks,
|
|
242
348
|
chunkIndex,
|
|
243
349
|
chunkSize,
|
|
@@ -258,19 +364,17 @@ class FileMessagerClient {
|
|
|
258
364
|
resolve();
|
|
259
365
|
});
|
|
260
366
|
},
|
|
261
|
-
onProgress: (progress, chunkSize) => {
|
|
262
|
-
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
263
|
-
},
|
|
264
367
|
originDetails: {
|
|
265
368
|
recipientID: recipientId,
|
|
266
369
|
senderID: clientID
|
|
267
370
|
},
|
|
268
371
|
fileDetails: {
|
|
372
|
+
destinationPath,
|
|
269
373
|
name: fileName,
|
|
270
374
|
path: filePath,
|
|
271
375
|
size: fileSize
|
|
272
376
|
}
|
|
273
|
-
}).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer
|
|
377
|
+
}, 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));
|
|
274
378
|
}
|
|
275
379
|
}
|
|
276
380
|
;
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
const {
|
|
16
16
|
FileTransferReceiverManager
|
|
17
17
|
} = require("./HUDManagers/FileTransferReceiverManager.js");
|
|
18
|
+
const FileTransferRecoveryManager = require("./HUDManagers/FileTransferRecoveryManager.js");
|
|
18
19
|
const {
|
|
19
20
|
FileNetConfigManager
|
|
20
21
|
} = require("./HUDManagers/FileNetConfigManager.js");
|
|
@@ -22,6 +23,7 @@ const {
|
|
|
22
23
|
FileUtilityManager
|
|
23
24
|
} = require("./HUDManagers/FileUtilityManager.js");
|
|
24
25
|
const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager");
|
|
26
|
+
const ChunkCapacitor = require("./HUDComponents/ChunkCapacitor.js");
|
|
25
27
|
const ConsoleTable = require("./HUDComponents/ConsoleTable.js");
|
|
26
28
|
const FileMessagerClient = require("./FileMessagerClient");
|
|
27
29
|
const FileMessager = require("./FileMessager");
|
|
@@ -75,13 +77,20 @@ class FileTide {
|
|
|
75
77
|
* @param {Function} onTransferProgress - Callback for when an current transfers progress
|
|
76
78
|
* @param {Boolean} [enableTransferBarrier=true] - Whether to enable the transfer barrier
|
|
77
79
|
* @param {Object} [options = {}] - Additional options
|
|
80
|
+
* @param {Object} [headers = {}] - Additional connection headers
|
|
81
|
+
* @param {Function} onConnect - Callback for when the client connects to the desired server
|
|
82
|
+
* @param {Function} onDisconnect - Callback for when the client disconnects from the desired server
|
|
83
|
+
* @param {String} authURL - The destination of the connection authentication functionality
|
|
84
|
+
* @param {Object} [authHeaders = {}] - Additional connection authentication headers
|
|
85
|
+
* @param {Boolean} [useAuthentication=true] - Whether to enable connection authentication
|
|
86
|
+
* @param {Boolean} [queryAuthToken=false] - Whether to enable connection authentication tokens
|
|
78
87
|
*/
|
|
79
|
-
launchMessager(clientOptions = {}, connectionOptions = {}, roomName, userID, onLaunch, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, enableTransferBarrier = true, options = {}) {
|
|
88
|
+
launchMessager(clientOptions = {}, connectionOptions = {}, roomName, userID, onLaunch, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, enableTransferBarrier = true, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
80
89
|
if (this.clients.has(userID)) {
|
|
81
90
|
this.stopMessager(userID);
|
|
82
91
|
}
|
|
83
92
|
const newClient = new FileMessagerClient(clientOptions);
|
|
84
|
-
newClient.joinRoom(userID, roomName, connectionOptions);
|
|
93
|
+
newClient.joinRoom(userID, roomName, connectionOptions, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
85
94
|
this.transferBarrier = enableTransferBarrier;
|
|
86
95
|
this.clientShorePolicies.set(userID, [FileUtilityManager.getTidePath(">CurrentUser"), FileUtilityManager.getTidePath(">Downloads"), FileUtilityManager.getTidePath(">Documents")]);
|
|
87
96
|
this.clients.set(userID, newClient);
|
|
@@ -104,6 +113,9 @@ class FileTide {
|
|
|
104
113
|
getTidePath(inputPath) {
|
|
105
114
|
return FileUtilityManager.getTidePath(inputPath);
|
|
106
115
|
}
|
|
116
|
+
saveTransferStates() {
|
|
117
|
+
FileTransferRecoveryManager.flushToDisk();
|
|
118
|
+
}
|
|
107
119
|
filterFilesAndDirectories(dirPath, filterContent = [], callback) {
|
|
108
120
|
FileUtilityManager.filterFilesAndDirectories(dirPath, filterContent, (files, error) => {
|
|
109
121
|
if (callback) {
|
|
@@ -120,8 +132,8 @@ class FileTide {
|
|
|
120
132
|
}
|
|
121
133
|
clientMessager.listFiles(clientID, recipientID, depth);
|
|
122
134
|
}
|
|
123
|
-
async listFiles(directories, depth = 1) {
|
|
124
|
-
return await FileUtilityManager.listFiles(directories, depth);
|
|
135
|
+
async listFiles(directories, depth = 1, onDirectory) {
|
|
136
|
+
return await FileUtilityManager.listFiles(directories, depth, onDirectory);
|
|
125
137
|
}
|
|
126
138
|
clearShorePolicies(clientID, shores = []) {
|
|
127
139
|
let clientShorePolicies = this.clientShorePolicies.get(clientID);
|
|
@@ -153,8 +165,11 @@ class FileTide {
|
|
|
153
165
|
* @param {Buffer} fileData - The path of the data to send
|
|
154
166
|
* @param {String} destinationPath - The destination path on the device
|
|
155
167
|
* @param {Array} filterDirectoryContent - List of paths to filter
|
|
168
|
+
* @param {Number} tideSize - The tide size in sending files (500)
|
|
169
|
+
* @param {Number} minTideSize - The minimum tide size in sending files (10)
|
|
170
|
+
* @param {Number} maxTideSize - The maximum tide size in sending files (2000)
|
|
156
171
|
*/
|
|
157
|
-
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = []) {
|
|
172
|
+
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
158
173
|
const clientID = this.currentUserID;
|
|
159
174
|
const clientMessager = this.clients.get(clientID);
|
|
160
175
|
if (!clientMessager) {
|
|
@@ -167,13 +182,18 @@ class FileTide {
|
|
|
167
182
|
return;
|
|
168
183
|
}
|
|
169
184
|
if (fileDetails.type === "file") {
|
|
185
|
+
if (fileDetails.largeFile) {
|
|
186
|
+
FileTide.outputGradient(`[${clientID}] Sending large file ~ ${fileDetails.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
187
|
+
await clientMessager.sendLargeFile(clientID, recipientID, fileDetails.fileName, fileDetails.filePath, destinationPath, fileDetails.fileSize, tideSize, minTideSize, maxTideSize);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
170
190
|
FileTide.outputGradient(`[${clientID}] Sending file ~ ${fileDetails.content.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
171
191
|
clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.fileData, destinationPath, fileDetails.content.size);
|
|
172
192
|
return;
|
|
173
193
|
}
|
|
174
194
|
if (fileDetails.type === "directory") {
|
|
175
195
|
FileTide.outputGradient(`[${clientID}] Sending ${fileDetails.content.length} files in directory ~ ${path.basename(filePath)} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
176
|
-
clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath);
|
|
196
|
+
clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
|
|
177
197
|
return;
|
|
178
198
|
}
|
|
179
199
|
FileTide.outputGradient(`[FileTide] ~ No active client ~ ${recipientID} found.`, errorMessageColors);
|
|
@@ -241,7 +261,8 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
241
261
|
onTransferRequested,
|
|
242
262
|
onTransferStatus,
|
|
243
263
|
onListFiles,
|
|
244
|
-
onCurrentOnlineClients
|
|
264
|
+
onCurrentOnlineClients,
|
|
265
|
+
onClientTiding
|
|
245
266
|
} = options;
|
|
246
267
|
const cliTable = new ConsoleTable({
|
|
247
268
|
padding: 2,
|
|
@@ -287,6 +308,11 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
287
308
|
onCurrentOnlineClients(currentClients, true);
|
|
288
309
|
}
|
|
289
310
|
});
|
|
311
|
+
client.clientTide.onEvent(userID, "current-client-tiding", data => {
|
|
312
|
+
if (onClientTiding) {
|
|
313
|
+
onClientTiding(data.message, significantMessageColors);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
290
316
|
client.clientTide.onEvent(userID, "current-clients", data => {
|
|
291
317
|
const currentClients = {};
|
|
292
318
|
Object.keys(data).forEach(key => {
|
|
@@ -302,6 +328,23 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
302
328
|
onCurrentOnlineClients(currentClients, false);
|
|
303
329
|
}
|
|
304
330
|
});
|
|
331
|
+
client.clientTide.onEvent(userID, "save-current-transfer-states", async data => {
|
|
332
|
+
this.saveTransferStates();
|
|
333
|
+
return;
|
|
334
|
+
});
|
|
335
|
+
client.clientTide.onEvent(userID, "current-transfer-state", async data => {
|
|
336
|
+
const {
|
|
337
|
+
senderID,
|
|
338
|
+
filePath
|
|
339
|
+
} = data;
|
|
340
|
+
const currentTransferState = FileTransferRecoveryManager.getTransferState(userID, senderID, filePath);
|
|
341
|
+
client.clientTide.emitEvent(userID, "send-current-transfer-state", {
|
|
342
|
+
recipientID: userID,
|
|
343
|
+
senderID,
|
|
344
|
+
transferState: currentTransferState
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
});
|
|
305
348
|
client.clientTide.onEvent(userID, "queue-incoming-transfer", async data => {
|
|
306
349
|
if (this.transferBarrier && onIncomingTransfer) {
|
|
307
350
|
onIncomingTransfer(data, status => {
|
|
@@ -320,6 +363,16 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
320
363
|
return;
|
|
321
364
|
});
|
|
322
365
|
client.clientTide.onEvent(userID, "incoming-transfer", async data => {
|
|
366
|
+
const {
|
|
367
|
+
currentSender
|
|
368
|
+
} = data;
|
|
369
|
+
if (currentSender && currentSender === userID) {
|
|
370
|
+
_FileTide.outputGradient(`[${userID}] Transfer successfully sent to ${data.recipientID}`, significantMessageColors);
|
|
371
|
+
this.progressBarManager.completionMessage = `Successfully sent to ${data.recipientID}!`;
|
|
372
|
+
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
373
|
+
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
323
376
|
_FileTide.outputGradient(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`, significantMessageColors);
|
|
324
377
|
if (onTransferStart) {
|
|
325
378
|
onTransferStart(data);
|
|
@@ -371,11 +424,29 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
371
424
|
}
|
|
372
425
|
await fileTransferReceiver.handleTransferProgress(data);
|
|
373
426
|
this.progressBarManager.updateTaskProgress(data.fileName, data.chunkSize || 512 * 1024);
|
|
427
|
+
const currentTransferState = FileTransferRecoveryManager.getTransferState(userID, data.senderName, data.path) || {
|
|
428
|
+
transferredSize: 0
|
|
429
|
+
};
|
|
430
|
+
currentTransferState.transferredSize += data.chunkSize || 512 * 1024;
|
|
431
|
+
FileTransferRecoveryManager.saveTransferState(userID, data.senderName, data.path, data.chunkIndex, currentTransferState.transferredSize);
|
|
374
432
|
if (onTransferProgress) {
|
|
375
433
|
onTransferProgress(data);
|
|
376
434
|
}
|
|
377
435
|
});
|
|
378
436
|
client.clientTide.onEvent(userID, "transfer-status", data => {
|
|
437
|
+
const {
|
|
438
|
+
chunkIndex,
|
|
439
|
+
chunkSize,
|
|
440
|
+
fileName,
|
|
441
|
+
fileSize
|
|
442
|
+
} = data;
|
|
443
|
+
if (chunkIndex === 0) {
|
|
444
|
+
this.progressBarManager.addTask({
|
|
445
|
+
name: fileName,
|
|
446
|
+
size: fileSize
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
379
450
|
if (onTransferStatus) {
|
|
380
451
|
onTransferStatus(data);
|
|
381
452
|
}
|
|
@@ -389,11 +460,12 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
389
460
|
if (!transferState) {
|
|
390
461
|
return;
|
|
391
462
|
}
|
|
392
|
-
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success) => {
|
|
463
|
+
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success, error) => {
|
|
393
464
|
if (success) {
|
|
465
|
+
FileTransferRecoveryManager.clearTransferState(userID, data.senderID, data.filePath);
|
|
394
466
|
_FileTide.outputGradient(`[${userID}] File saved at : ${savePath}\n`, significantMessageColors);
|
|
395
467
|
} else if (!success) {
|
|
396
|
-
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n`, errorMessageColors);
|
|
468
|
+
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n\t${error}\n`, errorMessageColors);
|
|
397
469
|
}
|
|
398
470
|
if (onTransferComplete) {
|
|
399
471
|
onTransferComplete(data, fileTransferReceiver.activeTransfers, success);
|
|
@@ -416,17 +488,29 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
416
488
|
return;
|
|
417
489
|
});
|
|
418
490
|
client.clientTide.onEvent(userID, "list-files", async data => {
|
|
419
|
-
_FileTide.outputGradient(`[${userID}] Sending file list
|
|
491
|
+
_FileTide.outputGradient(`[${userID}] Sending file list to ${data.senderID}...!`, significantMessageColors);
|
|
420
492
|
const currentClientShorePolicies = this.getShorePolicies(userID);
|
|
421
|
-
const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
493
|
+
const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1, (totalItems, directoryContents) => {
|
|
494
|
+
const capacitor = new ChunkCapacitor(directoryContents, 100);
|
|
495
|
+
const contents = capacitor.getAllChunks();
|
|
496
|
+
for (let files of contents) {
|
|
497
|
+
client.clientTide.emitEvent(userID, "send-file-list-to-client", {
|
|
498
|
+
senderID: data.recipientID,
|
|
499
|
+
recipientID: data.senderID,
|
|
500
|
+
totalItems: files.length,
|
|
501
|
+
listedFiles: files
|
|
502
|
+
});
|
|
503
|
+
}
|
|
426
504
|
});
|
|
505
|
+
setTimeout(() => {
|
|
506
|
+
_FileTide.outputGradient(`[${userID}] Sent file list to ${data.senderID}!`, significantMessageColors);
|
|
507
|
+
}, 1000);
|
|
508
|
+
});
|
|
509
|
+
client.clientTide.onEvent(userID, "error", async error => {
|
|
510
|
+
_FileTide.outputGradient(`[${userID} | FileTide Error] ${error}`, errorMessageColors);
|
|
427
511
|
});
|
|
428
512
|
client.clientTide.onEvent(userID, "client-file-list", async data => {
|
|
429
|
-
_FileTide.outputGradient(`[${userID}]
|
|
513
|
+
_FileTide.outputGradient(`[${userID}] Received ${data.totalItems} directory contents from ${data.senderID}'s file list!`, significantMessageColors);
|
|
430
514
|
if (onListFiles) {
|
|
431
515
|
onListFiles(data);
|
|
432
516
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
class ChunkCapacitor {
|
|
4
|
+
constructor(list, chunkSize = 100) {
|
|
5
|
+
this.list = list;
|
|
6
|
+
this.chunkSize = chunkSize;
|
|
7
|
+
this.chunks = this.createChunks();
|
|
8
|
+
}
|
|
9
|
+
createChunks() {
|
|
10
|
+
const chunks = [];
|
|
11
|
+
for (let i = 0; i < this.list.length; i += this.chunkSize) {
|
|
12
|
+
const chunk = this.list.slice(i, i + this.chunkSize);
|
|
13
|
+
chunks.push(chunk);
|
|
14
|
+
}
|
|
15
|
+
return chunks;
|
|
16
|
+
}
|
|
17
|
+
getChunk(index) {
|
|
18
|
+
if (index < 0 || index >= this.chunks.length) {
|
|
19
|
+
console.log("Chunk index out of bounds.");
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return this.chunks[index];
|
|
23
|
+
}
|
|
24
|
+
getTotalChunks() {
|
|
25
|
+
return this.chunks.length;
|
|
26
|
+
}
|
|
27
|
+
getTotalItems() {
|
|
28
|
+
return this.list.length;
|
|
29
|
+
}
|
|
30
|
+
getAllChunks() {
|
|
31
|
+
return this.chunks;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
;
|
|
35
|
+
module.exports = ChunkCapacitor;
|
|
@@ -123,7 +123,11 @@ class ConsoleProgressBarManager {
|
|
|
123
123
|
newBar.speed = speed;
|
|
124
124
|
const filledLength = Math.round(settings.barLength * (newBar.current / newBar.totalSize));
|
|
125
125
|
const bar = settings.barColor(settings.filledChar.repeat(filledLength)) + settings.unfilledChar.repeat(settings.barLength - filledLength);
|
|
126
|
-
|
|
126
|
+
try {
|
|
127
|
+
process.stdout.write(`${settings.taskNameColor(newBar.taskName)} > ${settings.totalSizeColor(newBar.getFormattedSize(newBar.totalSize))} | ${settings.sizeTransferredColor(newBar.getFormattedSize(newBar.current))} ${settings.speedColor(`${speedData.current} ${speedData.unit}/s`)} | ${settings.taskETAColor(this.convertSeconds(timeLeft.toFixed(2)))} [${bar}] ${settings.percentageColor(percentage.toFixed(2) + "%")}`);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.log(error);
|
|
130
|
+
}
|
|
127
131
|
},
|
|
128
132
|
update: amount => {
|
|
129
133
|
newBar.current += amount;
|