@trap_stevo/filetide 0.0.38 → 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 +241 -76
- package/dist/cjs/FileMessagerClient.js +145 -39
- package/dist/cjs/FileTide.js +120 -40
- package/dist/cjs/HUDComponents/ChunkCapacitor.js +35 -0
- package/dist/cjs/HUDComponents/ConsoleProgressBarManager.js +5 -1
- package/dist/cjs/HUDManagers/FileTransferManager.js +134 -20
- package/dist/cjs/HUDManagers/FileTransferReceiverManager.js +82 -0
- package/dist/cjs/HUDManagers/FileTransferRecoveryManager.js +94 -0
- package/dist/cjs/HUDManagers/FileUtilityManager.js +140 -72
- 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
|
-
onSendChunk: (transferId, chunkIndex, chunkData, totalChunks) => {
|
|
158
|
-
if (chunkIndex === 0) {
|
|
159
|
-
this.progressBarManager.addTask({
|
|
160
|
-
name: fileName,
|
|
161
|
-
size: fileSize
|
|
162
|
-
});
|
|
163
|
-
}
|
|
171
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks) => {
|
|
164
172
|
return new Promise((resolve, reject) => {
|
|
165
173
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
166
174
|
senderID: clientID,
|
|
@@ -169,6 +177,7 @@ class FileMessagerClient {
|
|
|
169
177
|
fileChunk: chunkData,
|
|
170
178
|
totalChunks,
|
|
171
179
|
chunkIndex,
|
|
180
|
+
chunkSize,
|
|
172
181
|
filePath,
|
|
173
182
|
fileSize
|
|
174
183
|
});
|
|
@@ -186,19 +195,124 @@ class FileMessagerClient {
|
|
|
186
195
|
resolve();
|
|
187
196
|
});
|
|
188
197
|
},
|
|
189
|
-
onProgress: progress => {
|
|
190
|
-
this.progressBarManager.updateTaskProgress(fileName, 512 * 1024);
|
|
191
|
-
},
|
|
192
198
|
originDetails: {
|
|
193
199
|
recipientID: recipientId,
|
|
194
200
|
senderID: clientID
|
|
195
201
|
},
|
|
202
|
+
recipientID: recipientId,
|
|
196
203
|
fileDetails: {
|
|
204
|
+
destinationPath: filePath,
|
|
197
205
|
name: fileName,
|
|
198
206
|
path: filePath,
|
|
199
207
|
size: fileSize
|
|
200
208
|
}
|
|
201
|
-
}).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
|
+
}
|
|
202
316
|
}
|
|
203
317
|
async sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize) {
|
|
204
318
|
if (!file) {
|
|
@@ -214,31 +328,25 @@ class FileMessagerClient {
|
|
|
214
328
|
if (!transferAllowed) {
|
|
215
329
|
return;
|
|
216
330
|
}
|
|
217
|
-
this.progressBarManager.completionMessage = `Successfully sent to ${recipientId}!`;
|
|
218
|
-
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
219
|
-
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
220
331
|
this.clientTide.emitEvent(clientID, "transfer-start", {
|
|
221
332
|
fileName,
|
|
222
333
|
senderID: clientID,
|
|
223
334
|
recipientID: recipientId,
|
|
224
|
-
path: filePath
|
|
335
|
+
path: filePath,
|
|
336
|
+
fileSize
|
|
225
337
|
});
|
|
226
|
-
this.transporter.sendFile(file, {
|
|
227
|
-
onSendChunk: (transferId, chunkIndex, chunkData, totalChunks) => {
|
|
228
|
-
if (chunkIndex === 0) {
|
|
229
|
-
this.progressBarManager.addTask({
|
|
230
|
-
name: fileName,
|
|
231
|
-
size: fileSize
|
|
232
|
-
});
|
|
233
|
-
}
|
|
338
|
+
await this.transporter.sendFile(file, {
|
|
339
|
+
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
234
340
|
return new Promise((resolve, reject) => {
|
|
235
341
|
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
236
342
|
senderID: clientID,
|
|
237
343
|
recipientId,
|
|
238
344
|
fileName,
|
|
239
345
|
fileChunk: chunkData,
|
|
346
|
+
completedChunks,
|
|
240
347
|
totalChunks,
|
|
241
348
|
chunkIndex,
|
|
349
|
+
chunkSize,
|
|
242
350
|
filePath,
|
|
243
351
|
fileSize
|
|
244
352
|
});
|
|
@@ -256,19 +364,17 @@ class FileMessagerClient {
|
|
|
256
364
|
resolve();
|
|
257
365
|
});
|
|
258
366
|
},
|
|
259
|
-
onProgress: progress => {
|
|
260
|
-
this.progressBarManager.updateTaskProgress(fileName, 512 * 1024);
|
|
261
|
-
},
|
|
262
367
|
originDetails: {
|
|
263
368
|
recipientID: recipientId,
|
|
264
369
|
senderID: clientID
|
|
265
370
|
},
|
|
266
371
|
fileDetails: {
|
|
372
|
+
destinationPath,
|
|
267
373
|
name: fileName,
|
|
268
374
|
path: filePath,
|
|
269
375
|
size: fileSize
|
|
270
376
|
}
|
|
271
|
-
}).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));
|
|
272
378
|
}
|
|
273
379
|
}
|
|
274
380
|
;
|
package/dist/cjs/FileTide.js
CHANGED
|
@@ -12,6 +12,10 @@ const {
|
|
|
12
12
|
significantMessageColors,
|
|
13
13
|
errorMessageColors
|
|
14
14
|
} = require("./HUDManagers/FileNetUtilityManager.js");
|
|
15
|
+
const {
|
|
16
|
+
FileTransferReceiverManager
|
|
17
|
+
} = require("./HUDManagers/FileTransferReceiverManager.js");
|
|
18
|
+
const FileTransferRecoveryManager = require("./HUDManagers/FileTransferRecoveryManager.js");
|
|
15
19
|
const {
|
|
16
20
|
FileNetConfigManager
|
|
17
21
|
} = require("./HUDManagers/FileNetConfigManager.js");
|
|
@@ -19,6 +23,7 @@ const {
|
|
|
19
23
|
FileUtilityManager
|
|
20
24
|
} = require("./HUDManagers/FileUtilityManager.js");
|
|
21
25
|
const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager");
|
|
26
|
+
const ChunkCapacitor = require("./HUDComponents/ChunkCapacitor.js");
|
|
22
27
|
const ConsoleTable = require("./HUDComponents/ConsoleTable.js");
|
|
23
28
|
const FileMessagerClient = require("./FileMessagerClient");
|
|
24
29
|
const FileMessager = require("./FileMessager");
|
|
@@ -72,13 +77,20 @@ class FileTide {
|
|
|
72
77
|
* @param {Function} onTransferProgress - Callback for when an current transfers progress
|
|
73
78
|
* @param {Boolean} [enableTransferBarrier=true] - Whether to enable the transfer barrier
|
|
74
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
|
|
75
87
|
*/
|
|
76
|
-
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) {
|
|
77
89
|
if (this.clients.has(userID)) {
|
|
78
90
|
this.stopMessager(userID);
|
|
79
91
|
}
|
|
80
92
|
const newClient = new FileMessagerClient(clientOptions);
|
|
81
|
-
newClient.joinRoom(userID, roomName, connectionOptions);
|
|
93
|
+
newClient.joinRoom(userID, roomName, connectionOptions, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
82
94
|
this.transferBarrier = enableTransferBarrier;
|
|
83
95
|
this.clientShorePolicies.set(userID, [FileUtilityManager.getTidePath(">CurrentUser"), FileUtilityManager.getTidePath(">Downloads"), FileUtilityManager.getTidePath(">Documents")]);
|
|
84
96
|
this.clients.set(userID, newClient);
|
|
@@ -101,6 +113,9 @@ class FileTide {
|
|
|
101
113
|
getTidePath(inputPath) {
|
|
102
114
|
return FileUtilityManager.getTidePath(inputPath);
|
|
103
115
|
}
|
|
116
|
+
saveTransferStates() {
|
|
117
|
+
FileTransferRecoveryManager.flushToDisk();
|
|
118
|
+
}
|
|
104
119
|
filterFilesAndDirectories(dirPath, filterContent = [], callback) {
|
|
105
120
|
FileUtilityManager.filterFilesAndDirectories(dirPath, filterContent, (files, error) => {
|
|
106
121
|
if (callback) {
|
|
@@ -117,8 +132,8 @@ class FileTide {
|
|
|
117
132
|
}
|
|
118
133
|
clientMessager.listFiles(clientID, recipientID, depth);
|
|
119
134
|
}
|
|
120
|
-
async listFiles(directories, depth = 1) {
|
|
121
|
-
return await FileUtilityManager.listFiles(directories, depth);
|
|
135
|
+
async listFiles(directories, depth = 1, onDirectory) {
|
|
136
|
+
return await FileUtilityManager.listFiles(directories, depth, onDirectory);
|
|
122
137
|
}
|
|
123
138
|
clearShorePolicies(clientID, shores = []) {
|
|
124
139
|
let clientShorePolicies = this.clientShorePolicies.get(clientID);
|
|
@@ -150,8 +165,11 @@ class FileTide {
|
|
|
150
165
|
* @param {Buffer} fileData - The path of the data to send
|
|
151
166
|
* @param {String} destinationPath - The destination path on the device
|
|
152
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)
|
|
153
171
|
*/
|
|
154
|
-
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = []) {
|
|
172
|
+
async sendToDevice(recipientID, filePath, destinationPath, filterDirectoryContent = [], tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
155
173
|
const clientID = this.currentUserID;
|
|
156
174
|
const clientMessager = this.clients.get(clientID);
|
|
157
175
|
if (!clientMessager) {
|
|
@@ -164,13 +182,18 @@ class FileTide {
|
|
|
164
182
|
return;
|
|
165
183
|
}
|
|
166
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
|
+
}
|
|
167
190
|
FileTide.outputGradient(`[${clientID}] Sending file ~ ${fileDetails.content.fileName} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
168
191
|
clientMessager.sendFile(clientID, recipientID, fileDetails.content.fileName, fileDetails.content.fileData, destinationPath, fileDetails.content.size);
|
|
169
192
|
return;
|
|
170
193
|
}
|
|
171
194
|
if (fileDetails.type === "directory") {
|
|
172
195
|
FileTide.outputGradient(`[${clientID}] Sending ${fileDetails.content.length} files in directory ~ ${path.basename(filePath)} to client ~ ${recipientID}...`, ["#00C897", "#00E0FF"]);
|
|
173
|
-
clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath);
|
|
196
|
+
clientMessager.sendDirectoryFiles(clientID, recipientID, fileDetails.content, this.getTidePath(filePath), destinationPath, tideSize, minTideSize, maxTideSize);
|
|
174
197
|
return;
|
|
175
198
|
}
|
|
176
199
|
FileTide.outputGradient(`[FileTide] ~ No active client ~ ${recipientID} found.`, errorMessageColors);
|
|
@@ -238,7 +261,8 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
238
261
|
onTransferRequested,
|
|
239
262
|
onTransferStatus,
|
|
240
263
|
onListFiles,
|
|
241
|
-
onCurrentOnlineClients
|
|
264
|
+
onCurrentOnlineClients,
|
|
265
|
+
onClientTiding
|
|
242
266
|
} = options;
|
|
243
267
|
const cliTable = new ConsoleTable({
|
|
244
268
|
padding: 2,
|
|
@@ -266,7 +290,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
266
290
|
return content;
|
|
267
291
|
}
|
|
268
292
|
});
|
|
269
|
-
|
|
293
|
+
const fileTransferReceiver = new FileTransferReceiverManager();
|
|
270
294
|
client.clientTide.onEvent(userID, "current-online-clients", data => {
|
|
271
295
|
const currentClients = {};
|
|
272
296
|
Object.keys(data).forEach(key => {
|
|
@@ -284,6 +308,11 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
284
308
|
onCurrentOnlineClients(currentClients, true);
|
|
285
309
|
}
|
|
286
310
|
});
|
|
311
|
+
client.clientTide.onEvent(userID, "current-client-tiding", data => {
|
|
312
|
+
if (onClientTiding) {
|
|
313
|
+
onClientTiding(data.message, significantMessageColors);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
287
316
|
client.clientTide.onEvent(userID, "current-clients", data => {
|
|
288
317
|
const currentClients = {};
|
|
289
318
|
Object.keys(data).forEach(key => {
|
|
@@ -299,6 +328,23 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
299
328
|
onCurrentOnlineClients(currentClients, false);
|
|
300
329
|
}
|
|
301
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
|
+
});
|
|
302
348
|
client.clientTide.onEvent(userID, "queue-incoming-transfer", async data => {
|
|
303
349
|
if (this.transferBarrier && onIncomingTransfer) {
|
|
304
350
|
onIncomingTransfer(data, status => {
|
|
@@ -317,6 +363,16 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
317
363
|
return;
|
|
318
364
|
});
|
|
319
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
|
+
}
|
|
320
376
|
_FileTide.outputGradient(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`, significantMessageColors);
|
|
321
377
|
if (onTransferStart) {
|
|
322
378
|
onTransferStart(data);
|
|
@@ -325,14 +381,10 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
325
381
|
this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
|
|
326
382
|
this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
|
|
327
383
|
});
|
|
328
|
-
client.clientTide.onEvent(userID, "incoming-file", data => {
|
|
384
|
+
client.clientTide.onEvent(userID, "incoming-file", async data => {
|
|
329
385
|
try {
|
|
330
386
|
_FileTide.outputGradient(`[${userID}] Preparing to receive file : ${data.fileName}`, significantMessageColors);
|
|
331
|
-
|
|
332
|
-
receivedChunks: [],
|
|
333
|
-
totalChunks: data.totalChunks,
|
|
334
|
-
fileInfo: data
|
|
335
|
-
});
|
|
387
|
+
await fileTransferReceiver.initializeTransfer(data);
|
|
336
388
|
const saveDir = FileUtilityManager.getTidePath(data.path);
|
|
337
389
|
const verifiedSender = data.senderID && data.senderID !== userID;
|
|
338
390
|
if (verifiedSender) {
|
|
@@ -342,7 +394,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
342
394
|
});
|
|
343
395
|
}
|
|
344
396
|
if (onIncomingFile) {
|
|
345
|
-
onIncomingFile(verifiedSender, data, activeTransfers);
|
|
397
|
+
onIncomingFile(verifiedSender, data, fileTransferReceiver.activeTransfers);
|
|
346
398
|
}
|
|
347
399
|
if (verifiedSender && !fs.existsSync(saveDir)) {
|
|
348
400
|
fs.mkdirSync(saveDir, {
|
|
@@ -366,22 +418,35 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
366
418
|
onTransferBarrier(data);
|
|
367
419
|
}
|
|
368
420
|
});
|
|
369
|
-
client.clientTide.onEvent(userID, "transfer-progress", data => {
|
|
421
|
+
client.clientTide.onEvent(userID, "transfer-progress", async data => {
|
|
370
422
|
if (!data || data.fileChunk === undefined || data.fileChunk === null) {
|
|
371
423
|
return;
|
|
372
424
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
425
|
+
await fileTransferReceiver.handleTransferProgress(data);
|
|
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);
|
|
380
432
|
if (onTransferProgress) {
|
|
381
433
|
onTransferProgress(data);
|
|
382
434
|
}
|
|
383
435
|
});
|
|
384
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);
|
|
385
450
|
if (onTransferStatus) {
|
|
386
451
|
onTransferStatus(data);
|
|
387
452
|
}
|
|
@@ -391,22 +456,25 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
391
456
|
const savePath = FileUtilityManager.getTidePath(path.join(data.filePath, data.fileName));
|
|
392
457
|
try {
|
|
393
458
|
_FileTide.outputGradient(`[${userID}] File transfer complete : ${data.fileName}`, significantMessageColors);
|
|
394
|
-
const transferState = activeTransfers.get(data.fileName);
|
|
459
|
+
const transferState = fileTransferReceiver.activeTransfers.get(data.fileName);
|
|
395
460
|
if (!transferState) {
|
|
396
461
|
return;
|
|
397
462
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
463
|
+
fileTransferReceiver.completeTransfer(data, (transferData, transfers, success, error) => {
|
|
464
|
+
if (success) {
|
|
465
|
+
FileTransferRecoveryManager.clearTransferState(userID, data.senderID, data.filePath);
|
|
466
|
+
_FileTide.outputGradient(`[${userID}] File saved at : ${savePath}\n`, significantMessageColors);
|
|
467
|
+
} else if (!success) {
|
|
468
|
+
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n\t${error}\n`, errorMessageColors);
|
|
469
|
+
}
|
|
470
|
+
if (onTransferComplete) {
|
|
471
|
+
onTransferComplete(data, fileTransferReceiver.activeTransfers, success);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
405
474
|
} catch (error) {
|
|
406
475
|
_FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n${error}`, errorMessageColors);
|
|
407
|
-
activeTransfers.delete(data.fileName);
|
|
408
476
|
if (onTransferComplete) {
|
|
409
|
-
onTransferComplete(data, activeTransfers, false);
|
|
477
|
+
onTransferComplete(data, fileTransferReceiver.activeTransfers, false);
|
|
410
478
|
}
|
|
411
479
|
}
|
|
412
480
|
});
|
|
@@ -420,17 +488,29 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
|
|
|
420
488
|
return;
|
|
421
489
|
});
|
|
422
490
|
client.clientTide.onEvent(userID, "list-files", async data => {
|
|
423
|
-
_FileTide.outputGradient(`[${userID}] Sending file list
|
|
491
|
+
_FileTide.outputGradient(`[${userID}] Sending file list to ${data.senderID}...!`, significantMessageColors);
|
|
424
492
|
const currentClientShorePolicies = this.getShorePolicies(userID);
|
|
425
|
-
const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
+
}
|
|
430
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);
|
|
431
511
|
});
|
|
432
512
|
client.clientTide.onEvent(userID, "client-file-list", async data => {
|
|
433
|
-
_FileTide.outputGradient(`[${userID}]
|
|
513
|
+
_FileTide.outputGradient(`[${userID}] Received ${data.totalItems} directory contents from ${data.senderID}'s file list!`, significantMessageColors);
|
|
434
514
|
if (onListFiles) {
|
|
435
515
|
onListFiles(data);
|
|
436
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;
|