@trap_stevo/filetide 0.0.33 → 0.0.35

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/LICENSE.md ADDED
@@ -0,0 +1,36 @@
1
+ # License Agreement for @trap_stevo/filetide
2
+
3
+ **Effective Date**: September 10, 2024
4
+
5
+ This License Agreement ("Agreement") is entered into by and between **Hassan Steven Compton**, the owner of the package ("Licensor"), and any individual or entity attempting to use the package ("Licensee"). By attempting to install, use, modify, or distribute the package, Licensee agrees to the following terms and conditions:
6
+
7
+ ## 1. **Ownership**
8
+ **Hassan Steven Compton** is the sole owner of all rights, title, and interest in and to @trap_stevo/filetide, including all related intellectual property rights.
9
+
10
+ ## 2. **Grant of License**
11
+ Licensee is **NOT** granted any rights to use, modify, distribute, or create derivative works of @trap_stevo/filetide, either in part or in whole, without prior express written consent from the Licensor. **Any granted license is non-transferable and non-sublicensable without express written consent from the Licensor.**
12
+
13
+ ## 3. **Prohibited Uses**
14
+ Without the express written permission of the Licensor, Licensee shall not:
15
+ - Use the package for any purpose, including but not limited to personal, commercial, or educational purposes.
16
+ - Copy, modify, distribute, or sublicense the package.
17
+ - Reverse-engineer, decompile, or disassemble the package.
18
+ - Create derivative works or adapt the package in any form.
19
+
20
+ ## 4. **Request for Permission**
21
+ Licensee may request permission to use the package by contacting the Licensor at **h.steven.compton13@gmail.com**. All requests must be made in writing, specifying the intended use of the package. Licensor reserves the right to approve, deny, or revoke any permission at its sole discretion. Any granted permission is subject to the Licensor’s terms and may be revoked at any time.
22
+
23
+ ## 5. **Violation of Terms**
24
+ Any unauthorized use of @trap_stevo/filetide will result in immediate termination of any rights granted under this Agreement. The Licensor reserves the right to pursue legal action, including seeking damages and injunctive relief, for any violations of these terms.
25
+
26
+ ## 6. **No Warranty**
27
+ @trap_stevo/filetide is provided "as is," without any warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, or non-infringement. Licensee assumes all risks associated with the use of the package, including but not limited to potential damage to systems or data.
28
+
29
+ ## 7. **Indemnification**
30
+ Licensee agrees to indemnify and hold harmless the Licensor from any and all claims, damages, liabilities, and expenses arising out of Licensee's use of the package in violation of this Agreement.
31
+
32
+ ## 8. **Governing Law and Dispute Resolution**
33
+ This Agreement shall be governed by and construed in accordance with the laws of **the state of Georgia**, without regard to its conflict of law principles. Any disputes arising out of this Agreement shall be resolved through arbitration in **the state of Georgia**.
34
+
35
+ ## 9. **Amendments**
36
+ Licensor reserves the right to modify or update this Agreement at any time. Any changes to the Agreement will be effective **30 days** after being posted to **https://www.npmjs.com/package/@trap_stevo/filetide**. The Licensor will notify Licensees of any material changes by **posting a notice in the package’s release notes on NPM**. Continued use of the package after the notice period constitutes acceptance of the modified terms.
@@ -41,6 +41,8 @@ class FileMessager {
41
41
  start() {
42
42
  this.fileNet.on("get-client-transfer-barrier-response", this.handleClientTransferBarrierResponse.bind(this));
43
43
  this.fileNet.on("notify-transfer-barrier", this.handleNotifyTransferBarrier.bind(this));
44
+ this.fileNet.on("send-file-list-to-client", this.handleSendFileListToClient.bind(this));
45
+ this.fileNet.on("list-client-files", this.handleListClientFiles.bind(this));
44
46
  this.fileNet.on("transfer-start", this.handleFileTransferStart.bind(this));
45
47
  this.fileNet.on("transfer-progress", this.handleFileTransferProgress.bind(this));
46
48
  this.fileNet.on("transfer-complete", this.handleFileTransferComplete.bind(this));
@@ -125,6 +127,41 @@ class FileMessager {
125
127
  } = transferData;
126
128
  this.requestFromClient(requesterID, senderID, filePath, destinationPath);
127
129
  }
130
+ handleSendFileListToClient(listData) {
131
+ const {
132
+ listedFiles,
133
+ recipientID,
134
+ senderID
135
+ } = listData;
136
+ const recipientConnectionID = FileNetClientManager.getOnlineClient(recipientID).id;
137
+ const senderConnectionID = FileNetClientManager.getOnlineClient(senderID).id;
138
+ const senderClient = this.getClientFromID(senderConnectionID);
139
+ const client = this.getClientFromID(recipientConnectionID);
140
+ if (!client || !senderClient) {
141
+ return;
142
+ }
143
+ this.fileNet.emitToTide(client.tideID, "client-file-list", {
144
+ senderID,
145
+ listedFiles
146
+ });
147
+ }
148
+ handleListClientFiles(clientData) {
149
+ const {
150
+ requesterID,
151
+ recipientID
152
+ } = clientData;
153
+ const recipientConnectionID = FileNetClientManager.getOnlineClient(recipientID).id;
154
+ const senderConnectionID = FileNetClientManager.getOnlineClient(requesterID).id;
155
+ const senderClient = this.getClientFromID(senderConnectionID);
156
+ const client = this.getClientFromID(recipientConnectionID);
157
+ if (!client || !senderClient) {
158
+ return;
159
+ }
160
+ this.fileNet.emitToTide(client.tideID, "list-files", {
161
+ senderID: requesterID,
162
+ recipientID
163
+ });
164
+ }
128
165
  handleClientToClientTransfer(transferData) {
129
166
  const {
130
167
  senderID,
@@ -53,7 +53,7 @@ class FileMessagerClient {
53
53
  });
54
54
  });
55
55
  }
56
- async requestTransfer(clientID, senderID, filePath, destinationPath) {
56
+ async requestTransfer(clientID, senderID, filePath, destinationPath, filterContent = []) {
57
57
  const transferAllowed = await this.allowedTransfer(clientID, senderID, destinationPath, "N/A", "requestSend");
58
58
  if (!transferAllowed) {
59
59
  return;
@@ -62,10 +62,19 @@ class FileMessagerClient {
62
62
  requesterID: clientID,
63
63
  senderID,
64
64
  destinationPath,
65
+ filterContent,
65
66
  filePath
66
67
  });
67
68
  return;
68
69
  }
70
+ listFiles(clientID, recipientID, depth = 1) {
71
+ this.clientTide.emitEvent(clientID, "list-client-files", {
72
+ requesterID: clientID,
73
+ recipientID,
74
+ depth
75
+ });
76
+ return;
77
+ }
69
78
  async allowedTransfer(clientID, recipientID, filePath, fileSize, transferType = "send") {
70
79
  try {
71
80
  const currentDate = Date.now();
@@ -66,10 +66,14 @@ class FileTide {
66
66
  * @param {String} roomName - The name of the room to join
67
67
  * @param {String} userID - The ID of the client user
68
68
  * @param {Function} onLaunch - Callback for when a file messager launches
69
+ * @param {Function} onIncomingFile - Callback for incoming files in transit
69
70
  * @param {Function} onIncomingTransfer - Callback for incoming transfers
70
71
  * @param {Function} onTransferBarrier - Callback for when an incoming transfer status updates
72
+ * @param {Function} onTransferProgress - Callback for when an current transfers progress
73
+ * @param {Boolean} [enableTransferBarrier=true] - Whether to enable the transfer barrier
74
+ * @param {Object} [options = {}] - Additional options
71
75
  */
72
- launchMessager(clientOptions = {}, connectionOptions = {}, roomName, userID, onLaunch, onIncomingFile, onIncomingTransfer, onTransferBarrier, enableTransferBarrier = true) {
76
+ launchMessager(clientOptions = {}, connectionOptions = {}, roomName, userID, onLaunch, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, enableTransferBarrier = true, options = {}) {
73
77
  if (this.clients.has(userID)) {
74
78
  this.stopMessager(userID);
75
79
  }
@@ -79,7 +83,7 @@ class FileTide {
79
83
  this.clientShorePolicies.set(userID, [FileUtilityManager.getTidePath(">CurrentUser"), FileUtilityManager.getTidePath(">Downloads"), FileUtilityManager.getTidePath(">Documents")]);
80
84
  this.clients.set(userID, newClient);
81
85
  FileTide.outputGradient(`[FileTide] ~ Messager launched successfully for client ~ ${userID}!`, significantMessageColors);
82
- _assertClassBrand(_FileTide_brand, this, _setupFileEventListeners).call(this, userID, newClient, onIncomingFile, onIncomingTransfer, onTransferBarrier);
86
+ _assertClassBrand(_FileTide_brand, this, _setupFileEventListeners).call(this, userID, newClient, onTransferProgress, onIncomingTransfer, onIncomingFile, onTransferBarrier, options);
83
87
  if (onLaunch) {
84
88
  onLaunch(newClient);
85
89
  }
@@ -104,8 +108,8 @@ class FileTide {
104
108
  }
105
109
  });
106
110
  }
107
- async listFiles(directories) {
108
- return await FileUtilityManager.listFiles(directories);
111
+ async listFiles(directories, depth = 1) {
112
+ return await FileUtilityManager.listFiles(directories, depth);
109
113
  }
110
114
  clearShorePolicies(clientID, shores = []) {
111
115
  let clientShorePolicies = this.clientShorePolicies.get(clientID);
@@ -218,7 +222,14 @@ class FileTide {
218
222
  }
219
223
  }
220
224
  _FileTide = FileTide;
221
- function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTransfer, onTransferBarrier) {
225
+ function _setupFileEventListeners(userID, client, onTransferProgress, onIncomingTransfer, onIncomingFile, onTransferBarrier, options = {}) {
226
+ const {
227
+ onTransferStart,
228
+ onTransferComplete,
229
+ onTransferRequested,
230
+ onListFiles,
231
+ onCurrentOnlineClients
232
+ } = options;
222
233
  const cliTable = new ConsoleTable({
223
234
  padding: 2,
224
235
  headerAlign: "center",
@@ -259,6 +270,9 @@ function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTran
259
270
  cliTable.setTitle(`✨ Online >${Object.keys(currentClients).length}< ✨`, 1);
260
271
  cliTable.setData(currentClients);
261
272
  console.log(`\n[FileTide ~ FileNet]\n\n`, cliTable.render(), "\n");
273
+ if (onCurrentOnlineClients) {
274
+ onCurrentOnlineClients(currentClients);
275
+ }
262
276
  });
263
277
  client.clientTide.onEvent(userID, "queue-incoming-transfer", async data => {
264
278
  if (this.transferBarrier && onIncomingTransfer) {
@@ -279,6 +293,9 @@ function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTran
279
293
  });
280
294
  client.clientTide.onEvent(userID, "incoming-transfer", async data => {
281
295
  _FileTide.outputGradient(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`, significantMessageColors);
296
+ if (onTransferStart) {
297
+ onTransferStart(data);
298
+ }
282
299
  this.progressBarManager.completionMessage = `Successfully received transfer from ${data.senderID}!`;
283
300
  this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
284
301
  this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
@@ -299,6 +316,9 @@ function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTran
299
316
  size: data.fileSize
300
317
  });
301
318
  }
319
+ if (onIncomingFile) {
320
+ onIncomingFile(verifiedSender, data, activeTransfers);
321
+ }
302
322
  if (verifiedSender && !fs.existsSync(saveDir)) {
303
323
  fs.mkdirSync(saveDir, {
304
324
  recursive: true
@@ -332,8 +352,8 @@ function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTran
332
352
  transferState.receivedChunks[data.chunkIndex] = Buffer.from(data.fileChunk);
333
353
  const progress = (data.chunkIndex + 1) / transferState.totalChunks * 100;
334
354
  this.progressBarManager.updateTaskProgress(data.fileName, 512 * 1024);
335
- if (onIncomingFile) {
336
- onIncomingFile(data);
355
+ if (onTransferProgress) {
356
+ onTransferProgress(data);
337
357
  }
338
358
  });
339
359
  client.clientTide.onEvent(userID, "transfer-complete", data => {
@@ -348,17 +368,42 @@ function _setupFileEventListeners(userID, client, onIncomingFile, onIncomingTran
348
368
  fs.writeFileSync(savePath, fullFile);
349
369
  _FileTide.outputGradient(`[${userID}] File saved at : ${savePath}`, significantMessageColors);
350
370
  activeTransfers.delete(data.fileName);
371
+ if (onTransferComplete) {
372
+ onTransferComplete(data, activeTransfers, true);
373
+ }
351
374
  } catch (error) {
352
375
  _FileTide.outputGradient(`[${userID}] Did not save file at : ${savePath}\n${error}`, errorMessageColors);
353
376
  activeTransfers.delete(data.fileName);
377
+ if (onTransferComplete) {
378
+ onTransferComplete(data, activeTransfers, false);
379
+ }
354
380
  }
355
381
  });
356
382
  client.clientTide.onEvent(userID, "transfer-requested", async data => {
357
383
  _FileTide.outputGradient(`[${userID}] Transfer requested from: ${data.requesterID}`, significantMessageColors);
358
384
  this.clients.get(userID).activeTransferTypes.set(data.destinationPath, data.type);
359
- await this.sendToDevice(data.requesterID, data.path, data.destinationPath);
385
+ if (onTransferRequested) {
386
+ onTransferRequested(data);
387
+ }
388
+ await this.sendToDevice(data.requesterID, data.path, data.destinationPath, data.filterContent || []);
360
389
  return;
361
390
  });
391
+ client.clientTide.onEvent(userID, "list-files", async data => {
392
+ _FileTide.outputGradient(`[${userID}] Sending file list!`, significantMessageColors);
393
+ const currentClientShorePolicies = this.getShorePolicies(userID);
394
+ const listedFiles = await this.listFiles(currentClientShorePolicies || [">Downloads"], data.depth || 1);
395
+ client.clientTide.emitEvent(userID, "send-file-list-to-client", {
396
+ senderID: data.recipientID,
397
+ recipientID: data.senderID,
398
+ listedFiles
399
+ });
400
+ });
401
+ client.clientTide.onEvent(userID, "client-file-list", async data => {
402
+ _FileTide.outputGradient(`[${userID}] Listed ${data.senderID}'s files!`, significantMessageColors);
403
+ if (onListFiles) {
404
+ onListFiles(data);
405
+ }
406
+ });
362
407
  this.currentUserID = userID;
363
408
  return;
364
409
  }
@@ -66,14 +66,15 @@ class FileUtilityManager {
66
66
 
67
67
  /**
68
68
  * Function to list all paths across the system using wildcard '*'.
69
+ * @param {number} depth - The maximum depth limit (from the root). Defaults to 1.
69
70
  * @returns {Promise<Array>} - A promise that resolves to an array of file and directory metadata across the system.
70
71
  */
71
- static async listAllPathsInOS() {
72
+ static async listAllPathsInOS(depth = 1) {
72
73
  const rootPaths = ["/", "C:/"];
73
74
  let allResults = [];
74
75
  const rootPromises = rootPaths.map(async rootPath => {
75
76
  if (await this.exists(rootPath)) {
76
- const subResult = await this.listPaths(rootPath);
77
+ const subResult = await this.listPaths(rootPath, depth);
77
78
  allResults.push(...subResult.results);
78
79
  }
79
80
  });
@@ -84,10 +85,19 @@ class FileUtilityManager {
84
85
  /**
85
86
  * Function to list all paths and their metadata recursively.
86
87
  * @param {string} dir - The directory path to scan.
88
+ * @param {number} maxDepth - The maximum depth limit (from the root). Defaults to 1.
89
+ * @param {number} currentDepth - The current depth level. Starts at 0 (for the root).
87
90
  * @returns {Promise<object>} - A promise that resolves to an object containing a list of files/directories with metadata.
88
91
  */
89
- static async listPaths(dir) {
92
+ static async listPaths(dir, maxDepth = 1, currentDepth = 0) {
90
93
  let results = [];
94
+ if (!maxDepth || currentDepth === undefined || currentDepth === null || currentDepth > maxDepth) {
95
+ return {
96
+ totalItems: 0,
97
+ totalSize: 0,
98
+ results
99
+ };
100
+ }
91
101
  const list = await fsAsync.readdir(dir, {
92
102
  withFileTypes: true
93
103
  });
@@ -103,23 +113,27 @@ class FileUtilityManager {
103
113
  results.push(dirMetadata);
104
114
  const promises = list.map(async file => {
105
115
  const filePath = this.getTidePath(path.join(dir, file.name));
106
- if (file.isDirectory()) {
107
- const subDirResult = await this.listPaths(filePath);
108
- dirMetadata.totalItems += subDirResult.totalItems;
109
- dirMetadata.totalSize += subDirResult.totalSize;
110
- results.push(...subDirResult.results);
111
- } else {
112
- const fileStats = await fsAsync.stat(filePath);
113
- const fileMetadata = {
114
- createdTime: fileStats.birthtime,
115
- lastModified: fileStats.mtime,
116
- size: fileStats.size,
117
- path: filePath,
118
- type: "file"
119
- };
120
- dirMetadata.totalSize += fileStats.size;
121
- dirMetadata.totalItems += 1;
122
- results.push(fileMetadata);
116
+ try {
117
+ if (file.isDirectory()) {
118
+ const subDirResult = await this.listPaths(filePath, maxDepth, currentDepth + 1);
119
+ dirMetadata.totalItems += subDirResult.totalItems;
120
+ dirMetadata.totalSize += subDirResult.totalSize;
121
+ results.push(...subDirResult.results);
122
+ } else {
123
+ const fileStats = await fsAsync.stat(filePath);
124
+ const fileMetadata = {
125
+ createdTime: fileStats.birthtime,
126
+ lastModified: fileStats.mtime,
127
+ size: fileStats.size,
128
+ path: filePath,
129
+ type: "file"
130
+ };
131
+ dirMetadata.totalSize += fileStats.size;
132
+ dirMetadata.totalItems += 1;
133
+ results.push(fileMetadata);
134
+ }
135
+ } catch (error) {
136
+ console.log(`[FileTide] Path not found: ${filePath}`);
123
137
  }
124
138
  });
125
139
  await Promise.all(promises);
@@ -133,17 +147,18 @@ class FileUtilityManager {
133
147
  /**
134
148
  * Allows for listing files in a specific directory or all files in the system '*'.
135
149
  * @param {Array} directories - Array of directories to scan or '*' for entire system.
150
+ * @param {number} depth - The maximum depth limit (from the root). Defaults to 1.
136
151
  * @returns {Promise<Array>} - A promise that resolves to an array of file and directory metadata from specified directories or the entire system.
137
152
  */
138
- static async listFiles(directories) {
153
+ static async listFiles(directories, depth = 1) {
139
154
  let fileList = [];
140
155
  if (directories.includes("*")) {
141
- fileList = await this.listAllPathsInOS();
156
+ fileList = await this.listAllPathsInOS(depth);
142
157
  } else {
143
158
  const dirPromises = directories.map(async dir => {
144
159
  const currentDir = this.getTidePath(dir);
145
160
  if (await this.exists(currentDir)) {
146
- const subResult = await this.listPaths(currentDir);
161
+ const subResult = await this.listPaths(currentDir, depth);
147
162
  fileList.push(...subResult.results);
148
163
  } else {
149
164
  console.warn(`Directory does not exist: ${currentDir}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trap_stevo/filetide",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
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": {
@@ -27,7 +27,7 @@
27
27
  "seamless connectivity"
28
28
  ],
29
29
  "author": "Steven Compton",
30
- "license": "ISC",
30
+ "license": "See License in LICENSE.md",
31
31
  "dependencies": {
32
32
  "@trap_stevo/iotide": "^0.0.37",
33
33
  "@trap_stevo/iotide-client": "^0.0.20",