@trap_stevo/filetide 0.0.39 → 0.0.41
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 +306 -83
- package/dist/cjs/FileMessagerClient.js +149 -43
- package/dist/cjs/FileTide.js +116 -17
- 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 +3 -3
|
@@ -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,31 +28,35 @@ 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);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
}, options, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
52
|
+
return () => {
|
|
53
|
+
this.clientTide.joinChannel(socketName, roomName, userID, () => {
|
|
54
|
+
FileNetUtilityManager.outputGradient(`\n[FileTide ~ File Messager] ~ Client ~ ${userID} joined room ${roomName} successfully!`, significantMessageColors);
|
|
55
|
+
this.clients.set(userID, {
|
|
56
|
+
roomName
|
|
57
|
+
});
|
|
53
58
|
});
|
|
54
|
-
}
|
|
59
|
+
};
|
|
55
60
|
}
|
|
56
61
|
async requestTransfer(clientID, senderID, filePath, destinationPath, filterContent = []) {
|
|
57
62
|
const transferAllowed = await this.allowedTransfer(clientID, senderID, destinationPath, "N/A", "requestSend");
|
|
@@ -111,8 +116,11 @@ class FileMessagerClient {
|
|
|
111
116
|
* @param {Array} filesData - Array of file data objects from the directory.
|
|
112
117
|
* @param {string} baseDirectory - The base directory path that contains the files.
|
|
113
118
|
* @param {string} destinationPath - The path to which the files should be sent.
|
|
119
|
+
* @param {Number} tideSize - The tide size in sending files (500)
|
|
120
|
+
* @param {Number} minTideSize - The minimum tide size in sending files (10)
|
|
121
|
+
* @param {Number} maxTideSize - The maximum tide size in sending files (2000)
|
|
114
122
|
*/
|
|
115
|
-
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath) {
|
|
123
|
+
async sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
116
124
|
try {
|
|
117
125
|
const baseDirectoryName = path.basename(baseDirectory);
|
|
118
126
|
const adjustedDestinationPath = FileUtilityManager.normalizePath(path.join(destinationPath, baseDirectoryName));
|
|
@@ -131,6 +139,9 @@ class FileMessagerClient {
|
|
|
131
139
|
const sendFilePromises = filesData.map(async (fileInfo, index) => {
|
|
132
140
|
const relativeFilePath = path.dirname(path.relative(baseDirectory, fileInfo.filePath));
|
|
133
141
|
const fileDestinationPath = FileUtilityManager.normalizePath(path.join(adjustedDestinationPath, relativeFilePath));
|
|
142
|
+
if (fileInfo.largeFile) {
|
|
143
|
+
return await this.sendDirectoryLargeFile(clientID, recipientId, fileInfo.fileName, fileInfo.filePath, fileDestinationPath, fileInfo.fileSize, index, tideSize, minTideSize, maxTideSize);
|
|
144
|
+
}
|
|
134
145
|
return await this.sendDirectoryFile(clientID, recipientId, fileInfo.fileName, fileInfo.fileData, fileDestinationPath, fileInfo.size, adjustedDestinationPath, index);
|
|
135
146
|
});
|
|
136
147
|
Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
|
|
@@ -138,29 +149,28 @@ class FileMessagerClient {
|
|
|
138
149
|
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused directory transfer: ${error}`, errorMessageColors);
|
|
139
150
|
}
|
|
140
151
|
}
|
|
152
|
+
async sendDirectoryLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destinationPath = null, fileSize, index = 0, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
153
|
+
let initiatingTransfer = false;
|
|
154
|
+
if (index === 0) {
|
|
155
|
+
initiatingTransfer = true;
|
|
156
|
+
}
|
|
157
|
+
return await this.sendLargeFile(clientID, recipientId, fileName, filePath, destinationPath, fileSize, tideSize, minTideSize, maxTideSize, initiatingTransfer, true);
|
|
158
|
+
}
|
|
141
159
|
sendDirectoryFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize, directoryPath = null, index = 0) {
|
|
142
160
|
if (!file) {
|
|
143
161
|
return;
|
|
144
162
|
}
|
|
145
163
|
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
164
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
150
165
|
fileName,
|
|
151
166
|
senderID: clientID,
|
|
152
167
|
recipientID: recipientId,
|
|
153
|
-
path: directoryPath || filePath
|
|
168
|
+
path: directoryPath || filePath,
|
|
169
|
+
fileSize
|
|
154
170
|
});
|
|
155
171
|
}
|
|
156
172
|
this.transporter.sendFile(file, {
|
|
157
173
|
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
158
|
-
if (chunkIndex === 0) {
|
|
159
|
-
this.progressBarManager.addTask({
|
|
160
|
-
name: fileName,
|
|
161
|
-
size: fileSize
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
174
|
return new Promise((resolve, reject) => {
|
|
165
175
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
166
176
|
senderID: clientID,
|
|
@@ -187,19 +197,124 @@ class FileMessagerClient {
|
|
|
187
197
|
resolve();
|
|
188
198
|
});
|
|
189
199
|
},
|
|
190
|
-
onProgress: (progress, chunkSize) => {
|
|
191
|
-
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
192
|
-
},
|
|
193
200
|
originDetails: {
|
|
194
201
|
recipientID: recipientId,
|
|
195
202
|
senderID: clientID
|
|
196
203
|
},
|
|
204
|
+
recipientID: recipientId,
|
|
197
205
|
fileDetails: {
|
|
206
|
+
destinationPath: filePath,
|
|
198
207
|
name: fileName,
|
|
199
208
|
path: filePath,
|
|
200
209
|
size: fileSize
|
|
201
210
|
}
|
|
202
|
-
}).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer: ${error}`, errorMessageColors));
|
|
211
|
+
}, 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));
|
|
212
|
+
}
|
|
213
|
+
async sendLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false) {
|
|
214
|
+
const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
|
|
215
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
|
|
216
|
+
const incomingType = this.activeTransferTypes.get(filePath);
|
|
217
|
+
if (!inDirectory && initiatingTransfer) {
|
|
218
|
+
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, fileSize, "send");
|
|
219
|
+
if (incomingType) {
|
|
220
|
+
this.activeTransferTypes.delete(filePath);
|
|
221
|
+
}
|
|
222
|
+
if (!transferAllowed) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
226
|
+
fileName,
|
|
227
|
+
senderID: clientID,
|
|
228
|
+
recipientID: recipientId,
|
|
229
|
+
path: destination,
|
|
230
|
+
fileSize
|
|
231
|
+
});
|
|
232
|
+
} else if (inDirectory && !initiatingTransfer) {
|
|
233
|
+
if (incomingType) {
|
|
234
|
+
this.activeTransferTypes.delete(filePath);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const fileHandle = await fs.promises.open(filePath, "r");
|
|
238
|
+
const fileDetails = {
|
|
239
|
+
destinationPath,
|
|
240
|
+
name: fileName,
|
|
241
|
+
path: filePath,
|
|
242
|
+
size: fileSize
|
|
243
|
+
};
|
|
244
|
+
try {
|
|
245
|
+
let lastSendTime = Date.now();
|
|
246
|
+
const maxBatchSize = maxTideSize;
|
|
247
|
+
const minBatchSize = minTideSize;
|
|
248
|
+
let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
|
|
249
|
+
const chunkBatch = [];
|
|
250
|
+
await this.transporter.sendLargeFile(fileHandle, {
|
|
251
|
+
recipientID: recipientId,
|
|
252
|
+
originDetails: {
|
|
253
|
+
recipientID: recipientId,
|
|
254
|
+
senderID: clientID
|
|
255
|
+
},
|
|
256
|
+
fileDetails,
|
|
257
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
258
|
+
return new Promise(resolve => {
|
|
259
|
+
chunkBatch.push({
|
|
260
|
+
senderID: clientID,
|
|
261
|
+
recipientId,
|
|
262
|
+
fileName,
|
|
263
|
+
fileChunk: chunkData,
|
|
264
|
+
completedChunks,
|
|
265
|
+
totalChunks,
|
|
266
|
+
chunkIndex,
|
|
267
|
+
chunkSize,
|
|
268
|
+
filePath: destination,
|
|
269
|
+
fileSize
|
|
270
|
+
});
|
|
271
|
+
if (chunkBatch.length >= batchSize) {
|
|
272
|
+
const now = Date.now();
|
|
273
|
+
const rtt = now - lastSendTime;
|
|
274
|
+
lastSendTime = now;
|
|
275
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
276
|
+
chunkBatch
|
|
277
|
+
});
|
|
278
|
+
chunkBatch.length = 0;
|
|
279
|
+
if (rtt >= 200 && batchSize < maxBatchSize) {
|
|
280
|
+
batchSize = Math.min(batchSize + 50, maxBatchSize);
|
|
281
|
+
} else if (rtt < 200 && batchSize > minBatchSize) {
|
|
282
|
+
batchSize = Math.max(batchSize - 50, minBatchSize);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
resolve();
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
onComplete: transferId => {
|
|
289
|
+
return new Promise(resolve => {
|
|
290
|
+
if (chunkBatch.length > 0) {
|
|
291
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
292
|
+
chunkBatch
|
|
293
|
+
});
|
|
294
|
+
chunkBatch.length = 0;
|
|
295
|
+
}
|
|
296
|
+
this.clientTide.emitEvent(clientID, "transfer-complete", {
|
|
297
|
+
senderID: clientID,
|
|
298
|
+
recipientId,
|
|
299
|
+
fileName,
|
|
300
|
+
filePath: destination
|
|
301
|
+
});
|
|
302
|
+
resolve();
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
onTiding: () => {
|
|
306
|
+
this.clientTide.emitEvent(clientID, "client-tiding", {
|
|
307
|
+
senderID: clientID,
|
|
308
|
+
message: "Transfer ongoing..."
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}, this.clientTide);
|
|
312
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Large file ~ ${fileName} transfer complete!`, significantMessageColors);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Error transferring large file: ${error.message}`, errorMessageColors);
|
|
315
|
+
} finally {
|
|
316
|
+
await fileHandle.close();
|
|
317
|
+
}
|
|
203
318
|
}
|
|
204
319
|
async sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize) {
|
|
205
320
|
if (!file) {
|
|
@@ -215,29 +330,22 @@ class FileMessagerClient {
|
|
|
215
330
|
if (!transferAllowed) {
|
|
216
331
|
return;
|
|
217
332
|
}
|
|
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
333
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
222
334
|
fileName,
|
|
223
335
|
senderID: clientID,
|
|
224
336
|
recipientID: recipientId,
|
|
225
|
-
path: filePath
|
|
337
|
+
path: filePath,
|
|
338
|
+
fileSize
|
|
226
339
|
});
|
|
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
|
-
}
|
|
340
|
+
await this.transporter.sendFile(file, {
|
|
341
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
235
342
|
return new Promise((resolve, reject) => {
|
|
236
343
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
237
344
|
senderID: clientID,
|
|
238
345
|
recipientId,
|
|
239
346
|
fileName,
|
|
240
347
|
fileChunk: chunkData,
|
|
348
|
+
completedChunks,
|
|
241
349
|
totalChunks,
|
|
242
350
|
chunkIndex,
|
|
243
351
|
chunkSize,
|
|
@@ -258,19 +366,17 @@ class FileMessagerClient {
|
|
|
258
366
|
resolve();
|
|
259
367
|
});
|
|
260
368
|
},
|
|
261
|
-
onProgress: (progress, chunkSize) => {
|
|
262
|
-
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
263
|
-
},
|
|
264
369
|
originDetails: {
|
|
265
370
|
recipientID: recipientId,
|
|
266
371
|
senderID: clientID
|
|
267
372
|
},
|
|
268
373
|
fileDetails: {
|
|
374
|
+
destinationPath,
|
|
269
375
|
name: fileName,
|
|
270
376
|
path: filePath,
|
|
271
377
|
size: fileSize
|
|
272
378
|
}
|
|
273
|
-
}).then(() => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`, significantMessageColors)).catch(error => FileNetUtilityManager.outputGradient(`[FileTide ~ File Messager] ~ Refused file transfer
|
|
379
|
+
}, 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
380
|
}
|
|
275
381
|
}
|
|
276
382
|
;
|
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,20 +77,27 @@ 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
|
+
const enterRoom = 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);
|
|
88
97
|
FileTide.outputGradient(`[FileTide] ~ Messager launched successfully for client ~ ${userID}!`, significantMessageColors);
|
|
89
98
|
_assertClassBrand(_FileTide_brand, this, _setupFileEventListeners).call(this, userID, newClient, onTransferProgress, onIncomingTransfer, onIncomingFile, onTransferBarrier, options);
|
|
90
99
|
if (onLaunch) {
|
|
91
|
-
onLaunch(newClient);
|
|
100
|
+
onLaunch(newClient, enterRoom);
|
|
92
101
|
}
|
|
93
102
|
return;
|
|
94
103
|
}
|
|
@@ -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);
|
|
@@ -215,6 +235,10 @@ class FileTide {
|
|
|
215
235
|
stopMessager(userID) {
|
|
216
236
|
if (this.clients.has(userID)) {
|
|
217
237
|
FileTide.outputGradient(`Stopping messager for user ${userID}...`, significantMessageColors);
|
|
238
|
+
const connectionOrigin = this.clients.get(userID);
|
|
239
|
+
if (connectionOrigin) {
|
|
240
|
+
connectionOrigin.clientTide.closeSocket(userID);
|
|
241
|
+
}
|
|
218
242
|
this.clients.delete(userID);
|
|
219
243
|
FileTide.outputGradient(`Stopped messager for user ${userID}.`, significantMessageColors);
|
|
220
244
|
return;
|
|
@@ -241,7 +265,9 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
241
265
|
onTransferRequested,
|
|
242
266
|
onTransferStatus,
|
|
243
267
|
onListFiles,
|
|
244
|
-
onCurrentOnlineClients
|
|
268
|
+
onCurrentOnlineClients,
|
|
269
|
+
onClientTiding,
|
|
270
|
+
onCurrentClientIDAlreadyOnline
|
|
245
271
|
} = options;
|
|
246
272
|
const cliTable = new ConsoleTable({
|
|
247
273
|
padding: 2,
|
|
@@ -287,6 +313,11 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
287
313
|
onCurrentOnlineClients(currentClients, true);
|
|
288
314
|
}
|
|
289
315
|
});
|
|
316
|
+
client.clientTide.onEvent(userID, "current-client-tiding", data => {
|
|
317
|
+
if (onClientTiding) {
|
|
318
|
+
onClientTiding(data.message, significantMessageColors);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
290
321
|
client.clientTide.onEvent(userID, "current-clients", data => {
|
|
291
322
|
const currentClients = {};
|
|
292
323
|
Object.keys(data).forEach(key => {
|
|
@@ -302,6 +333,33 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
302
333
|
onCurrentOnlineClients(currentClients, false);
|
|
303
334
|
}
|
|
304
335
|
});
|
|
336
|
+
client.clientTide.onEvent(userID, "current-client-id-already-online", clientID => {
|
|
337
|
+
if (userID === clientID) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
_FileTide.outputGradient(`[FileTide ~ FileNet] ~ Client ~ ${userID} already online.`, significantMessageColors);
|
|
341
|
+
if (onCurrentClientIDAlreadyOnline) {
|
|
342
|
+
onCurrentClientIDAlreadyOnline(clientID);
|
|
343
|
+
}
|
|
344
|
+
return;
|
|
345
|
+
});
|
|
346
|
+
client.clientTide.onEvent(userID, "save-current-transfer-states", async data => {
|
|
347
|
+
this.saveTransferStates();
|
|
348
|
+
return;
|
|
349
|
+
});
|
|
350
|
+
client.clientTide.onEvent(userID, "current-transfer-state", async data => {
|
|
351
|
+
const {
|
|
352
|
+
senderID,
|
|
353
|
+
filePath
|
|
354
|
+
} = data;
|
|
355
|
+
const currentTransferState = FileTransferRecoveryManager.getTransferState(userID, senderID, filePath);
|
|
356
|
+
client.clientTide.emitEvent(userID, "send-current-transfer-state", {
|
|
357
|
+
recipientID: userID,
|
|
358
|
+
senderID,
|
|
359
|
+
transferState: currentTransferState
|
|
360
|
+
});
|
|
361
|
+
return;
|
|
362
|
+
});
|
|
305
363
|
client.clientTide.onEvent(userID, "queue-incoming-transfer", async data => {
|
|
306
364
|
if (this.transferBarrier && onIncomingTransfer) {
|
|
307
365
|
onIncomingTransfer(data, status => {
|
|
@@ -320,6 +378,16 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
320
378
|
return;
|
|
321
379
|
});
|
|
322
380
|
client.clientTide.onEvent(userID, "incoming-transfer", async data => {
|
|
381
|
+
const {
|
|
382
|
+
currentSender
|
|
383
|
+
} = data;
|
|
384
|
+
if (currentSender && currentSender === userID) {
|
|
385
|
+
_FileTide.outputGradient(`[${userID}] Transfer successfully sent to ${data.recipientID}`, significantMessageColors);
|
|
386
|
+
this.progressBarManager.completionMessage = `Successfully sent to ${data.recipientID}!`;
|
|
387
|
+
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
388
|
+
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
323
391
|
_FileTide.outputGradient(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`, significantMessageColors);
|
|
324
392
|
if (onTransferStart) {
|
|
325
393
|
onTransferStart(data);
|
|
@@ -371,11 +439,29 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
371
439
|
}
|
|
372
440
|
await fileTransferReceiver.handleTransferProgress(data);
|
|
373
441
|
this.progressBarManager.updateTaskProgress(data.fileName, data.chunkSize || 512 * 1024);
|
|
442
|
+
const currentTransferState = FileTransferRecoveryManager.getTransferState(userID, data.senderName, data.path) || {
|
|
443
|
+
transferredSize: 0
|
|
444
|
+
};
|
|
445
|
+
currentTransferState.transferredSize += data.chunkSize || 512 * 1024;
|
|
446
|
+
FileTransferRecoveryManager.saveTransferState(userID, data.senderName, data.path, data.chunkIndex, currentTransferState.transferredSize);
|
|
374
447
|
if (onTransferProgress) {
|
|
375
448
|
onTransferProgress(data);
|
|
376
449
|
}
|
|
377
450
|
});
|
|
378
451
|
client.clientTide.onEvent(userID, "transfer-status", data => {
|
|
452
|
+
const {
|
|
453
|
+
chunkIndex,
|
|
454
|
+
chunkSize,
|
|
455
|
+
fileName,
|
|
456
|
+
fileSize
|
|
457
|
+
} = data;
|
|
458
|
+
if (chunkIndex === 0) {
|
|
459
|
+
this.progressBarManager.addTask({
|
|
460
|
+
name: fileName,
|
|
461
|
+
size: fileSize
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
this.progressBarManager.updateTaskProgress(fileName, chunkSize);
|
|
379
465
|
if (onTransferStatus) {
|
|
380
466
|
onTransferStatus(data);
|
|
381
467
|
}
|
|
@@ -389,11 +475,12 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
389
475
|
if (!transferState) {
|
|
390
476
|
return;
|
|
391
477
|
}
|
|
392
|
-
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success) => {
|
|
478
|
+
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success, error) => {
|
|
393
479
|
if (success) {
|
|
480
|
+
FileTransferRecoveryManager.clearTransferState(userID, data.senderID, data.filePath);
|
|
394
481
|
_FileTide.outputGradient(`[${userID}] File saved at : ${savePath}\n`, significantMessageColors);
|
|
395
482
|
} else if (!success) {
|
|
396
|
-
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n`, errorMessageColors);
|
|
483
|
+
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n\t${error}\n`, errorMessageColors);
|
|
397
484
|
}
|
|
398
485
|
if (onTransferComplete) {
|
|
399
486
|
onTransferComplete(data, fileTransferReceiver.activeTransfers, success);
|
|
@@ -416,17 +503,29 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
416
503
|
return;
|
|
417
504
|
});
|
|
418
505
|
client.clientTide.onEvent(userID, "list-files", async data => {
|
|
419
|
-
_FileTide.outputGradient(`[${userID}] Sending file list
|
|
506
|
+
_FileTide.outputGradient(`[${userID}] Sending file list to ${data.senderID}...!`, significantMessageColors);
|
|
420
507
|
const currentClientShorePolicies = this.getShorePolicies(userID);
|
|
421
|
-
const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
508
|
+
const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1, (totalItems, directoryContents) => {
|
|
509
|
+
const capacitor = new ChunkCapacitor(directoryContents, 100);
|
|
510
|
+
const contents = capacitor.getAllChunks();
|
|
511
|
+
for (let files of contents) {
|
|
512
|
+
client.clientTide.emitEvent(userID, "send-file-list-to-client", {
|
|
513
|
+
senderID: data.recipientID,
|
|
514
|
+
recipientID: data.senderID,
|
|
515
|
+
totalItems: files.length,
|
|
516
|
+
listedFiles: files
|
|
517
|
+
});
|
|
518
|
+
}
|
|
426
519
|
});
|
|
520
|
+
setTimeout(() => {
|
|
521
|
+
_FileTide.outputGradient(`[${userID}] Sent file list to ${data.senderID}!`, significantMessageColors);
|
|
522
|
+
}, 1000);
|
|
523
|
+
});
|
|
524
|
+
client.clientTide.onEvent(userID, "error", async error => {
|
|
525
|
+
_FileTide.outputGradient(`[${userID} | FileTide Error] ${error}`, errorMessageColors);
|
|
427
526
|
});
|
|
428
527
|
client.clientTide.onEvent(userID, "client-file-list", async data => {
|
|
429
|
-
_FileTide.outputGradient(`[${userID}]
|
|
528
|
+
_FileTide.outputGradient(`[${userID}] Received ${data.totalItems} directory contents from ${data.senderID}'s file list!`, significantMessageColors);
|
|
430
529
|
if (onListFiles) {
|
|
431
530
|
onListFiles(data);
|
|
432
531
|
}
|
|
@@ -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;
|