From 85b225e101590d5cd0961adc9da4f571e3145a01 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Tue, 8 Feb 2022 13:20:35 +0100 Subject: [PATCH] - Improve command code structure --- HyperbolicDownloader/Program.cs | 3 +- .../UserInterface/Commands/ClientCommands.cs | 21 + .../Commands/DownloadCommands.cs | 237 ++++++++ .../UserInterface/Commands/FileCommands.cs | 187 +++++++ .../UserInterface/Commands/HostCommands.cs | 102 ++++ .../UserInterface/InputHandler.cs | 512 +----------------- 6 files changed, 570 insertions(+), 492 deletions(-) create mode 100644 HyperbolicDownloader/UserInterface/Commands/ClientCommands.cs create mode 100644 HyperbolicDownloader/UserInterface/Commands/DownloadCommands.cs create mode 100644 HyperbolicDownloader/UserInterface/Commands/FileCommands.cs create mode 100644 HyperbolicDownloader/UserInterface/Commands/HostCommands.cs diff --git a/HyperbolicDownloader/Program.cs b/HyperbolicDownloader/Program.cs index c791976..81ca2b1 100644 --- a/HyperbolicDownloader/Program.cs +++ b/HyperbolicDownloader/Program.cs @@ -55,7 +55,8 @@ internal static class Program if (args.Length > 0 && File.Exists(args[0])) { - inputHandler.GetFileFrom(args[0]); + UserInterface.Commands.DownloadCommands downloadCommands = new UserInterface.Commands.DownloadCommands(hostsManager, filesManager); + downloadCommands.GetFileFrom(args[0]); Console.WriteLine("Do you want to continue using this instance? [y/N]"); if (char.ToLower(Console.ReadKey().KeyChar) != 'y') { diff --git a/HyperbolicDownloader/UserInterface/Commands/ClientCommands.cs b/HyperbolicDownloader/UserInterface/Commands/ClientCommands.cs new file mode 100644 index 0000000..35b659b --- /dev/null +++ b/HyperbolicDownloader/UserInterface/Commands/ClientCommands.cs @@ -0,0 +1,21 @@ +using HyperbolicDownloader.Networking; + +using Stone_Red_Utilities.ConsoleExtentions; + +namespace HyperbolicDownloader.UserInterface.Commands; + +internal class ClientCommands +{ + public 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); + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/UserInterface/Commands/DownloadCommands.cs b/HyperbolicDownloader/UserInterface/Commands/DownloadCommands.cs new file mode 100644 index 0000000..ca3ee90 --- /dev/null +++ b/HyperbolicDownloader/UserInterface/Commands/DownloadCommands.cs @@ -0,0 +1,237 @@ +using HyperbolicDownloader.FileProcessing; +using HyperbolicDownloader.Networking; + +using Stone_Red_Utilities.ConsoleExtentions; +using Stone_Red_Utilities.StringExtentions; + +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Text.Json; + +namespace HyperbolicDownloader.UserInterface.Commands; + +internal class DownloadCommands +{ + private readonly HostsManager hostsManager; + private readonly FilesManager filesManager; + + public DownloadCommands(HostsManager hostsManager, FilesManager filesManager) + { + this.hostsManager = hostsManager; + this.filesManager = filesManager; + } + + public void GetFileFrom(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + ConsoleExt.WriteLine("Path is empty!", ConsoleColor.Red); + return; + } + + string fullPath = Path.GetFullPath(path); + + if (!File.Exists(fullPath)) + { + ConsoleExt.WriteLine("Invalid file path!", ConsoleColor.Red); + } + + string json = File.ReadAllText(fullPath); + + PublicHyperFileInfo? publicHyperFileInfo = JsonSerializer.Deserialize(json); + if (publicHyperFileInfo == null) + { + ConsoleExt.WriteLine("Parsing file failed!", ConsoleColor.Red); + return; + } + + hostsManager.AddRange(publicHyperFileInfo.Hosts); + GetFile(publicHyperFileInfo.Hash); + } + + public void GetFile(string hash) + { + if (string.IsNullOrEmpty(hash)) + { + ConsoleExt.WriteLine("No hash value specified!", ConsoleColor.Red); + return; + } + + hash = hash.Trim().ToLower(); + + foreach (NetworkSocket host in hostsManager.ToList()) + { + bool validIpAdress = IPAddress.TryParse(host.IPAddress, out IPAddress? ipAddress); + + if (!validIpAdress) + { + hostsManager.Remove(host, true); + continue; + } + + ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow); + + Console.CursorLeft = 0; + + Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", hash); + + _ = sendTask.Wait(1000); + + if (!sendTask.IsCompletedSuccessfully) + { + Console.CursorLeft = 0; + ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); + + hostsManager.Remove(host); + continue; + } + 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..."); + + using TcpClient tcpClient = new TcpClient(); + tcpClient.Connect(ipAddress!, host.Port); + tcpClient.ReceiveBufferSize = 64000; + + NetworkStream nwStream = tcpClient.GetStream(); + byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; + byte[] reciveBuffer = new byte[64000]; + + byte[] bytesToSend = Encoding.ASCII.GetBytes($"Download {hash}"); + nwStream.Write(bytesToSend); + nwStream.ReadTimeout = 30000; + + int bytesRead; + try + { + bytesRead = nwStream.Read(buffer, 0, tcpClient.ReceiveBufferSize); + } + catch (IOException) + { + Console.WriteLine(); + ConsoleExt.WriteLine("Lost connection to other host!", ConsoleColor.Red); + continue; + } + + string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead); + + string[] parts = dataReceived.Split('/'); + + if (parts.Length == 2) //If received data does not contain 2 parts -> error + { + bool validFileSize = int.TryParse(parts[0], out int fileSize); + + if (!validFileSize || fileSize <= 0) + { + ConsoleExt.WriteLine("Invalid file size!", ConsoleColor.Red); + continue; + } + + string fileName = parts[1].ToFileName(); + string directoryPath = Path.Combine(Program.BasePath, "Downloads"); + string filePath = Path.Combine(directoryPath, fileName); + + Console.WriteLine($"File name: {fileName}"); + Console.WriteLine($"Starting download..."); + + int totalBytesRead = 0; + + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + using FileStream? fileStream = new FileStream(filePath, FileMode.Create); + + int bytesInOneSecond = 0; + int unitsPerSecond = 0; + string unit = "Kb"; + + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + while (totalBytesRead < fileSize) + { + try + { + bytesRead = nwStream.Read(reciveBuffer, 0, reciveBuffer.Length); + } + catch (IOException) + { + Console.WriteLine(); + ConsoleExt.WriteLine("Lost connection to other host!", ConsoleColor.Red); + break; + } + + bytesRead = Math.Min(bytesRead, fileSize - totalBytesRead); + + fileStream.Write(reciveBuffer, 0, bytesRead); + totalBytesRead += bytesRead; + + bytesInOneSecond += bytesRead; + + if (stopWatch.ElapsedMilliseconds >= 1000) + { + unitsPerSecond = (unitsPerSecond + bytesInOneSecond) / 2; + if (unitsPerSecond > 125000) + { + unitsPerSecond /= 125000; + unit = "Mb"; + } + else + { + unitsPerSecond /= 125; + unit = "Kb"; + } + bytesInOneSecond = 0; + stopWatch.Restart(); + } + + Console.CursorLeft = 0; + + Console.Out.WriteAsync($"Downloading: {Math.Clamp(Math.Ceiling(100d / fileSize * totalBytesRead), 0, 100)}% {totalBytesRead / 1000}/{fileSize / 1000}KB [{unitsPerSecond}{unit}/s] "); + } + + fileStream.Close(); + + if (totalBytesRead < fileSize) + { + continue; + } + + Console.WriteLine(); + + Console.WriteLine("Validating file..."); + if (FileValidator.ValidateHash(filePath, hash)) + { + _ = filesManager.TryAdd(filePath, out _, out _); + } + else + { + ConsoleExt.WriteLine("Warning: File hash does not match! File might me corrupted or manipulated!", ConsoleColor.DarkYellow); + } + + Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); + ConsoleExt.WriteLine("Done", ConsoleColor.Green); + stopWatch.Stop(); + hostsManager.SaveHosts(); + return; + } + else + { + ConsoleExt.WriteLine(dataReceived, ConsoleColor.Red); + } + } + 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/Commands/FileCommands.cs b/HyperbolicDownloader/UserInterface/Commands/FileCommands.cs new file mode 100644 index 0000000..88f684b --- /dev/null +++ b/HyperbolicDownloader/UserInterface/Commands/FileCommands.cs @@ -0,0 +1,187 @@ +using HyperbolicDownloader.FileProcessing; +using HyperbolicDownloader.Networking; + +using Stone_Red_Utilities.ConsoleExtentions; + +using System.Net; +using System.Text.Json; + +namespace HyperbolicDownloader.UserInterface.Commands; + +internal class FileCommands +{ + private readonly HostsManager hostsManager; + + private readonly FilesManager filesManager; + + public FileCommands(HostsManager hostsManager, FilesManager filesManager) + { + this.hostsManager = hostsManager; + this.filesManager = filesManager; + } + + public void AddFile(string path) + { + if (filesManager.TryAdd(path, out PrivateHyperFileInfo? fileInfo, out string? message)) + { + ConsoleExt.WriteLine($"Added file: {fileInfo!.FilePath}", ConsoleColor.Green); + Console.WriteLine($"Hash: {fileInfo.Hash}"); + } + else + { + ConsoleExt.WriteLine(message, ConsoleColor.Red); + } + } + + public void RemoveFile(string hash) + { + hash = hash.Trim().ToLower(); + + if (filesManager.TryRemove(hash)) + { + ConsoleExt.WriteLine($"Removed file successfully!", ConsoleColor.Green); + } + else + { + ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); + } + } + + public void ListFiles(string _) + { + int index = 0; + List fileInfos = filesManager.ToList(); + + if (fileInfos.Count == 0) + { + ConsoleExt.WriteLine("No tracked files!", ConsoleColor.DarkYellow); + return; + } + + foreach (PrivateHyperFileInfo fileInfo in fileInfos) + { + index++; + Console.WriteLine($"{index}) {fileInfo.FilePath}"); + Console.WriteLine($"Hash: {fileInfo.Hash}"); + Console.WriteLine(); + } + Console.CursorTop--; + } + + public void GenerateFileSingle(string hash) + { + string directoryPath = Path.Combine(Program.BasePath, "GeneratedFiles"); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + hash = hash.Trim().ToLower(); + + if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) + { + ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); + return; + } + + string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); + string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); + + PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); + + NetworkSocket? localHost = Program.GetLocalSocket(); + if (localHost is null) + { + ConsoleExt.WriteLine("Network error!", ConsoleColor.Red); + return; + } + + publicHyperFileInfo.Hosts.Add(localHost); + + JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; + string json = JsonSerializer.Serialize(publicHyperFileInfo, options); + + File.WriteAllText(filePath, json); + + ConsoleExt.WriteLine("Done", ConsoleColor.Green); + Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); + } + + public void GenerateFileFull(string hash) + { + string directoryPath = Path.Combine(Program.BasePath, "GeneratedFiles"); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + hash = hash.Trim().ToLower(); + + if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) + { + ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); + return; + } + + string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); + string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); + + PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); + + NetworkSocket? localHost = Program.GetLocalSocket(); + if (localHost is null) + { + ConsoleExt.WriteLine("Network error!", ConsoleColor.Red); + return; + } + + foreach (NetworkSocket host in hostsManager.ToList()) + { + bool validIpAdress = IPAddress.TryParse(host.IPAddress, out IPAddress? ipAddress); + + if (!validIpAdress) + { + hostsManager.Remove(host, true); + continue; + } + + ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow); + + Console.CursorLeft = 0; + + Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", hash); + + _ = sendTask.Wait(1000); + + if (!sendTask.IsCompletedSuccessfully) + { + Console.CursorLeft = 0; + ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); + + hostsManager.Remove(host); + continue; + } + 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); + publicHyperFileInfo.Hosts.Add(host); + } + + publicHyperFileInfo.Hosts.Add(localHost); + + JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; + string json = JsonSerializer.Serialize(publicHyperFileInfo, options); + + File.WriteAllText(filePath, json); + + ConsoleExt.WriteLine("Done", ConsoleColor.Green); + Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/UserInterface/Commands/HostCommands.cs b/HyperbolicDownloader/UserInterface/Commands/HostCommands.cs new file mode 100644 index 0000000..dd4905f --- /dev/null +++ b/HyperbolicDownloader/UserInterface/Commands/HostCommands.cs @@ -0,0 +1,102 @@ +using HyperbolicDownloader.Networking; + +using Stone_Red_Utilities.ConsoleExtentions; + +using System.Net; +using System.Net.Sockets; + +namespace HyperbolicDownloader.UserInterface.Commands; + +internal class HostCommands +{ + private readonly HostsManager hostsManager; + + public HostCommands(HostsManager hostsManager) + { + this.hostsManager = hostsManager; + } + + public void Discover(string _) + { + Console.WriteLine("Running local discovery routine..."); + BroadcastClient.Send(Program.BroadcastPort, Program.PrivatePort.ToString()); + Thread.Sleep(3000); + } + + public void CheckActiveHosts(string _) + { + int activeHostsCount = hostsManager.CheckHostsActivity(); + if (activeHostsCount == 0) + { + ConsoleExt.WriteLine("No active hosts found!", ConsoleColor.Red); + ConsoleExt.WriteLine("Use 'add host xxx.xxx.xxx.xxx:yyyy' to add a new host.", ConsoleColor.Red); + } + + Console.WriteLine($"{hostsManager.Count} known host(s)."); + Console.WriteLine($"{activeHostsCount} active host(s)."); + } + + public 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--; + } + + public void AddHost(string args) + { + string[] parts = args.Split(":"); + + if (parts.Length != 2) + { + ConsoleExt.WriteLine("Invalid format! Use this format: (xxx.xxx.xxx.xxx:yyyy)", ConsoleColor.Red); + return; + } + + string ipAddressInput = parts[0]; + string portInput = parts[1]; + + _ = int.TryParse(portInput, out int port); + if (port < 1000 || port >= 6000) + { + ConsoleExt.WriteLine("Invalid port number!", ConsoleColor.Red); + } + else if (IPAddress.TryParse(ipAddressInput, out IPAddress? ipAddress)) + { + try + { + Console.WriteLine("Waiting for response..."); + 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) + { + ConsoleExt.WriteLine($"Success! Added {recivedHosts.Count} new host(s).", ConsoleColor.Green); + hostsManager.AddRange(recivedHosts); + } + else + { + ConsoleExt.WriteLine($"Invalid response!", ConsoleColor.Red); + } + } + catch (SocketException ex) + { + ConsoleExt.WriteLine($"Invalid host! Error message: {ex.Message}", ConsoleColor.Red); + } + catch (IOException ex) + { + ConsoleExt.WriteLine($"Invalid host! Error message: {ex.Message}", ConsoleColor.Red); + } + } + else + { + ConsoleExt.WriteLine("Invalid IP address!", ConsoleColor.Red); + } + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/UserInterface/InputHandler.cs b/HyperbolicDownloader/UserInterface/InputHandler.cs index 50a0590..9552656 100644 --- a/HyperbolicDownloader/UserInterface/InputHandler.cs +++ b/HyperbolicDownloader/UserInterface/InputHandler.cs @@ -1,53 +1,49 @@ using Commander_Net; using HyperbolicDownloader.FileProcessing; -using HyperbolicDownloader.Networking; +using HyperbolicDownloader.UserInterface.Commands; using Stone_Red_Utilities.ConsoleExtentions; -using Stone_Red_Utilities.StringExtentions; - -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Text.Json; namespace HyperbolicDownloader.UserInterface; internal class InputHandler { private readonly HostsManager hostsManager; - private readonly FilesManager filesManager; private readonly Commander commander = new Commander(); private bool exit = false; public InputHandler(HostsManager hostsManager, FilesManager filesManager) { + HostCommands hostCommands = new HostCommands(hostsManager); + FileCommands fileCommands = new FileCommands(hostsManager, filesManager); + DownloadCommands downloadCommands = new DownloadCommands(hostsManager, filesManager); + ClientCommands clientCommands = new ClientCommands(); + this.hostsManager = hostsManager; + commander.Register((_) => Console.Clear(), "clear", "cls"); commander.Register(Exit, "exit", "quit"); - commander.Register(ShowInfo, "info", "inf"); - commander.Register(Discover, "discover", "disc"); + commander.Register(clientCommands.ShowInfo, "info", "inf"); + commander.Register(hostCommands.Discover, "discover", "disc"); - Command getCommand = commander.Register(GetFile, "get"); - getCommand.Register(GetFileFrom, "from"); + Command getCommand = commander.Register(downloadCommands.GetFile, "get"); + getCommand.Register(downloadCommands.GetFileFrom, "from"); - Command generateCommad = commander.Register(GenerateFileFull, "generate", "gen"); - generateCommad.Register(GenerateFileSingle, "noscan"); + Command generateCommad = commander.Register(fileCommands.GenerateFileFull, "generate", "gen"); + generateCommad.Register(fileCommands.GenerateFileSingle, "noscan"); - Command addCommand = commander.Register(AddFile, "add"); - addCommand.Register(AddHost, "host"); - addCommand.Register(AddFile, "file"); + Command addCommand = commander.Register(fileCommands.AddFile, "add"); + addCommand.Register(hostCommands.AddHost, "host"); + addCommand.Register(fileCommands.AddFile, "file"); - commander.Register(RemoveFile, "remove", "rm"); + commander.Register(fileCommands.RemoveFile, "remove", "rm"); - Command listCommand = commander.Register(ListFiles, "list", "ls"); - listCommand.Register(ListFiles, "files"); - listCommand.Register(ListHosts, "hosts"); + Command listCommand = commander.Register(fileCommands.ListFiles, "list", "ls"); + listCommand.Register(fileCommands.ListFiles, "files"); + listCommand.Register(hostCommands.ListHosts, "hosts"); - commander.Register(CheckActiveHosts, "status", "check"); - - this.filesManager = filesManager; + commander.Register(hostCommands.CheckActiveHosts, "status", "check"); } public void ReadInput() @@ -68,475 +64,9 @@ internal class InputHandler } } - private void AddHost(string args) - { - string[] parts = args.Split(":"); - - if (parts.Length != 2) - { - ConsoleExt.WriteLine("Invalid format! Use this format: (xxx.xxx.xxx.xxx:yyyy)", ConsoleColor.Red); - return; - } - - string ipAddressInput = parts[0]; - string portInput = parts[1]; - - _ = int.TryParse(portInput, out int port); - if (port < 1000 || port >= 6000) - { - ConsoleExt.WriteLine("Invalid port number!", ConsoleColor.Red); - } - else if (IPAddress.TryParse(ipAddressInput, out IPAddress? ipAddress)) - { - try - { - Console.WriteLine("Waiting for response..."); - 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) - { - ConsoleExt.WriteLine($"Success! Added {recivedHosts.Count} new host(s).", ConsoleColor.Green); - hostsManager.AddRange(recivedHosts); - } - else - { - ConsoleExt.WriteLine($"Invalid response!", ConsoleColor.Red); - } - } - catch (SocketException ex) - { - ConsoleExt.WriteLine($"Invalid host! Error message: {ex.Message}", ConsoleColor.Red); - } - catch (IOException ex) - { - ConsoleExt.WriteLine($"Invalid host! Error message: {ex.Message}", ConsoleColor.Red); - } - } - else - { - ConsoleExt.WriteLine("Invalid IP address!", ConsoleColor.Red); - } - } - - private void AddFile(string path) - { - if (filesManager.TryAdd(path, out PrivateHyperFileInfo? fileInfo, out string? message)) - { - ConsoleExt.WriteLine($"Added file: {fileInfo!.FilePath}", ConsoleColor.Green); - Console.WriteLine($"Hash: {fileInfo.Hash}"); - } - else - { - ConsoleExt.WriteLine(message, ConsoleColor.Red); - } - } - - private void RemoveFile(string hash) - { - hash = hash.Trim().ToLower(); - - if (filesManager.TryRemove(hash)) - { - ConsoleExt.WriteLine($"Removed file successfully!", ConsoleColor.Green); - } - else - { - ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); - } - } - - private void ListFiles(string _) - { - int index = 0; - foreach (PrivateHyperFileInfo fileInfo in filesManager.ToList()) - { - index++; - Console.WriteLine($"{index}) {fileInfo.FilePath}"); - 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 Discover(string _) - { - Console.WriteLine("Running local discovery routine..."); - BroadcastClient.Send(Program.BroadcastPort, Program.PrivatePort.ToString()); - Thread.Sleep(3000); - } - - private void CheckActiveHosts(string _) - { - int activeHostsCount = hostsManager.CheckHostsActivity(); - if (activeHostsCount == 0) - { - ConsoleExt.WriteLine("No active hosts found!", ConsoleColor.Red); - ConsoleExt.WriteLine("Use 'add host xxx.xxx.xxx.xxx:yyyy' to add a new host.", ConsoleColor.Red); - } - - Console.WriteLine($"{hostsManager.Count} known host(s)."); - Console.WriteLine($"{activeHostsCount} active host(s)."); - } - private void Exit(string _) { hostsManager.SaveHosts(); exit = true; } - - private void GenerateFileSingle(string hash) - { - string directoryPath = Path.Combine(Program.BasePath, "GeneratedFiles"); - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - hash = hash.Trim().ToLower(); - - if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) - { - ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); - return; - } - - string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); - string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); - - PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); - - NetworkSocket? localHost = Program.GetLocalSocket(); - if (localHost is null) - { - ConsoleExt.WriteLine("Network error!", ConsoleColor.Red); - return; - } - - publicHyperFileInfo.Hosts.Add(localHost); - - JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; - string json = JsonSerializer.Serialize(publicHyperFileInfo, options); - - File.WriteAllText(filePath, json); - - ConsoleExt.WriteLine("Done", ConsoleColor.Green); - Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); - } - - private void GenerateFileFull(string hash) - { - string directoryPath = Path.Combine(Program.BasePath, "GeneratedFiles"); - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - hash = hash.Trim().ToLower(); - - if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) - { - ConsoleExt.WriteLine("The file is not being tracked!", ConsoleColor.Red); - return; - } - - string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); - string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); - - PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); - - NetworkSocket? localHost = Program.GetLocalSocket(); - if (localHost is null) - { - ConsoleExt.WriteLine("Network error!", ConsoleColor.Red); - return; - } - - foreach (NetworkSocket host in hostsManager.ToList()) - { - bool validIpAdress = IPAddress.TryParse(host.IPAddress, out IPAddress? ipAddress); - - if (!validIpAdress) - { - hostsManager.Remove(host, true); - continue; - } - - ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow); - - Console.CursorLeft = 0; - - Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", hash); - - _ = sendTask.Wait(1000); - - if (!sendTask.IsCompletedSuccessfully) - { - Console.CursorLeft = 0; - ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); - - hostsManager.Remove(host); - continue; - } - 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); - publicHyperFileInfo.Hosts.Add(host); - } - - publicHyperFileInfo.Hosts.Add(localHost); - - JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; - string json = JsonSerializer.Serialize(publicHyperFileInfo, options); - - File.WriteAllText(filePath, json); - - ConsoleExt.WriteLine("Done", ConsoleColor.Green); - Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); - } - - public void GetFileFrom(string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - ConsoleExt.WriteLine("Path is empty!", ConsoleColor.Red); - return; - } - - string fullPath = Path.GetFullPath(path); - - if (!File.Exists(fullPath)) - { - ConsoleExt.WriteLine("Invalid file path!", ConsoleColor.Red); - } - - string json = File.ReadAllText(fullPath); - - PublicHyperFileInfo? publicHyperFileInfo = JsonSerializer.Deserialize(json); - if (publicHyperFileInfo == null) - { - ConsoleExt.WriteLine("Parsing file failed!", ConsoleColor.Red); - return; - } - - hostsManager.AddRange(publicHyperFileInfo.Hosts); - GetFile(publicHyperFileInfo.Hash); - } - - private void GetFile(string hash) - { - if (string.IsNullOrEmpty(hash)) - { - ConsoleExt.WriteLine("No hash value specified!", ConsoleColor.Red); - return; - } - - hash = hash.Trim().ToLower(); - - foreach (NetworkSocket host in hostsManager.ToList()) - { - bool validIpAdress = IPAddress.TryParse(host.IPAddress, out IPAddress? ipAddress); - - if (!validIpAdress) - { - hostsManager.Remove(host, true); - continue; - } - - ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow); - - Console.CursorLeft = 0; - - Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", hash); - - _ = sendTask.Wait(1000); - - if (!sendTask.IsCompletedSuccessfully) - { - Console.CursorLeft = 0; - ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red); - - hostsManager.Remove(host); - continue; - } - 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..."); - - using TcpClient tcpClient = new TcpClient(); - tcpClient.Connect(ipAddress!, host.Port); - tcpClient.ReceiveBufferSize = 64000; - - NetworkStream nwStream = tcpClient.GetStream(); - byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; - byte[] reciveBuffer = new byte[64000]; - - byte[] bytesToSend = Encoding.ASCII.GetBytes($"Download {hash}"); - nwStream.Write(bytesToSend); - nwStream.ReadTimeout = 30000; - - int bytesRead; - try - { - bytesRead = nwStream.Read(buffer, 0, tcpClient.ReceiveBufferSize); - } - catch (IOException) - { - Console.WriteLine(); - ConsoleExt.WriteLine("Lost connection to other host!", ConsoleColor.Red); - continue; - } - - string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead); - - string[] parts = dataReceived.Split('/'); - - if (parts.Length == 2) //If received data does not contain 2 parts -> error - { - bool validFileSize = int.TryParse(parts[0], out int fileSize); - - if (!validFileSize || fileSize <= 0) - { - ConsoleExt.WriteLine("Invalid file size!", ConsoleColor.Red); - continue; - } - - string fileName = parts[1].ToFileName(); - string directoryPath = Path.Combine(Program.BasePath, "Downloads"); - string filePath = Path.Combine(directoryPath, fileName); - - Console.WriteLine($"File name: {fileName}"); - Console.WriteLine($"Starting download..."); - - int totalBytesRead = 0; - - if (!Directory.Exists(directoryPath)) - { - Directory.CreateDirectory(directoryPath); - } - - using FileStream? fileStream = new FileStream(filePath, FileMode.Create); - - int bytesInOneSecond = 0; - int unitsPerSecond = 0; - string unit = "Kb"; - - Stopwatch stopWatch = new Stopwatch(); - stopWatch.Start(); - while (totalBytesRead < fileSize) - { - try - { - bytesRead = nwStream.Read(reciveBuffer, 0, reciveBuffer.Length); - } - catch (IOException) - { - Console.WriteLine(); - ConsoleExt.WriteLine("Lost connection to other host!", ConsoleColor.Red); - break; - } - - bytesRead = Math.Min(bytesRead, fileSize - totalBytesRead); - - fileStream.Write(reciveBuffer, 0, bytesRead); - totalBytesRead += bytesRead; - - bytesInOneSecond += bytesRead; - - if (stopWatch.ElapsedMilliseconds >= 1000) - { - unitsPerSecond = (unitsPerSecond + bytesInOneSecond) / 2; - if (unitsPerSecond > 125000) - { - unitsPerSecond /= 125000; - unit = "Mb"; - } - else - { - unitsPerSecond /= 125; - unit = "Kb"; - } - bytesInOneSecond = 0; - stopWatch.Restart(); - } - - Console.CursorLeft = 0; - - Console.Out.WriteAsync($"Downloading: {Math.Clamp(Math.Ceiling(100d / fileSize * totalBytesRead), 0, 100)}% {totalBytesRead / 1000}/{fileSize / 1000}KB [{unitsPerSecond}{unit}/s] "); - } - - fileStream.Close(); - - if (totalBytesRead < fileSize) - { - continue; - } - - Console.WriteLine(); - - Console.WriteLine("Validating file..."); - if (FileValidator.ValidateHash(filePath, hash)) - { - _ = filesManager.TryAdd(filePath, out _, out _); - } - else - { - ConsoleExt.WriteLine("Warning: File hash does not match! File might me corrupted or manipulated!", ConsoleColor.DarkYellow); - } - - Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); - ConsoleExt.WriteLine("Done", ConsoleColor.Green); - stopWatch.Stop(); - hostsManager.SaveHosts(); - return; - } - else - { - ConsoleExt.WriteLine(dataReceived, ConsoleColor.Red); - } - } - ConsoleExt.WriteLine("None of the available hosts have the requested file!", ConsoleColor.Red); - hostsManager.SaveHosts(); - } } \ No newline at end of file