@trap_stevo/filetide 0.0.25 → 0.0.26

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.
@@ -35,65 +35,104 @@ class FileMessager {
35
35
  this.fileNet.on("transfer-start", this.handleFileTransferStart.bind(this));
36
36
  this.fileNet.on("transfer-progress", this.handleFileTransferProgress.bind(this));
37
37
  this.fileNet.on("transfer-complete", this.handleFileTransferComplete.bind(this));
38
+ this.fileNet.on("request-transfer-from-client", this.handleRequestTransferFromClient.bind(this));
38
39
  this.fileNet.on("client-to-client-transfer", this.handleClientToClientTransfer.bind(this));
39
40
  this.fileNet.on("client-offline", this.handleClientOffline.bind(this));
40
41
  this.fileNet.on("clients-online", this.handleClientsOnline.bind(this));
41
42
  this.fileNet.on("client-online", this.handleClientOnline.bind(this));
42
43
  return;
43
44
  }
45
+ getClientFromID(clientID) {
46
+ const client = this.onlineClients.get(clientID);
47
+ if (!client) {
48
+ console.log(`Client ~ ${clientID} not found.`);
49
+ return;
50
+ }
51
+ return client;
52
+ }
53
+ requestFromClient(senderID, clientID, filePath = process.cwd(), destinationPath) {
54
+ const client = this.getClientFromID(clientID);
55
+ if (!client) {
56
+ return;
57
+ }
58
+ this.fileNet.emitToTide(client.tideID, "transfer-requested", {
59
+ senderID,
60
+ clientID,
61
+ path: filePath,
62
+ destinationPath
63
+ });
64
+ }
44
65
 
45
66
  /**
46
67
  * Send file chunk to a specific client
47
- * @param {String} senderID - The ID of the sender (tide ID)
48
- * @param {String} clientId - The ID of the client (socket ID)
68
+ * @param {Object} senderData - Holds the ID (tide ID), and client name (userID) of the sender
69
+ * @param {Object} clientData - The ID (socket ID), and client name (userID) of the client
49
70
  * @param {Buffer} fileChunk - The file chunk to send
50
71
  * @param {String} fileName - The name of the file
51
72
  * @param {Number} chunkIndex - The index of the current chunk
52
73
  */
53
- sendFileChunkToClient(senderID, clientId, fileChunk, fileName, chunkIndex, totalChunks, filePath = process.cwd()) {
54
- const client = this.onlineClients.get(clientId);
74
+ sendFileChunkToClient(senderData, clientData, fileChunk, fileName, chunkIndex, totalChunks, filePath = process.cwd(), fileSize = 100) {
75
+ const senderClient = this.getClientFromID(senderData.id);
76
+ const client = this.getClientFromID(clientData.id);
55
77
  if (!client) {
56
- console.log(`Client ~ ${clientId} not found.`);
57
78
  return;
58
79
  }
59
80
  if (chunkIndex === 0) {
60
81
  this.fileNet.emitToTide(client.tideID, "incoming-file", {
61
- senderID,
82
+ senderID: senderData.userID,
83
+ clientID: clientData.userID,
62
84
  fileName,
63
85
  totalChunks,
64
86
  chunkIndex,
65
- path: filePath
87
+ path: filePath,
88
+ fileSize
66
89
  });
67
90
  }
68
91
  this.fileNet.emitToTide(client.tideID, "transfer-progress", {
69
- senderID,
92
+ senderID: senderData.id,
70
93
  fileName,
71
94
  fileChunk,
72
95
  chunkIndex,
73
- path: filePath
96
+ path: filePath,
97
+ fileSize
74
98
  });
75
- console.log(`[FileTide ~ File Messager] ~ Sent chunk ${chunkIndex} of ${fileName} to client ~ ${clientId}!`);
76
- const senderClient = this.onlineClients.get(senderID);
99
+ console.log(`[FileTide ~ File Messager] ~ Sent chunk ${chunkIndex} of ${fileName} to client ~ ${clientData.userID}!`);
77
100
  if (senderClient) {
78
101
  this.fileNet.emitToTide(senderClient.tideID, "transfer-status", {
79
- status: `Chunk ${chunkIndex} of ${fileName} sent to client ${clientId}!`,
80
- recipientID: clientId,
102
+ status: `Chunk ${chunkIndex} of ${fileName} sent to client ${clientData.userID}!`,
103
+ recipientID: clientData.userID,
81
104
  success: true
82
105
  });
83
106
  }
84
107
  }
108
+ handleRequestTransferFromClient(transferData) {
109
+ const {
110
+ senderID,
111
+ recipientId,
112
+ filePath,
113
+ destinationPath
114
+ } = transferData;
115
+ this.requestFromClient(senderID, recipientId, filePath, destinationPath);
116
+ }
85
117
  handleClientToClientTransfer(transferData) {
86
118
  const {
87
119
  senderID,
88
120
  recipientId,
89
121
  fileName,
90
122
  fileChunk,
123
+ fileSize,
91
124
  filePath,
92
125
  chunkIndex,
93
126
  totalChunks
94
127
  } = transferData;
95
128
  console.log(`Transferring file ~ ${fileName} | chunk ${chunkIndex + 1} of ${totalChunks} to client (${recipientId})`);
96
- this.sendFileChunkToClient(FileNetClientManager.getOnlineClient(senderID).id, FileNetClientManager.getOnlineClient(recipientId).id, fileChunk, fileName, chunkIndex, totalChunks, filePath);
129
+ this.sendFileChunkToClient({
130
+ userID: senderID,
131
+ id: FileNetClientManager.getOnlineClient(senderID).id
132
+ }, {
133
+ userID: recipientId,
134
+ id: FileNetClientManager.getOnlineClient(recipientId).id
135
+ }, fileChunk, fileName, chunkIndex, totalChunks, filePath, fileSize);
97
136
  if (chunkIndex + 1 === totalChunks) {
98
137
  this.fileNet.emit("transfer-complete", {
99
138
  senderID,
@@ -104,8 +143,13 @@ class FileMessager {
104
143
  console.log(`[FileTide ~ File Messager] ~ File transfer completed: ${fileName} from ${senderID} to ${recipientId}`);
105
144
  }
106
145
  }
107
- handleFileTransferStart(fileData, emitToChannel) {
108
- console.log(`Starting file transfer: ${fileData.fileName}`);
146
+ handleFileTransferStart(data, emitToChannel) {
147
+ console.log(`Alerting client of incoming transfer from ${data.senderID}...`);
148
+ const client = this.getClientFromID(data.recipientID);
149
+ if (!client) {
150
+ return;
151
+ }
152
+ this.fileNet.emitToTide(client.tideID, "incoming-transfer", data);
109
153
  }
110
154
  handleFileTransferProgress(data, emitToChannel) {
111
155
  console.log(`Progress: ${data.progress}`);
@@ -3,6 +3,8 @@
3
3
  const {
4
4
  HUDIoTide
5
5
  } = require("@trap_stevo/iotide-client");
6
+ const chalk = require("chalk");
7
+ const path = require("path");
6
8
  const {
7
9
  FileMessagerConfigManager
8
10
  } = require("./HUDManagers/FileMessagerConfigManager");
@@ -12,7 +14,7 @@ const {
12
14
  const {
13
15
  FileUtilityManager
14
16
  } = require("./HUDManagers/FileUtilityManager");
15
- const path = require("path");
17
+ const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager");
16
18
  class FileMessagerClient {
17
19
  constructor(options = {}, transportOptions = {
18
20
  parallelChunks: 3,
@@ -20,6 +22,9 @@ class FileMessagerClient {
20
22
  }) {
21
23
  this.clientOptions = FileMessagerConfigManager.getClientOptions(options);
22
24
  this.transporter = new FileTransferManager(transportOptions);
25
+ this.progressBarManager = new ConsoleProgressBarManager([], {
26
+ completionMessageColor: chalk.blue.bold
27
+ });
23
28
  this.clientTide = new HUDIoTide();
24
29
  this.clients = new Map();
25
30
  }
@@ -54,19 +59,36 @@ class FileMessagerClient {
54
59
  sendDirectoryFiles(clientID, recipientId, filesData, baseDirectory, destinationPath) {
55
60
  const baseDirectoryName = path.basename(baseDirectory);
56
61
  const adjustedDestinationPath = FileUtilityManager.normalizePath(path.join(destinationPath, baseDirectoryName));
57
- const sendFilePromises = filesData.map(fileInfo => {
62
+ const sendFilePromises = filesData.map((fileInfo, index) => {
58
63
  const relativeFilePath = path.dirname(path.relative(baseDirectory, fileInfo.filePath));
59
64
  const fileDestinationPath = FileUtilityManager.normalizePath(path.join(adjustedDestinationPath, relativeFilePath));
60
- return this.sendFile(clientID, recipientId, fileInfo.fileName, fileInfo.fileData, fileDestinationPath);
65
+ return this.sendFile(clientID, recipientId, fileInfo.fileName, fileInfo.fileData, fileDestinationPath, fileInfo.size, adjustedDestinationPath, index);
61
66
  });
62
67
  Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer files: ", error));
63
68
  }
64
- sendFile(clientID, recipientId, fileName, file, filePath = process.cwd()) {
69
+ sendFile(clientID, recipientId, fileName, file, filePath = process.cwd(), fileSize, directoryPath = null, index = 0) {
65
70
  if (!file) {
66
71
  return;
67
72
  }
73
+ if (index === 0) {
74
+ this.progressBarManager.completionMessage = `Successfully sent to ${recipientId}!`;
75
+ this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
76
+ this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
77
+ this.clientTide.emitEvent(clientID, "transfer-start", {
78
+ fileName,
79
+ senderID: clientID,
80
+ recipientID: recipientId,
81
+ path: directoryPath || filePath
82
+ });
83
+ }
68
84
  this.transporter.sendFile(file, {
69
85
  onSendChunk: (transferId, chunkIndex, chunkData, totalChunks) => {
86
+ if (chunkIndex === 0) {
87
+ this.progressBarManager.addTask({
88
+ name: fileName,
89
+ size: fileSize
90
+ });
91
+ }
70
92
  return new Promise((resolve, reject) => {
71
93
  this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
72
94
  senderID: clientID,
@@ -75,7 +97,8 @@ class FileMessagerClient {
75
97
  fileChunk: chunkData,
76
98
  totalChunks,
77
99
  chunkIndex,
78
- filePath
100
+ filePath,
101
+ fileSize
79
102
  });
80
103
  resolve();
81
104
  });
@@ -92,13 +115,18 @@ class FileMessagerClient {
92
115
  });
93
116
  },
94
117
  onProgress: progress => {
95
- console.log(`\n[FileTide ~ File Messager] ~ ${progress.toFixed(2)}% |>>| ${fileName}`);
118
+ //console.log(`\n[FileTide ~ File Messager] ~ ${progress.toFixed(2)}% |>>| ${fileName}`);
119
+ this.progressBarManager.updateTaskProgress(fileName, 512 * 1024);
120
+ },
121
+ originDetails: {
122
+ recipientID: recipientId,
123
+ senderID: clientID
96
124
  },
97
125
  fileDetails: {
98
126
  name: fileName,
99
127
  path: filePath
100
128
  }
101
- }).then(() => console.log(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`)).catch(error => console.error('File transfer failed:', error));
129
+ }).then(() => console.log(`[FileTide ~ File Messager] ~ File ~ ${fileName} transfer complete!`)).catch(error => console.error("Refused file transfer: ", error));
102
130
  }
103
131
  onFileChunkReceived(userID) {
104
132
  this.clientTide.onEvent(userID, "transfer-progress", data => {
@@ -12,6 +12,7 @@ const {
12
12
  const {
13
13
  FileUtilityManager
14
14
  } = require("./HUDManagers/FileUtilityManager.js");
15
+ const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager");
15
16
  const ConsoleTable = require("./HUDComponents/ConsoleTable.js");
16
17
  const FileMessagerClient = require("./FileMessagerClient");
17
18
  const FileMessager = require("./FileMessager");
@@ -23,6 +24,9 @@ class FileTide {
23
24
  * Automatically checks and creates directories as needed.
24
25
  */
25
26
  _classPrivateMethodInitSpec(this, _FileTide_brand);
27
+ this.progressBarManager = new ConsoleProgressBarManager([], {
28
+ completionMessageColor: chalk.blue.bold
29
+ });
26
30
  this.clients = new Map();
27
31
  return;
28
32
  }
@@ -74,6 +78,9 @@ class FileTide {
74
78
  getPathData(inputPath) {
75
79
  return FileUtilityManager.getPathData(inputPath);
76
80
  }
81
+ getTidePath(inputPath) {
82
+ return FileUtilityManager.getTidePath(inputPath);
83
+ }
77
84
 
78
85
  /**
79
86
  * Send a file directly to a device without it needing to create a client.
@@ -237,6 +244,12 @@ function _setupFileEventListeners(userID, client, onIncomingFile) {
237
244
  cliTable.setData(currentClients);
238
245
  console.log(`\n[FileTide ~ FileNet]\n\n`, cliTable.render(), "\n");
239
246
  });
247
+ client.clientTide.onEvent(userID, "incoming-transfer", data => {
248
+ console.log(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`);
249
+ this.progressBarManager.completionMessage = `Successfully received transfer from ${recipientId}!`;
250
+ this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
251
+ this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
252
+ });
240
253
  client.clientTide.onEvent(userID, "incoming-file", data => {
241
254
  console.log(`[${userID}] Preparing to receive file : ${data.fileName}`);
242
255
  activeTransfers.set(data.fileName, {
@@ -244,7 +257,11 @@ function _setupFileEventListeners(userID, client, onIncomingFile) {
244
257
  totalChunks: data.totalChunks,
245
258
  fileInfo: data
246
259
  });
247
- const saveDir = FileUtilityManager.osPath(data.path);
260
+ const saveDir = FileUtilityManager.getTidePath(data.path);
261
+ this.progressBarManager.addTask({
262
+ name: data.fileName,
263
+ size: data.fileSize
264
+ });
248
265
  if (data.senderID && data.senderID !== userID && !fs.existsSync(saveDir)) {
249
266
  fs.mkdirSync(saveDir, {
250
267
  recursive: true
@@ -260,10 +277,15 @@ function _setupFileEventListeners(userID, client, onIncomingFile) {
260
277
  if (!transferState) {
261
278
  return;
262
279
  }
263
- console.log(`[${userID}] Receiving chunk ${data.chunkIndex + 1}/${transferState.totalChunks} for file : ${data.fileName}`);
280
+
281
+ //console.log(`[${userID}] Receiving chunk ${data.chunkIndex + 1}/${transferState.totalChunks} for file : ${data.fileName}`);
282
+
264
283
  transferState.receivedChunks[data.chunkIndex] = Buffer.from(data.fileChunk);
265
284
  const progress = (data.chunkIndex + 1) / transferState.totalChunks * 100;
266
- console.log(`[${userID}] Progress : ${progress.toFixed(2)}%`);
285
+
286
+ //console.log(`[${userID}] Progress : ${progress.toFixed(2)}%`);
287
+
288
+ this.progressBarManager.updateTaskProgress(data.fileName, 512 * 1024);
267
289
  if (onIncomingFile) {
268
290
  onIncomingFile(data);
269
291
  }
@@ -274,12 +296,15 @@ function _setupFileEventListeners(userID, client, onIncomingFile) {
274
296
  if (!transferState) {
275
297
  return;
276
298
  }
277
- const savePath = FileUtilityManager.osPath(path.join(data.filePath, data.fileName));
299
+ const savePath = FileUtilityManager.getTidePath(path.join(data.filePath, data.fileName));
278
300
  const fullFile = Buffer.concat(transferState.receivedChunks);
279
301
  fs.writeFileSync(savePath, fullFile);
280
302
  console.log(`[${userID}] File saved at : ${savePath}`);
281
303
  activeTransfers.delete(data.fileName);
282
304
  });
305
+ client.clientTide.onEvent(userID, "transfer-request", data => {
306
+ console.log(`[${userID}] Transfer requested from: ${data.clientID}`);
307
+ });
283
308
  return;
284
309
  }
285
310
  ;
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+
3
+ const readline = require("readline");
4
+ const chalk = require("chalk");
5
+ class ConsoleProgressBarManager {
6
+ constructor(tasks = [], options = {}) {
7
+ this.visibleBars = process.stdout.rows - 3;
8
+ this.currentPage = 0;
9
+ this.barsPerPage = this.visibleBars;
10
+ this.maxCompletionFeedSize = 5;
11
+ this.completionTimeout = 5000;
12
+ this.completionFeed = [];
13
+ this.completedTasksCount = 0;
14
+ this.totalTasks = tasks.length;
15
+ this.taskBars = [];
16
+ this.options = options;
17
+ this.completionMessage = options.completionMessage || "Successfully processed all tasks!";
18
+ this.completionMessageColor = options.completionMessageColor || chalk.green;
19
+ this.allTasksCompleted = false;
20
+ this.taskBars = tasks.map((task, index) => this.createTaskBar(task, index));
21
+ }
22
+ convertSeconds(seconds) {
23
+ if (seconds === 0) return "0 s";
24
+ const units = [{
25
+ name: "y",
26
+ seconds: 60 * 60 * 24 * 365
27
+ }, {
28
+ name: "mo",
29
+ seconds: 60 * 60 * 24 * 30
30
+ }, {
31
+ name: "w",
32
+ seconds: 60 * 60 * 24 * 7
33
+ }, {
34
+ name: "d",
35
+ seconds: 60 * 60 * 24
36
+ }, {
37
+ name: "h",
38
+ seconds: 60 * 60
39
+ }, {
40
+ name: "m",
41
+ seconds: 60
42
+ }, {
43
+ name: "s",
44
+ seconds: 1
45
+ }];
46
+ let remainingSeconds = seconds;
47
+ let result = "";
48
+ for (const unit of units) {
49
+ const count = Math.floor(remainingSeconds / unit.seconds);
50
+ if (count > 0) {
51
+ result += `${count}${unit.name} `;
52
+ remainingSeconds %= unit.seconds;
53
+ }
54
+ }
55
+ return result.trim();
56
+ }
57
+ createTaskBar(task, index) {
58
+ const defaultOptions = {
59
+ barLength: 40,
60
+ filledChar: ">",
61
+ unfilledChar: " ",
62
+ barColor: chalk.hex("#00CED1").bold,
63
+ taskNameColor: chalk.hex("#007B7F").bold,
64
+ taskCompletedColor: chalk.hex("#2ED573").bold,
65
+ sizeTransferredColor: chalk.hex("#5ECAFF"),
66
+ totalSizeColor: chalk.hex("#00FFFF"),
67
+ taskETAColor: chalk.hex("#00BFFF"),
68
+ speedColor: chalk.hex("#90E0EF"),
69
+ percentageColor: chalk.hex("#1A936F").bold,
70
+ dynamicUnits: true
71
+ };
72
+ const settings = {
73
+ ...defaultOptions,
74
+ ...this.options
75
+ };
76
+ const newBar = {
77
+ taskName: task.name,
78
+ totalSize: task.size,
79
+ current: 0,
80
+ startTime: Date.now(),
81
+ taskIndex: index,
82
+ completed: false,
83
+ getFormattedSize: size => {
84
+ if (!settings.dynamicUnits) return `${size.toFixed(1)} B`;
85
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
86
+ let unitIndex = 0;
87
+ while (size >= 1024 && unitIndex < units.length - 1) {
88
+ size /= 1024;
89
+ unitIndex++;
90
+ }
91
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
92
+ },
93
+ getUnitData: size => {
94
+ if (!settings.dynamicUnits) return {
95
+ current: size.toFixed(1),
96
+ unit: "B"
97
+ };
98
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
99
+ let unitIndex = 0;
100
+ while (size >= 1024 && unitIndex < units.length - 1) {
101
+ size /= 1024;
102
+ unitIndex++;
103
+ }
104
+ return {
105
+ current: size.toFixed(2),
106
+ unit: units[unitIndex]
107
+ };
108
+ },
109
+ redraw: () => {
110
+ readline.cursorTo(process.stdout, 0, newBar.taskIndex % this.barsPerPage);
111
+ process.stdout.clearLine();
112
+ if (newBar.completed) {
113
+ process.stdout.write(settings.taskCompletedColor(`${newBar.taskName}: Completed!`));
114
+ return;
115
+ }
116
+ const percentage = newBar.current / newBar.totalSize * 100;
117
+ const elapsedTime = (Date.now() - newBar.startTime) / 1000;
118
+ const speed = newBar.current / elapsedTime;
119
+ const speedData = newBar.getUnitData(speed);
120
+ const timeLeft = (newBar.totalSize - newBar.current) / (speed || 1);
121
+ newBar.progress = percentage;
122
+ newBar.timeLeft = timeLeft;
123
+ newBar.speed = speed;
124
+ const filledLength = Math.round(settings.barLength * (newBar.current / newBar.totalSize));
125
+ const bar = settings.barColor(settings.filledChar.repeat(filledLength)) + settings.unfilledChar.repeat(settings.barLength - filledLength);
126
+ 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) + "%")}`);
127
+ },
128
+ update: amount => {
129
+ newBar.current += amount;
130
+ if (newBar.current > newBar.totalSize) {
131
+ newBar.current = newBar.totalSize;
132
+ }
133
+ const startIndex = this.currentPage * this.barsPerPage;
134
+ const endIndex = startIndex + this.barsPerPage;
135
+ if (newBar.taskIndex >= startIndex && newBar.taskIndex < endIndex) {
136
+ newBar.redraw();
137
+ }
138
+ },
139
+ set: amount => {
140
+ newBar.current = amount;
141
+ if (newBar.current > newBar.totalSize) {
142
+ newBar.current = newBar.totalSize;
143
+ }
144
+ const startIndex = this.currentPage * this.barsPerPage;
145
+ const endIndex = startIndex + this.barsPerPage;
146
+ if (newBar.taskIndex >= startIndex && newBar.taskIndex < endIndex) {
147
+ newBar.redraw();
148
+ }
149
+ },
150
+ complete: () => {
151
+ newBar.completed = true;
152
+ this.completedTasksCount++;
153
+ if (this.completionFeed.length >= this.maxCompletionFeedSize) {
154
+ this.completionFeed.shift();
155
+ }
156
+ this.completionFeed.push(newBar.taskName);
157
+ newBar.redraw();
158
+ setTimeout(() => {
159
+ this.completionFeed = this.completionFeed.filter(task => task !== newBar.taskName);
160
+ }, this.completionTimeout);
161
+ if (this.completedTasksCount === this.totalTasks) {
162
+ this.allTasksCompleted = true;
163
+ this.exitInputListener();
164
+ this.displayPage();
165
+ this.displayCompletionMessage();
166
+ }
167
+ }
168
+ };
169
+ return newBar;
170
+ }
171
+ addTask(task) {
172
+ const index = this.taskBars.length;
173
+ const newTaskBar = this.createTaskBar(task, index);
174
+ this.taskBars.push(newTaskBar);
175
+ this.totalTasks++;
176
+ }
177
+ updateTaskProgress(taskName, amount) {
178
+ const taskBar = this.taskBars.find(bar => bar.taskName === taskName);
179
+ if (taskBar) {
180
+ taskBar.update(amount);
181
+ try {
182
+ if (taskBar.current >= taskBar.totalSize && taskBar.complete) {
183
+ taskBar.complete();
184
+ }
185
+ } catch (error) {}
186
+ } else {
187
+ console.log(chalk.red(`Task ${taskName} not found.`));
188
+ }
189
+ }
190
+ setTaskProgress(taskName, amount) {
191
+ const taskBar = this.taskBars.find(bar => bar.taskName === taskName);
192
+ if (taskBar) {
193
+ taskBar.set(amount);
194
+ if (taskBar.current >= taskBar.totalSize) {
195
+ taskBar.complete();
196
+ }
197
+ } else {
198
+ console.log(chalk.red(`Task ${taskName} not found.`));
199
+ }
200
+ }
201
+ clearPage() {
202
+ for (let i = 0; i < this.barsPerPage + 2; i++) {
203
+ readline.cursorTo(process.stdout, 0, i);
204
+ process.stdout.clearLine();
205
+ }
206
+ }
207
+ displayPage(customPagePrefix = "Page", bottomMessage, bottomMessageColor = chalk.gray) {
208
+ this.clearPage();
209
+ const startIndex = this.currentPage * this.barsPerPage;
210
+ const endIndex = startIndex + this.barsPerPage;
211
+ this.taskBars.slice(startIndex, endIndex).forEach(bar => {
212
+ bar.redraw();
213
+ });
214
+ if (!this.allTasksCompleted) {
215
+ this.redrawCompletionFeed(customPagePrefix, bottomMessage, bottomMessageColor);
216
+ }
217
+ }
218
+ redrawCompletionFeed(customPagePrefix = "Page", bottomMessage, pageFooterMessageColor = chalk.blue, bottomMessageColor = chalk.gray, recentlyCompletedColor = chalk.green) {
219
+ const bottomPosition = this.barsPerPage;
220
+ readline.cursorTo(process.stdout, 0, bottomPosition);
221
+ process.stdout.clearLine();
222
+ process.stdout.write(pageFooterMessageColor(`${customPagePrefix} ${this.currentPage + 1}/${Math.max(1, Math.ceil(this.taskBars.length / this.barsPerPage))} | Completed: ${this.completedTasksCount}/${this.totalTasks}`));
223
+ if (this.completionFeed.length > 0) {
224
+ process.stdout.write(recentlyCompletedColor(` | Recently completed: ${this.completionFeed.join(", ")}`));
225
+ }
226
+ readline.cursorTo(process.stdout, 0, bottomPosition + 1);
227
+ process.stdout.clearLine();
228
+ if (bottomMessage) {
229
+ process.stdout.write(bottomMessageColor(bottomMessage));
230
+ }
231
+ }
232
+ listenForInput(customPagePrefix = "Page", bottomMessage, bottomMessageColor = chalk.gray, recentlyCompletedColor = chalk.green) {
233
+ process.stdin.setRawMode(true);
234
+ process.stdin.resume();
235
+ process.stdin.setEncoding("utf-8");
236
+ this.inputListener = key => {
237
+ if (key === "\u0003") {
238
+ process.exit();
239
+ } else if (this.allTasksCompleted) {
240
+ this.exitInputListener();
241
+ } else if (key === "n" && this.currentPage < Math.ceil(this.taskBars.length / this.barsPerPage) - 1) {
242
+ this.currentPage++;
243
+ this.displayPage(customPagePrefix, bottomMessage, bottomMessageColor, recentlyCompletedColor);
244
+ } else if (key === "p" && this.currentPage > 0) {
245
+ this.currentPage--;
246
+ this.displayPage(customPagePrefix, bottomMessage, bottomMessageColor, recentlyCompletedColor);
247
+ }
248
+ };
249
+ process.stdin.on("data", this.inputListener);
250
+ }
251
+ exitInputListener() {
252
+ process.stdin.removeListener("data", this.inputListener);
253
+ process.stdin.setRawMode(false);
254
+ process.stdin.pause();
255
+ }
256
+ displayCompletionMessage() {
257
+ const lastLine = Math.min(this.taskBars.length, this.barsPerPage);
258
+ readline.cursorTo(process.stdout, 0, lastLine);
259
+ process.stdout.clearLine();
260
+ console.log(this.completionMessageColor(this.completionMessage));
261
+ }
262
+ }
263
+ ;
264
+ module.exports = ConsoleProgressBarManager;
@@ -50,12 +50,6 @@ function _startTransfer(file, transferId, fileDetails, onSendChunk, onComplete,
50
50
  const start = chunkIndex * this.chunkSize;
51
51
  const end = Math.min(start + this.chunkSize, file.length);
52
52
  const chunk = file.slice(start, end);
53
- if (!fs.existsSync(fileDetails.path)) {
54
- fs.mkdirSync(fileDetails.path, {
55
- recursive: true
56
- });
57
- console.log(`[FileTide ~ Transporter] Created directory: ${fileDetails.path}`);
58
- }
59
53
  if (onStart && chunkIndex === 0) {
60
54
  onStart({
61
55
  name: fileDetails.name,
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
 
3
- const path = require('path');
4
- const fs = require('fs');
5
- const filesPath = path.join(__dirname, '../files');
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const filesPath = path.join(__dirname, "../files");
6
7
  class FileUtilityManager {
7
8
  /**
8
9
  * Recursively calculates the total size of files in a directory.
@@ -23,6 +24,45 @@ class FileUtilityManager {
23
24
  });
24
25
  return totalSize;
25
26
  }
27
+ static getTidePath(inputPath) {
28
+ const homeDir = os.homedir();
29
+ const platform = process.platform;
30
+ const folderMappings = {
31
+ ">Downloads": path.join(homeDir, "Downloads"),
32
+ ">Documents": path.join(homeDir, "Documents"),
33
+ ">Desktop": path.join(homeDir, "Desktop"),
34
+ ">AppData": platform === "win32" ? path.join(homeDir, "AppData", "Roaming") : path.join(homeDir, ".config"),
35
+ ">LocalAppData": platform === "win32" ? path.join(homeDir, "AppData", "Local") : "/var/local",
36
+ ">Music": path.join(homeDir, "Music"),
37
+ ">Pictures": path.join(homeDir, "Pictures"),
38
+ ">Videos": path.join(homeDir, "Videos"),
39
+ ">Public": platform === "win32" ? path.join("C:", "Users", "Public") : "/usr/share",
40
+ ">Templates": path.join(homeDir, "Templates"),
41
+ ">Temp": platform === "win32" ? path.join("C:", "Windows", "Temp") : "/tmp",
42
+ ">LogFiles": platform === "win32" ? path.join("C:", "Windows", "Logs") : "/var/log",
43
+ ">SystemRoot": platform === "win32" ? path.join("C:", "Windows") : "/",
44
+ ">Downloads": path.join(homeDir, "Downloads"),
45
+ ">Cache": platform === "win32" ? path.join(homeDir, "AppData", "Local", "Cache") : path.join(homeDir, ".cache"),
46
+ ">Config": platform === "win32" ? path.join(homeDir, "AppData", "Local", "Config") : "/etc",
47
+ ">CurrentDirectory": process.cwd(),
48
+ ">Home": homeDir
49
+ };
50
+ let resolvedPath = inputPath;
51
+ Object.keys(folderMappings).forEach(shortcut => {
52
+ if (resolvedPath.includes(shortcut)) {
53
+ const replacementPath = folderMappings[shortcut];
54
+ if (fs.existsSync(replacementPath)) {
55
+ resolvedPath = resolvedPath.replace(shortcut, replacementPath);
56
+ } else {
57
+ console.log(`The directory for '${shortcut}' does not exist on this system.`);
58
+ resolvedPath = resolvedPath.replace(shortcut, homeDir);
59
+ }
60
+ }
61
+ });
62
+ resolvedPath = this.osPath(resolvedPath);
63
+ resolvedPath = this.normalizePath(resolvedPath);
64
+ return resolvedPath;
65
+ }
26
66
 
27
67
  /**
28
68
  * Normalizes the input path to handle both single and double slashes.
@@ -48,7 +88,7 @@ class FileUtilityManager {
48
88
  * @returns {Array} - An array of objects containing file data, name, and path.
49
89
  */
50
90
  static getDirectoryData(inputDirPath) {
51
- const dirPath = this.normalizePath(inputDirPath);
91
+ const dirPath = this.getTidePath(inputDirPath);
52
92
  if (!fs.existsSync(dirPath)) {
53
93
  console.log(`Directory at path ${dirPath} not found.`);
54
94
  return [];
@@ -76,10 +116,10 @@ class FileUtilityManager {
76
116
  /**
77
117
  * Gets file data from a given file path.
78
118
  * @param {string} inputFilePath - The full path to the file.
79
- * @returns {Object|null} - An object containing file data, name, and path, or null if the file doesn't exist.
119
+ * @returns {Object|null} - An object containing file data, name, path, and size or null if the file doesn't exist.
80
120
  */
81
121
  static getFileData(inputFilePath) {
82
- const filePath = this.normalizePath(inputFilePath);
122
+ const filePath = this.getTidePath(inputFilePath);
83
123
  if (!fs.existsSync(filePath)) {
84
124
  console.log(`File at path ${filePath} not found.`);
85
125
  return null;
@@ -89,6 +129,7 @@ class FileUtilityManager {
89
129
  });
90
130
  const fileName = path.basename(filePath);
91
131
  return {
132
+ size: fileData.length,
92
133
  fileName,
93
134
  fileData,
94
135
  filePath
@@ -101,7 +142,7 @@ class FileUtilityManager {
101
142
  * @returns {Object|Array|null} - File data if it's a file, an array of file data if it's a directory, or null if the path doesn't exist.
102
143
  */
103
144
  static getPathData(inputPath) {
104
- const currentInputPath = this.normalizePath(inputPath);
145
+ const currentInputPath = this.getTidePath(inputPath);
105
146
  if (!fs.existsSync(currentInputPath)) {
106
147
  console.log(`Path at ${currentInputPath} not found.`);
107
148
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trap_stevo/filetide",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities with a tool designed for precision, efficiency, and effortless connectivity.",
5
5
  "main": "dist/cjs/FileTide.js",
6
6
  "scripts": {