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