From 2df780709fb6f53d84c2b1a9696eb8d69352b01e Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 27 Jan 2022 21:40:29 +0100 Subject: [PATCH] - Optimize downloading process - Add expiration time to inactive hosts --- .../FileProcessing/FilesManager.cs | 7 +++ .../Networking/HostsManager.cs | 18 +++++-- .../Networking/NetworkClient.cs | 4 +- .../Networking/NetworkSocket.cs | 4 +- HyperbolicDownloader/Program.cs | 50 +++++++++++------ .../UserInterface/InputHandler.cs | 54 ++++++++++++++++--- HyperbolicDownloader/UserInterface/Setup.cs | 2 +- 7 files changed, 107 insertions(+), 32 deletions(-) diff --git a/HyperbolicDownloader/FileProcessing/FilesManager.cs b/HyperbolicDownloader/FileProcessing/FilesManager.cs index 5bdc819..ed6630c 100644 --- a/HyperbolicDownloader/FileProcessing/FilesManager.cs +++ b/HyperbolicDownloader/FileProcessing/FilesManager.cs @@ -8,6 +8,13 @@ internal class FilesManager public bool TryAdd(string filePath, out HyperFileInfo? fileInfo, out string? errorMessage) { + if (string.IsNullOrWhiteSpace(filePath)) + { + fileInfo = null; + errorMessage = "Path is empty!"; + return false; + } + string fullPath = Path.GetFullPath(filePath); if (!File.Exists(fullPath)) diff --git a/HyperbolicDownloader/Networking/HostsManager.cs b/HyperbolicDownloader/Networking/HostsManager.cs index 3efb92f..8f39129 100644 --- a/HyperbolicDownloader/Networking/HostsManager.cs +++ b/HyperbolicDownloader/Networking/HostsManager.cs @@ -40,9 +40,10 @@ internal class HostsManager SaveHosts(); } - public void RemoveInactiveHosts() + public int CheckHostsActivity() { List hostsToRemove = new List(); + int activeHostsCount = 0; foreach (NetworkSocket host in hosts) { ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow); @@ -55,16 +56,24 @@ internal class HostsManager if (tcpClient.Connected) { ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Active", ConsoleColor.Green); + host.LastActive = DateTime.Now; + activeHostsCount++; } else { - hostsToRemove.Add(host); + if (DateTime.Now - host.LastActive >= new TimeSpan(24, 0, 0)) + { + hostsToRemove.Add(host); + } ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); } } catch { - hostsToRemove.Add(host); + if (DateTime.Now - host.LastActive >= new TimeSpan(24, 0, 0)) + { + hostsToRemove.Add(host); + } Console.CursorLeft = 0; ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); } @@ -76,6 +85,7 @@ internal class HostsManager } SaveHosts(); + return activeHostsCount; } public List ToList() @@ -83,7 +93,7 @@ internal class HostsManager return hosts.ToList(); } - private void SaveHosts() + public void SaveHosts() { File.WriteAllText(Program.HostsFilePath, JsonSerializer.Serialize(hosts)); } diff --git a/HyperbolicDownloader/Networking/NetworkClient.cs b/HyperbolicDownloader/Networking/NetworkClient.cs index fd11e2b..adc1993 100644 --- a/HyperbolicDownloader/Networking/NetworkClient.cs +++ b/HyperbolicDownloader/Networking/NetworkClient.cs @@ -12,7 +12,7 @@ namespace HyperbolicDownloader.Networking public bool IsListening { get; private set; } = false; private TcpListener? tcpListener; - private FilesManager filesManager; + private readonly FilesManager filesManager; private readonly Dictionary events = new(); public NetworkClient(FilesManager filesManager) @@ -107,7 +107,7 @@ namespace HyperbolicDownloader.Networking NetworkStream nwStream = client.GetStream(); byte[] buffer = new byte[client.ReceiveBufferSize]; - int bytesRead = await nwStream.ReadAsync(buffer, 0, client.ReceiveBufferSize); + int bytesRead = await nwStream.ReadAsync(buffer.AsMemory(0, client.ReceiveBufferSize)); string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead); diff --git a/HyperbolicDownloader/Networking/NetworkSocket.cs b/HyperbolicDownloader/Networking/NetworkSocket.cs index 0d1a396..9886bc4 100644 --- a/HyperbolicDownloader/Networking/NetworkSocket.cs +++ b/HyperbolicDownloader/Networking/NetworkSocket.cs @@ -4,10 +4,12 @@ internal class NetworkSocket { public string IPAddress { get; set; } public int Port { get; set; } + public DateTime LastActive { get; set; } - public NetworkSocket(string ipAddress, int port) + public NetworkSocket(string ipAddress, int port, DateTime lastActive) { IPAddress = ipAddress; Port = port; + LastActive = lastActive; } } \ No newline at end of file diff --git a/HyperbolicDownloader/Program.cs b/HyperbolicDownloader/Program.cs index d41e4dc..77c9573 100644 --- a/HyperbolicDownloader/Program.cs +++ b/HyperbolicDownloader/Program.cs @@ -20,8 +20,21 @@ internal class Program public const string HostsFilePath = "Hosts.json"; public const string FilesInfoPath = "Files.json"; - private static int publicPort; - private static readonly int privatePort = 3055; + public static int PublicPort { get; private set; } + public static int PrivatePort { get; } = 3055; + + public static IPAddress? PublicIpAddress + { + get + { + if (device is not null) + { + return device.GetExternalIPAsync().GetAwaiter().GetResult(); + } + return null; + } + } + private static NatDevice? device; private static Mapping? portMapping; private static readonly HostsManager hostsManager = new(); @@ -50,7 +63,7 @@ internal class Program _ = await OpenPorts(); ConsoleExt.WriteLine($"The private IP Address is: {NetworkUtilities.GetIP4Adress()} ", ConsoleColor.Green); - ConsoleExt.WriteLine($"The private port is: {privatePort}", ConsoleColor.Green); + ConsoleExt.WriteLine($"The private port is: {PrivatePort}", ConsoleColor.Green); Console.WriteLine("Starting TCP listener..."); @@ -60,7 +73,7 @@ internal class Program networkClient.ListenTo>("DiscoverAnswer", DiscoverAnswer); networkClient.ListenTo("Message", ReciveMessage); networkClient.ListenTo("HasFile", HasFile); - networkClient.StartListening(privatePort); + networkClient.StartListening(PrivatePort); } catch (SocketException ex) { @@ -71,23 +84,25 @@ internal class Program BroadcastClient broadcastClient = new BroadcastClient(); Console.WriteLine("Running local discovery routine..."); - BroadcastClient.Send(BroadcastPort, privatePort.ToString()); + BroadcastClient.Send(BroadcastPort, PrivatePort.ToString()); await Task.Delay(5000); + int activeHostsCount = 0; if (hostsManager.Count > 0) { Console.WriteLine("Checking if hosts are active..."); - hostsManager.RemoveInactiveHosts(); + activeHostsCount = hostsManager.CheckHostsActivity(); } - if (hostsManager.Count == 0) + if (activeHostsCount == 0) { hostsManager.AddRange(await Setup.ConfigureHost()); Console.WriteLine("Checking if hosts are active..."); - hostsManager.RemoveInactiveHosts(); + activeHostsCount = hostsManager.CheckHostsActivity(); } - Console.WriteLine($"{hostsManager.Count} active host(s)."); + Console.WriteLine($"{hostsManager.Count} known host(s)."); + Console.WriteLine($"{activeHostsCount} active host(s)."); Console.WriteLine("Starting broadcast listener..."); broadcastClient.StartListening(BroadcastPort); broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived; @@ -116,7 +131,7 @@ internal class Program if (success) { - hostsManager.Add(new NetworkSocket(recivedEventArgs.IPEndPoint.Address.ToString(), remotePort)); + hostsManager.Add(new NetworkSocket(recivedEventArgs.IPEndPoint.Address.ToString(), remotePort, DateTime.Now)); try { await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend); @@ -170,7 +185,7 @@ internal class Program { try { - publicPort = random.Next(1000, 6000); + PublicPort = random.Next(1000, 6000); NatDiscoverer? discoverer = new NatDiscoverer(); device = await discoverer.DiscoverDeviceAsync(); @@ -178,11 +193,11 @@ internal class Program IPAddress? ip = await device.GetExternalIPAsync(); ConsoleExt.WriteLine($"The public IP Address is: {ip} ", ConsoleColor.Green); - portMapping = new Mapping(Protocol.Tcp, privatePort, publicPort, "HyperbolicDowloader"); + portMapping = new Mapping(Protocol.Tcp, PrivatePort, PublicPort, "HyperbolicDowloader"); await device.CreatePortMapAsync(portMapping); - ConsoleExt.WriteLine($"The public port is: {publicPort}", ConsoleColor.Green); + ConsoleExt.WriteLine($"The public port is: {PublicPort}", ConsoleColor.Green); return true; } catch (NatDeviceNotFoundException) @@ -192,7 +207,7 @@ internal class Program } catch (MappingException ex) { - ConsoleExt.WriteLine($"An error occurred while mapping the private port ({privatePort}) to the public port ({publicPort})! Error message: {ex.Message}", ConsoleColor.Red); + ConsoleExt.WriteLine($"An error occurred while mapping the private port ({PrivatePort}) to the public port ({PublicPort})! Error message: {ex.Message}", ConsoleColor.Red); return false; } } @@ -226,11 +241,12 @@ internal class Program private static void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) { ClosePorts(); + hostsManager.SaveHosts(); } public static NetworkSocket? GetLocalSocket() { - int port = publicPort; + int port = PublicPort; string? ipAddress = null; if (device is not null) @@ -241,7 +257,7 @@ internal class Program if (ipAddress is null || ipAddress == "0.0.0.0") { ipAddress = NetworkUtilities.GetIP4Adress()?.ToString(); - port = privatePort; + port = PrivatePort; } if (ipAddress is null) @@ -249,6 +265,6 @@ internal class Program return null; } - return new NetworkSocket(ipAddress, port); + return new NetworkSocket(ipAddress, port, DateTime.Now); } } \ No newline at end of file diff --git a/HyperbolicDownloader/UserInterface/InputHandler.cs b/HyperbolicDownloader/UserInterface/InputHandler.cs index 929a36e..b7b4a8f 100644 --- a/HyperbolicDownloader/UserInterface/InputHandler.cs +++ b/HyperbolicDownloader/UserInterface/InputHandler.cs @@ -23,14 +23,20 @@ internal class InputHandler public InputHandler(HostsManager hostsManager, FilesManager filesManager) { this.hostsManager = hostsManager; - commander.Register((_) => Console.Clear(), "clear"); - commander.Register(Exit, "exit"); + commander.Register((_) => Console.Clear(), "clear", "cls"); + commander.Register(Exit, "exit", "quit"); + commander.Register(ShowInfo, "info", "inf"); commander.Register(GetFile, "get"); + Command addCommand = commander.Register(AddFile, "add"); addCommand.Register(AddHost, "host"); addCommand.Register(AddFile, "file"); - commander.Register(RemoveFile, "remove"); - commander.Register(ListFiles, "list"); + + commander.Register(RemoveFile, "remove", "rm"); + + Command listCommand = commander.Register(ListFiles, "list", "ls"); + listCommand.Register(ListFiles, "files"); + listCommand.Register(ListHosts, "hosts"); this.filesManager = filesManager; } @@ -39,6 +45,7 @@ internal class InputHandler { while (!exit) { + Console.WriteLine(); Console.Write("> "); Console.CursorVisible = true; @@ -75,7 +82,7 @@ internal class InputHandler try { Console.WriteLine("Waiting for response..."); - NetworkSocket? localSocket = Program.GetLocalSocket() ?? new NetworkSocket("0.0.0.0", 0); + NetworkSocket? localSocket = Program.GetLocalSocket() ?? new NetworkSocket("0.0.0.0", 0, DateTime.MinValue); List? recivedHosts = NetworkClient.Send>(ipAddress, port, "GetHostsList", localSocket); if (recivedHosts is not null) @@ -134,10 +141,38 @@ internal class InputHandler Console.WriteLine($"Hash: {fileInfo.Hash}"); Console.WriteLine(); } + Console.CursorTop--; + } + + private void ListHosts(string _) + { + int index = 0; + foreach (NetworkSocket host in hostsManager.ToList()) + { + index++; + Console.WriteLine($"{index}) {host.IPAddress}:{host.Port}"); + Console.WriteLine($"Last active: {host.LastActive}"); + Console.WriteLine(); + } + Console.CursorTop--; + } + + private void ShowInfo(string _) + { + if (Program.PublicIpAddress is not null) + { + ConsoleExt.WriteLine($"The public IP Address is: {Program.PublicIpAddress}", ConsoleColor.Green); + ConsoleExt.WriteLine($"The public port is: {Program.PublicPort}", ConsoleColor.Green); + Console.WriteLine(); + } + + ConsoleExt.WriteLine($"The private IP Address is: {NetworkUtilities.GetIP4Adress()}", ConsoleColor.Green); + ConsoleExt.WriteLine($"The private port is: {Program.PrivatePort}", ConsoleColor.Green); } private void Exit(string _) { + hostsManager.SaveHosts(); exit = true; } @@ -177,10 +212,13 @@ internal class InputHandler } else if (!sendTask.Result) { + host.LastActive = DateTime.Now; ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Does not have the requested file", ConsoleColor.Red); continue; } + host.LastActive = DateTime.Now; + ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Has the requested file", ConsoleColor.Green); Console.WriteLine("Requesting file..."); @@ -256,12 +294,12 @@ internal class InputHandler unitsPerSecond = (unitsPerSecond + bytesInOneSecond) / 2; if (unitsPerSecond > 125000) { - unitsPerSecond = unitsPerSecond / 125000; + unitsPerSecond /= 125000; unit = "Mb"; } else { - unitsPerSecond = unitsPerSecond / 125; + unitsPerSecond /= 125; unit = "Kb"; } bytesInOneSecond = 0; @@ -291,6 +329,7 @@ internal class InputHandler Console.WriteLine($"File saved at: {Path.GetFullPath($"./Downloads/{fileName}")}"); ConsoleExt.WriteLine("Done", ConsoleColor.Green); stopWatch.Stop(); + hostsManager.SaveHosts(); return; } else @@ -299,5 +338,6 @@ internal class InputHandler } } ConsoleExt.WriteLine("None of the available hosts have the requested file!", ConsoleColor.Red); + hostsManager.SaveHosts(); } } \ No newline at end of file diff --git a/HyperbolicDownloader/UserInterface/Setup.cs b/HyperbolicDownloader/UserInterface/Setup.cs index 92bc346..8764d25 100644 --- a/HyperbolicDownloader/UserInterface/Setup.cs +++ b/HyperbolicDownloader/UserInterface/Setup.cs @@ -33,7 +33,7 @@ internal static class Setup try { Console.WriteLine("Waiting for response..."); - NetworkSocket? localSocket = Program.GetLocalSocket() ?? new NetworkSocket("0.0.0.0", 0); + NetworkSocket? localSocket = Program.GetLocalSocket() ?? new NetworkSocket("0.0.0.0", 0, DateTime.MinValue); List? recivedHosts = await NetworkClient.SendAsync>(ipAddress, port, "GetHostsList", localSocket); if (recivedHosts is not null)