@trap_stevo/filetide 0.0.84 → 0.0.86

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.
@@ -11,12 +11,14 @@ const chalk = require("chalk");
11
11
  const path = require("path");
12
12
  const fs = require("fs");
13
13
  const os = require("os");
14
- require("./HUDComponents/FileTideCommunicationConfigurations.js");
15
14
  require("./HUDComponents/FileTideEnvironment.js");
15
+ require("./HUDComponents/FileTideCommunicationConfigurations.js");
16
+ require("./HUDComponents/FileTidePathsConfigurations.js");
16
17
  const {
17
18
  FileTideDebugUtilityManager,
18
19
  significantMessageColors,
19
- errorMessageColors
20
+ errorMessageColors,
21
+ debugMessageColors
20
22
  } = require("./HUDManagers/FileTideDebugUtilityManager.js");
21
23
  const {
22
24
  displayFileTideAuthor,
@@ -33,11 +35,13 @@ const TideTokenEnforcer = require("./HUDManagers/TideTokenEnforcementManager.js"
33
35
  const {
34
36
  FileUtilityManager
35
37
  } = require("./HUDManagers/FileUtilityManager.js");
36
- const ConsoleProgressBarManager = require("./HUDComponents/ConsoleProgressBarManager.js");
38
+ const {
39
+ FileTransferStatsManager
40
+ } = require("./HUDManagers/FileTransferStatsManager.js");
37
41
  const ChunkCapacitor = require("./HUDComponents/ChunkCapacitor.js");
38
42
  const ConsoleTable = require("./HUDComponents/ConsoleTable.js");
39
43
  const FileMessagerClient = require("./FileMessagerClient.js");
40
- const FileMessager = require("./FileMessager.js");
44
+ const FileTideAnchor = require("./FileTideAnchor.js");
41
45
  var _FileTide_brand = /*#__PURE__*/new WeakSet();
42
46
  class FileTide {
43
47
  constructor(debugMode = true) {
@@ -47,9 +51,7 @@ class FileTide {
47
51
  * Automatically checks and creates directories as needed.
48
52
  */
49
53
  _classPrivateMethodInitSpec(this, _FileTide_brand);
50
- this.progressBarManager = new ConsoleProgressBarManager([], {
51
- completionMessageColor: chalk.blue.bold
52
- });
54
+ this.transferStatsManager = new FileTransferStatsManager();
53
55
  this.clientShorePolicies = new Map();
54
56
  this.transferBarrier = false;
55
57
  this.clientDetails = new Map();
@@ -80,28 +82,28 @@ class FileTide {
80
82
  return TideTokenEnforcer.getKey(scope);
81
83
  }
82
84
 
83
- // --- FileTide Gateway Management ---
85
+ // --- FileTide Anchor Management ---
84
86
 
85
87
  /**
86
- * Initialize and start the server.
88
+ * Initialize and start the Anchor (coordination server).
87
89
  * @param {Object} serverOptions - Configuration for server (e.g., port, useCors, useHTTPS)
88
90
  * @param {Function} onLaunch - Callback for when a file tide instance launches
89
91
  * @param {...any} tideConfigurations - Additional configuration objects for customizing FileTide behavior
90
92
  */
91
93
  launchFileTide(serverOptions = {}, onLaunch, ...tideConfigurations) {
92
94
  TideTokenEnforcer.protect(() => {
93
- this.fileNet = new FileMessager(serverOptions, ...tideConfigurations);
94
- this.fileNet.start();
95
- FileTide.outputGradient("[FileTide] ~ FileNet launched successfully!", significantMessageColors);
95
+ this.anchor = new FileTideAnchor(serverOptions, ...tideConfigurations);
96
+ this.anchor.start();
97
+ FileTide.outputGradient("[FileTide] ~ Anchor launched successfully!", significantMessageColors);
96
98
  if (onLaunch) {
97
- onLaunch(this.fileNet);
99
+ onLaunch(this.anchor);
98
100
  }
99
101
  }, "default")();
100
102
  return;
101
103
  }
102
104
 
103
105
  /**
104
- * Initialize and start a new client for each user.
106
+ * Initialize and start a new client for each Tider (user).
105
107
  * @param {Object} clientOptions - Configuration for client (e.g., serverUrl)
106
108
  * @param {Object} connectionOptions - Configuration for the client connection
107
109
  * @param {Object} transportOptions - Configuration for the file transporter
@@ -114,7 +116,7 @@ class FileTide {
114
116
  * @param {Function} onTransferBarrier - Callback for when an incoming transfer status updates
115
117
  * @param {Function} onTransferProgress - Callback for when an current transfers progress
116
118
  * @param {Boolean} [enableTransferBarrier=true] - Whether to enable the transfer barrier
117
- * @param {Object} [options = {}] - Additional options
119
+ * @param {Object} [options = {}] - Additional options including transfer lifecycle callbacks such as onTransferStart, onTransferComplete, and onTransferFailure.
118
120
  * @param {Object} [headers = {}] - Additional connection headers
119
121
  * @param {Function} onConnect - Callback for when the client connects to the desired server
120
122
  * @param {Function} onDisconnect - Callback for when the client disconnects from the desired server
@@ -140,7 +142,7 @@ class FileTide {
140
142
  const {
141
143
  onCurrentClientUnauthorized
142
144
  } = options;
143
- FileTide.outputGradient(`[FileTide ~ FileNet] ~ Unauthorized access detected.`, errorMessageColors);
145
+ FileTide.outputGradient(`[FileTide ~ Anchor] ~ Unauthorized access detected.`, errorMessageColors);
144
146
  if (onCurrentClientUnauthorized) {
145
147
  onCurrentClientUnauthorized({
146
148
  ...currentClientDetails,
@@ -194,6 +196,13 @@ class FileTide {
194
196
 
195
197
  // --- FileTide Transfer State Management ---
196
198
 
199
+ getTransferStats(transferID) {
200
+ return this.transferStatsManager.getTransferStats(transferID);
201
+ }
202
+ getTransferStatsOverview() {
203
+ return this.transferStatsManager.getTransfers();
204
+ }
205
+
197
206
  // --- FileTide Remote Files Management ---
198
207
 
199
208
  listFilesFromClient(recipientID, depth = 1) {
@@ -314,7 +323,7 @@ class FileTide {
314
323
  * @returns {Boolean} - True if server running
315
324
  */
316
325
  async fileTideOperational() {
317
- return await TideTokenEnforcer.protect(() => this.fileNet !== null, "default")();
326
+ return await TideTokenEnforcer.protect(() => this.anchor !== null, "default")();
318
327
  }
319
328
 
320
329
  /**
@@ -332,10 +341,10 @@ class FileTide {
332
341
  */
333
342
  stopFileTide() {
334
343
  TideTokenEnforcer.protect(() => {
335
- if (this.fileNet) {
344
+ if (this.anchor) {
336
345
  FileTide.outputGradient("Stopping FileTide...", significantMessageColors);
337
- this.fileNet.close();
338
- this.fileNet = null;
346
+ this.anchor.close();
347
+ this.anchor = null;
339
348
  FileTide.outputGradient("Stopped FileTide.", significantMessageColors);
340
349
  }
341
350
  }, "default")();
@@ -445,6 +454,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
445
454
  const {
446
455
  onTransferStart,
447
456
  onTransferComplete,
457
+ onTransferFailure,
448
458
  onTransferRequested,
449
459
  onTransferStatus,
450
460
  onListFiles,
@@ -517,6 +527,28 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
517
527
  onClientTiding(data.message, significantMessageColors);
518
528
  }
519
529
  });
530
+ client.clientTide.onEvent(userID, "tide-network-sample", data => {
531
+ const throughputBps = Number(data?.throughputBps);
532
+ if (!Number.isFinite(throughputBps) || throughputBps <= 0) {
533
+ return;
534
+ }
535
+ const networkStatus = client.recordNetworkThroughput(throughputBps);
536
+ if (this.inDebugMode) {
537
+ const sampleDetails = JSON.stringify({
538
+ state: networkStatus.state,
539
+ bandwidthBps: networkStatus.bandwidthBps,
540
+ deliveredThroughputBps: networkStatus.deliveredThroughputBps,
541
+ sendRateBps: networkStatus.sendRateBps,
542
+ throughputRatio: networkStatus.throughputRatio,
543
+ latencyMs: networkStatus.latencyMs,
544
+ failureRate: networkStatus.failureRate,
545
+ retryRate: networkStatus.retryRate,
546
+ recommendedChunkSize: networkStatus.recommendedChunkSize,
547
+ sampleCount: networkStatus.sampleCount
548
+ }, null, 5);
549
+ _FileTide.outputGradient(`[FileTide ~ Network Traffic] ${sampleDetails}`, debugMessageColors);
550
+ }
551
+ });
520
552
  client.clientTide.onEvent(userID, "current-clients", data => {
521
553
  const currentClients = {};
522
554
  Object.keys(data).forEach(key => {
@@ -537,7 +569,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
537
569
  if (userID === clientID) {
538
570
  return;
539
571
  }
540
- _FileTide.outputGradient(`[FileTide ~ FileNet] ~ Client ~ ${userID} already online.`, significantMessageColors);
572
+ _FileTide.outputGradient(`[FileTide ~ Anchor] ~ Client ~ ${userID} already online.`, significantMessageColors);
541
573
  if (onCurrentClientIDAlreadyOnline) {
542
574
  onCurrentClientIDAlreadyOnline(clientID);
543
575
  }
@@ -551,7 +583,7 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
551
583
  if (!bannedDetails.banned) {
552
584
  return;
553
585
  }
554
- _FileTide.outputGradient(`[FileTide ~ FileNet] ~ Unauthorized access detected.`, errorMessageColors);
586
+ _FileTide.outputGradient(`[FileTide ~ Anchor] ~ Unauthorized access detected.`, errorMessageColors);
555
587
  await this.stopAllMessagers(onBeforeCurrentClientUnauthorizedDisconnect, onCurrentClientUnauthorizedDisconnect, async () => {
556
588
  if (onCurrentClientUnauthorized) {
557
589
  onCurrentClientUnauthorized(bannedDetails);
@@ -582,18 +614,12 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
582
614
  } = data;
583
615
  if (currentSender && currentSender === userID) {
584
616
  _FileTide.outputGradient(`[${userID}] Transfer successfully sent to ${data.recipientID}`, significantMessageColors);
585
- this.progressBarManager.completionMessage = `Successfully sent to ${data.recipientID}!`;
586
- this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
587
- this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
588
617
  return;
589
618
  }
590
619
  _FileTide.outputGradient(`[${userID}] Preparing to receive transfer : ${FileUtilityManager.getTidePath(data.path)}`, significantMessageColors);
591
620
  if (onTransferStart) {
592
621
  onTransferStart(data);
593
622
  }
594
- this.progressBarManager.completionMessage = `Successfully received transfer from ${data.senderID}!`;
595
- this.progressBarManager.displayPage("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta);
596
- this.progressBarManager.listenForInput("Page Number:", "Press 'n' for next page, 'p' for previous page.", chalk.blue, chalk.magenta, chalk.yellow);
597
623
  });
598
624
  client.clientTide.onEvent(userID, "incoming-file", async data => {
599
625
  try {
@@ -602,16 +628,13 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
602
628
  const saveDir = FileUtilityManager.getTidePath(data.path);
603
629
  const verifiedSender = data.senderID && data.senderID !== userID;
604
630
  if (verifiedSender) {
605
- this.progressBarManager.addTask({
606
- name: data.fileName,
607
- size: data.fileSize
608
- });
631
+ this.transferStatsManager.startTransfer(data, "receiving");
609
632
  }
610
633
  if (onIncomingFile) {
611
- const taskBarStats = this.progressBarManager.getTaskBar(data.fileName);
634
+ const transferStats = this.transferStatsManager.getTransferStats(data.transferId || data.fileName);
612
635
  onIncomingFile(verifiedSender, {
613
636
  ...data,
614
- stats: taskBarStats
637
+ stats: transferStats
615
638
  }, FileTransferTrackingManager.activeTransfers);
616
639
  }
617
640
  if (verifiedSender && !fs.existsSync(saveDir)) {
@@ -637,53 +660,91 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
637
660
  }
638
661
  });
639
662
  client.clientTide.onEvent(userID, "transfer-progress", async data => {
640
- if (!data || data.fileChunk === undefined || data.fileChunk === null) {
641
- FileTideDebugUtilityManager.log("notice", true, `Received invalid data chunk from ~ ${data.senderName} in transfer progress ~ ${data.fileName}`);
663
+ const tide = data?.tide;
664
+ if (!tide || !Array.isArray(tide.chunks) || tide.chunks.length <= 0) {
665
+ FileTideDebugUtilityManager.log("notice", true, `Received invalid Tide from ~ ${tide?.senderID || data?.senderName || "unknown"} in transfer progress ~ ${tide?.fileName || data?.fileName || "unknown"}`);
642
666
  FileTransferTrackingManager.outputCurrentTransfers();
643
667
  return;
644
668
  }
645
- await fileTransferReceiver.handleTransferProgress(data);
646
- this.progressBarManager.updateTaskProgress(data.fileName, data.chunkSize || 512 * 1024);
647
- const taskBarStats = this.progressBarManager.getTaskBar(data.fileName);
648
- client.clientTide.emitEvent(userID, "acknowledge-transfer-tide", {
649
- fileName: data.fileName,
650
- senderName: data.senderName,
651
- recipientName: userID,
652
- transferStateID: `${data.path}-${data.fileName}`,
653
- path: data.path,
654
- transferStats: taskBarStats,
655
- metadata: data.metadata
656
- });
657
- if (onTransferProgress) {
658
- onTransferProgress({
659
- ...data,
660
- stats: taskBarStats,
661
- metadata: data.metadata
669
+ try {
670
+ const tideState = await fileTransferReceiver.handleTransferTide(tide);
671
+ let transferStats = this.transferStatsManager.getTransferStats(tide.transferId || tide.fileName);
672
+ if (!transferStats) {
673
+ this.transferStatsManager.startTransfer({
674
+ transferId: tide.transferId,
675
+ fileName: tide.fileName,
676
+ fileSize: tide.fileSize,
677
+ senderID: tide.senderID,
678
+ recipientId: tide.recipientId
679
+ }, "receiving");
680
+ }
681
+ transferStats = this.transferStatsManager.updateTransfer(tide.transferId || tide.fileName, tideState.tideBytes);
682
+ client.clientTide.emitEvent(userID, "acknowledge-transfer-tide", {
683
+ transferId: tide.transferId,
684
+ fileName: tide.fileName,
685
+ senderName: tide.senderID,
686
+ recipientName: userID,
687
+ transferStateID: `${tide.filePath}-${tide.fileName}`,
688
+ path: tide.filePath,
689
+ fileSize: tide.fileSize,
690
+ chunkSize: tide.chunks[0]?.chunkSize,
691
+ transferStats,
692
+ firstChunkIndex: tideState.firstChunkIndex,
693
+ lastChunkIndex: tideState.lastChunkIndex,
694
+ highestContiguousChunk: tideState.highestContiguousChunk,
695
+ tideChunkCount: tideState.tideChunkCount,
696
+ tideBytes: tideState.tideBytes,
697
+ completedChunks: tideState.completedChunks,
698
+ totalChunks: tideState.totalChunks,
699
+ missingChunks: tideState.missingChunks,
700
+ metadata: tide.metadata
662
701
  });
702
+ if (onTransferProgress) {
703
+ onTransferProgress({
704
+ ...tide,
705
+ ...tideState,
706
+ stats: transferStats,
707
+ metadata: tide.metadata
708
+ });
709
+ }
710
+ } catch (error) {
711
+ client.clientTide.emitEvent(userID, "transfer-failed", {
712
+ transferId: tide.transferId,
713
+ senderID: tide.senderID,
714
+ recipientId: tide.recipientId,
715
+ fileName: tide.fileName,
716
+ filePath: tide.filePath,
717
+ reason: error.message,
718
+ metadata: tide.metadata
719
+ });
720
+ FileTideDebugUtilityManager.log("error", true, `Failed to process Tide ~ ${tide.fileName} | ${error.message}`);
721
+ return;
663
722
  }
664
723
  });
665
724
  client.clientTide.onEvent(userID, "transfer-status", data => {
666
725
  const {
667
- chunkIndex,
668
- chunkSize,
726
+ firstChunkIndex,
727
+ lastChunkIndex,
728
+ tideBytes,
669
729
  fileName,
670
730
  fileSize
671
731
  } = data;
672
- if (chunkIndex === 0) {
732
+ if (firstChunkIndex === 0) {
673
733
  FileTransferTrackingManager.trackTransfer(data);
674
- this.progressBarManager.addTask({
675
- name: fileName,
676
- size: fileSize
677
- });
678
- } else if (chunkIndex > 0) {
679
- FileTransferTrackingManager.updateTransfer(data);
680
- this.progressBarManager.updateTaskProgress(fileName, chunkSize);
734
+ this.transferStatsManager.startTransfer(data, "sending");
681
735
  }
736
+ FileTransferTrackingManager.updateTransferRange(data);
737
+ let transferStats = this.transferStatsManager.getTransferStats(data.transferId || fileName);
738
+ if (!transferStats) {
739
+ this.transferStatsManager.startTransfer(data, "sending");
740
+ }
741
+ transferStats = this.transferStatsManager.updateTransfer(data.transferId || fileName, tideBytes || 0);
682
742
  if (onTransferStatus) {
683
- const taskBarStats = this.progressBarManager.getTaskBar(fileName);
684
743
  onTransferStatus({
685
744
  ...data,
686
- stats: taskBarStats
745
+ firstChunkIndex,
746
+ lastChunkIndex,
747
+ stats: transferStats
687
748
  });
688
749
  }
689
750
  return;
@@ -704,47 +765,68 @@ function _setupFileEventListeners(userID, client, onTransferProgress, onIncoming
704
765
  } else if (!success) {
705
766
  _FileTide.outputGradient(`[${userID}] Did not save file at ~ ${savePath}\n\t${error}\n`, errorMessageColors);
706
767
  }
768
+ const transferStats = success ? this.transferStatsManager.completeTransfer(data.transferId || data.fileName) : this.transferStatsManager.failTransfer(data.transferId || data.fileName);
707
769
  if (onTransferComplete) {
708
- const taskBarStats = this.progressBarManager.getTaskBar(data.fileName);
709
770
  onTransferComplete({
710
771
  ...data,
711
- stats: taskBarStats
772
+ stats: transferStats
712
773
  }, FileTransferTrackingManager.activeTransfers, success);
713
774
  }
714
- setTimeout(() => {
715
- FileTransferTrackingManager.outputCurrentTransfers();
716
- this.progressBarManager.clearTaskBar(data.fileName);
717
- }, this.progressBarManager.completionTimeout);
775
+ FileTransferTrackingManager.outputCurrentTransfers();
776
+ this.transferStatsManager.clearTransfer(data.transferId || data.fileName);
718
777
  });
719
778
  return;
720
779
  }
721
780
  FileTransferTrackingManager.untrackTransfer(data.fileName);
722
781
  _FileTide.outputGradient(`[${userID}] Transfer successfully sent to ~ ${data.recipientId} and saved at ~ ${path.join(data.filePath, data.fileName)}\n`, significantMessageColors);
782
+ const transferStats = this.transferStatsManager.completeTransfer(data.transferId || data.fileName);
723
783
  if (onTransferComplete) {
724
- const taskBarStats = this.progressBarManager.getTaskBar(data.fileName);
725
784
  onTransferComplete({
726
785
  ...data,
727
- stats: taskBarStats
786
+ stats: transferStats
728
787
  }, FileTransferTrackingManager.activeTransfers, true);
729
788
  }
730
- setTimeout(() => {
731
- FileTransferTrackingManager.outputCurrentTransfers();
732
- this.progressBarManager.clearTaskBar(data.fileName);
733
- }, this.progressBarManager.completionTimeout);
789
+ FileTransferTrackingManager.outputCurrentTransfers();
790
+ this.transferStatsManager.clearTransfer(data.transferId || data.fileName);
734
791
  } catch (error) {
735
792
  _FileTide.outputGradient(`[${userID}] Did not save file at ~ ${savePath}\n${error}`, errorMessageColors);
793
+ const transferStats = this.transferStatsManager.failTransfer(data.transferId || data.fileName);
736
794
  if (onTransferComplete) {
737
- const taskBarStats = this.progressBarManager.getTaskBar(data.fileName);
738
795
  onTransferComplete({
739
796
  ...data,
740
- stats: taskBarStats
797
+ stats: transferStats
741
798
  }, FileTransferTrackingManager.activeTransfers, false);
742
799
  }
743
- setTimeout(() => {
744
- FileTransferTrackingManager.outputCurrentTransfers();
745
- this.progressBarManager.clearTaskBar(data.fileName);
746
- }, this.progressBarManager.completionTimeout);
800
+ FileTransferTrackingManager.outputCurrentTransfers();
801
+ this.transferStatsManager.clearTransfer(data.transferId || data.fileName);
802
+ }
803
+ });
804
+ client.clientTide.onEvent(userID, "transfer-failed", async data => {
805
+ const transferState = FileTransferTrackingManager.getTransfer(data.fileName);
806
+ _FileTide.outputGradient(`[${userID}] File transfer failed ~ ${data.fileName}${data.reason ? `\n${data.reason}` : ""}`, errorMessageColors);
807
+ if (transferState?.fileStream) {
808
+ try {
809
+ await new Promise(resolve => {
810
+ transferState.fileStream.end(resolve);
811
+ });
812
+ } catch (error) {
813
+ FileTideDebugUtilityManager.log("notice", true, `Did not close failed transfer stream ~ ${data.fileName} ~ ${error.message}`);
814
+ }
815
+ }
816
+ FileTransferTrackingManager.untrackTransfer(data.fileName);
817
+ const transferStats = this.transferStatsManager.failTransfer(data.transferId || data.fileName);
818
+ const failureData = {
819
+ ...data,
820
+ stats: transferStats
821
+ };
822
+ if (onTransferFailure) {
823
+ onTransferFailure(failureData, FileTransferTrackingManager.activeTransfers);
824
+ }
825
+ if (onTransferComplete) {
826
+ onTransferComplete(failureData, FileTransferTrackingManager.activeTransfers, false);
747
827
  }
828
+ FileTransferTrackingManager.outputCurrentTransfers();
829
+ this.transferStatsManager.clearTransfer(data.transferId || data.fileName);
748
830
  });
749
831
  client.clientTide.onEvent(userID, "transfer-requested", async data => {
750
832
  _FileTide.outputGradient(`[${userID}] Transfer requested from: ${data.requesterID}`, significantMessageColors);