From eeb1882685709627e44e9164662167f3a5bf252a Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:15:42 +0100 Subject: [PATCH] - Add ability to generate `.hyper` files - Add ability to open `.hyper` files - Code optimizations --- .../FileProcessing/FileCompressor.cs | 3 +- .../FileProcessing/FilesManager.cs | 14 +- .../FileProcessing/HyperFileInfo.cs | 13 -- .../FileProcessing/PrivateHyperFileInfo.cs | 13 ++ .../FileProcessing/PublicHyperFileInfo.cs | 24 +++ .../Networking/NetworkClient.cs | 23 +-- .../Networking/NetworkUtilities.cs | 9 +- HyperbolicDownloader/Program.cs | 46 +++-- .../UserInterface/InputHandler.cs | 184 ++++++++++++++++-- 9 files changed, 248 insertions(+), 81 deletions(-) delete mode 100644 HyperbolicDownloader/FileProcessing/HyperFileInfo.cs create mode 100644 HyperbolicDownloader/FileProcessing/PrivateHyperFileInfo.cs create mode 100644 HyperbolicDownloader/FileProcessing/PublicHyperFileInfo.cs diff --git a/HyperbolicDownloader/FileProcessing/FileCompressor.cs b/HyperbolicDownloader/FileProcessing/FileCompressor.cs index 487f0e8..2c92498 100644 --- a/HyperbolicDownloader/FileProcessing/FileCompressor.cs +++ b/HyperbolicDownloader/FileProcessing/FileCompressor.cs @@ -23,10 +23,9 @@ internal static class FileCompressor public static IEnumerable ReadChunks(string path, int chunkSize) { byte[] buffer = new byte[chunkSize]; - int bytesRead; using FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); using BufferedStream bs = new BufferedStream(fs); - while ((bytesRead = bs.Read(buffer, 0, chunkSize)) != 0) + while (bs.Read(buffer, 0, chunkSize) != 0) { yield return buffer; } diff --git a/HyperbolicDownloader/FileProcessing/FilesManager.cs b/HyperbolicDownloader/FileProcessing/FilesManager.cs index ed6630c..089de5f 100644 --- a/HyperbolicDownloader/FileProcessing/FilesManager.cs +++ b/HyperbolicDownloader/FileProcessing/FilesManager.cs @@ -4,9 +4,9 @@ namespace HyperbolicDownloader.FileProcessing; internal class FilesManager { - private readonly List files = new List(); + private readonly List files = new List(); - public bool TryAdd(string filePath, out HyperFileInfo? fileInfo, out string? errorMessage) + public bool TryAdd(string filePath, out PrivateHyperFileInfo? fileInfo, out string? errorMessage) { if (string.IsNullOrWhiteSpace(filePath)) { @@ -33,7 +33,7 @@ internal class FilesManager return false; } - fileInfo = new HyperFileInfo(hash, fullPath); + fileInfo = new PrivateHyperFileInfo(hash, fullPath); files.Add(fileInfo); @@ -43,9 +43,9 @@ internal class FilesManager return true; } - public void AddRange(IEnumerable fileInfos) + public void AddRange(IEnumerable fileInfos) { - foreach (HyperFileInfo fileInfo in fileInfos) + foreach (PrivateHyperFileInfo fileInfo in fileInfos) { if (File.Exists(fileInfo.FilePath) && !Contains(fileInfo.Hash)) { @@ -56,7 +56,7 @@ internal class FilesManager SaveFiles(); } - public bool TryGet(string hash, out HyperFileInfo? fileInfo) + public bool TryGet(string hash, out PrivateHyperFileInfo? fileInfo) { if (Contains(hash)) { @@ -84,7 +84,7 @@ internal class FilesManager return files.Any(f => f.Hash == hash); } - public List ToList() + public List ToList() { return files.ToList(); } diff --git a/HyperbolicDownloader/FileProcessing/HyperFileInfo.cs b/HyperbolicDownloader/FileProcessing/HyperFileInfo.cs deleted file mode 100644 index 5896956..0000000 --- a/HyperbolicDownloader/FileProcessing/HyperFileInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace HyperbolicDownloader.FileProcessing; - -internal class HyperFileInfo -{ - public string Hash { get; set; } = string.Empty; - public string FilePath { get; set; } = string.Empty; - - public HyperFileInfo(string hash, string filePath) - { - Hash = hash; - FilePath = filePath; - } -} \ No newline at end of file diff --git a/HyperbolicDownloader/FileProcessing/PrivateHyperFileInfo.cs b/HyperbolicDownloader/FileProcessing/PrivateHyperFileInfo.cs new file mode 100644 index 0000000..b5a7b36 --- /dev/null +++ b/HyperbolicDownloader/FileProcessing/PrivateHyperFileInfo.cs @@ -0,0 +1,13 @@ +namespace HyperbolicDownloader.FileProcessing; + +internal class PrivateHyperFileInfo +{ + public string Hash { get; set; } + public string FilePath { get; set; } + + public PrivateHyperFileInfo(string hash, string filePath) + { + Hash = hash; + FilePath = filePath; + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/FileProcessing/PublicHyperFileInfo.cs b/HyperbolicDownloader/FileProcessing/PublicHyperFileInfo.cs new file mode 100644 index 0000000..a357a69 --- /dev/null +++ b/HyperbolicDownloader/FileProcessing/PublicHyperFileInfo.cs @@ -0,0 +1,24 @@ +using HyperbolicDownloader.Networking; + +namespace HyperbolicDownloader.FileProcessing; + +internal class PublicHyperFileInfo +{ + public string Hash { get; set; } = string.Empty; + public List Hosts { get; } = new(); + + public PublicHyperFileInfo() + { + } + + public PublicHyperFileInfo(string hash) + { + Hash = hash; + } + + public PublicHyperFileInfo(string hash, List hosts) + { + Hash = hash; + Hosts = hosts; + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/Networking/NetworkClient.cs b/HyperbolicDownloader/Networking/NetworkClient.cs index a0309c7..54c7609 100644 --- a/HyperbolicDownloader/Networking/NetworkClient.cs +++ b/HyperbolicDownloader/Networking/NetworkClient.cs @@ -88,7 +88,7 @@ namespace HyperbolicDownloader.Networking public void StartListening(int port) { - if (IsListening == true) + if (IsListening) { throw new InvalidOperationException("Already listening!"); } @@ -146,7 +146,7 @@ namespace HyperbolicDownloader.Networking { if (ex.SocketErrorCode != SocketError.Interrupted) { - throw ex; + throw; } } } @@ -162,22 +162,11 @@ namespace HyperbolicDownloader.Networking hash = hash.Trim(); NetworkStream nwStream = client.GetStream(); client.SendBufferSize = 64000; - if (filesManager.TryGet(hash, out HyperFileInfo? hyperFileInfo) && File.Exists(hyperFileInfo?.FilePath)) + if (filesManager.TryGet(hash, out PrivateHyperFileInfo? hyperFileInfo) && File.Exists(hyperFileInfo?.FilePath)) { - if (hash != await FileValidator.CalculateHashAsync(hyperFileInfo.FilePath)) - { - bytesToSend = Encoding.ASCII.GetBytes("Hash does not match!"); - await nwStream.WriteAsync(bytesToSend); - return; - } + FileInfo fileInfo = new FileInfo(hyperFileInfo.FilePath); - //string compressedFilePath = $"{hash + DateTime.Now.Millisecond}.temp"; - - //FileCompressor.CompressFile(hyperFileInfo.FilePath, compressedFilePath); - - FileInfo compressedFileInfo = new FileInfo(hyperFileInfo.FilePath); - - bytesToSend = Encoding.ASCII.GetBytes($"{compressedFileInfo.Length}/{Path.GetFileName(hyperFileInfo.FilePath)}"); + bytesToSend = Encoding.ASCII.GetBytes($"{fileInfo.Length}/{Path.GetFileName(hyperFileInfo.FilePath)}"); await nwStream.WriteAsync(bytesToSend); foreach (byte[]? chunk in FileCompressor.ReadChunks(hyperFileInfo.FilePath, 64000)) @@ -187,8 +176,6 @@ namespace HyperbolicDownloader.Networking await nwStream.WriteAsync(chunk); } } - - // File.Delete(compressedFilePath); } else { diff --git a/HyperbolicDownloader/Networking/NetworkUtilities.cs b/HyperbolicDownloader/Networking/NetworkUtilities.cs index a24f615..910353a 100644 --- a/HyperbolicDownloader/Networking/NetworkUtilities.cs +++ b/HyperbolicDownloader/Networking/NetworkUtilities.cs @@ -4,7 +4,7 @@ using System.Net.Sockets; namespace HyperbolicDownloader.Networking; -internal class NetworkUtilities +internal static class NetworkUtilities { public static UnicastIPAddressInformation? GetUnicastIPAddressInformation(IPAddress address) { @@ -12,12 +12,9 @@ internal class NetworkUtilities { foreach (UnicastIPAddressInformation unicastIPAddressInformation in adapter.GetIPProperties().UnicastAddresses) { - if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork) + if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork && address.Equals(unicastIPAddressInformation.Address)) { - if (address.Equals(unicastIPAddressInformation.Address)) - { - return unicastIPAddressInformation; - } + return unicastIPAddressInformation; } } } diff --git a/HyperbolicDownloader/Program.cs b/HyperbolicDownloader/Program.cs index bb9cb37..a8073de 100644 --- a/HyperbolicDownloader/Program.cs +++ b/HyperbolicDownloader/Program.cs @@ -1,5 +1,4 @@ - -using HyperbolicDownloader.FileProcessing; +using HyperbolicDownloader.FileProcessing; using HyperbolicDownloader.Networking; using HyperbolicDownloader.UserInterface; @@ -10,30 +9,23 @@ using Stone_Red_Utilities.ConsoleExtentions; using System.Diagnostics; using System.Net; using System.Net.Sockets; +using System.Reflection; using System.Text.Json; namespace HyperbolicDownloader; -internal class Program +internal static class Program { public const int BroadcastPort = 2155; - public const string HostsFilePath = "Hosts.json"; - public const string FilesInfoPath = "Files.json"; + + public static string BasePath { get; } = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) ?? string.Empty; + public static string HostsFilePath { get; } = Path.Combine(BasePath, "Hosts.json"); + public static string FilesInfoPath { get; } = Path.Combine(BasePath, "Files.json"); 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; - } - } + public static IPAddress? PublicIpAddress => device?.GetExternalIPAsync().GetAwaiter().GetResult(); private static NatDevice? device; private static Mapping? portMapping; @@ -42,7 +34,7 @@ internal class Program private static readonly NetworkClient networkClient = new(filesManager); private static readonly Random random = new(); - private static async Task Main() + private static async Task Main(string[] args) { Console.CancelKeyPress += Console_CancelKeyPress; Console.CursorVisible = false; @@ -56,7 +48,20 @@ internal class Program if (File.Exists(FilesInfoPath)) { string filesJson = await File.ReadAllTextAsync(FilesInfoPath); - filesManager.AddRange(JsonSerializer.Deserialize>(filesJson) ?? new()); + filesManager.AddRange(JsonSerializer.Deserialize>(filesJson) ?? new()); + } + + InputHandler inputHandler = new InputHandler(hostsManager, filesManager); + + if (args.Length > 0 && File.Exists(args[0])) + { + inputHandler.GetFileFrom(args[0]); + Console.WriteLine("Do you want to continue using this instance? [y/N]"); + if (char.ToLower(Console.ReadKey().KeyChar) != 'y') + { + return; + } + Console.WriteLine(); } Console.WriteLine("Searching for a UPnP/NAT-PMP device..."); @@ -77,7 +82,8 @@ internal class Program } catch (SocketException ex) { - Console.WriteLine($"An error occurred while starting the TCP listener! Error message: {ex.Message}"); + ConsoleExt.WriteLine($"An error occurred while starting the TCP listener! Error message: {ex.Message}", ConsoleColor.Red); // net stop hns && net start hns + Console.ReadKey(); return; } @@ -107,7 +113,7 @@ internal class Program broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived; ConsoleExt.WriteLine("Done", ConsoleColor.Green); - new InputHandler(hostsManager, filesManager).ReadInput(); + inputHandler.ReadInput(); ClosePorts(); } diff --git a/HyperbolicDownloader/UserInterface/InputHandler.cs b/HyperbolicDownloader/UserInterface/InputHandler.cs index 922f349..beb4fa0 100644 --- a/HyperbolicDownloader/UserInterface/InputHandler.cs +++ b/HyperbolicDownloader/UserInterface/InputHandler.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Text; +using System.Text.Json; namespace HyperbolicDownloader.UserInterface; @@ -27,7 +28,12 @@ internal class InputHandler commander.Register(Exit, "exit", "quit"); commander.Register(ShowInfo, "info", "inf"); commander.Register(Discover, "discover", "disc"); - commander.Register(GetFile, "get"); + + Command getCommand = commander.Register(GetFile, "get"); + getCommand.Register(GetFileFrom, "from"); + + Command generateCommad = commander.Register(GenerateFileFull, "generate", "gen"); + generateCommad.Register(GenerateFileSingle, "single"); Command addCommand = commander.Register(AddFile, "add"); addCommand.Register(AddHost, "host"); @@ -113,9 +119,9 @@ internal class InputHandler } } - private void AddFile(string args) + private void AddFile(string path) { - if (filesManager.TryAdd(args, out HyperFileInfo? fileInfo, out string? message)) + if (filesManager.TryAdd(path, out PrivateHyperFileInfo? fileInfo, out string? message)) { ConsoleExt.WriteLine($"Added file: {fileInfo!.FilePath}", ConsoleColor.Green); Console.WriteLine($"Hash: {fileInfo.Hash}"); @@ -126,9 +132,11 @@ internal class InputHandler } } - private void RemoveFile(string args) + private void RemoveFile(string hash) { - if (filesManager.TryRemove(args)) + hash = hash.Trim().ToLower(); + + if (filesManager.TryRemove(hash)) { ConsoleExt.WriteLine($"Removed file successfully!", ConsoleColor.Green); } @@ -141,7 +149,7 @@ internal class InputHandler private void ListFiles(string _) { int index = 0; - foreach (HyperFileInfo fileInfo in filesManager.ToList()) + foreach (PrivateHyperFileInfo fileInfo in filesManager.ToList()) { index++; Console.WriteLine($"{index}) {fileInfo.FilePath}"); @@ -203,6 +211,151 @@ internal class InputHandler 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)) @@ -211,7 +364,7 @@ internal class InputHandler return; } - hash = hash.Trim(); + hash = hash.Trim().ToLower(); foreach (NetworkSocket host in hostsManager.ToList()) { @@ -251,7 +404,7 @@ internal class InputHandler ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Has the requested file", ConsoleColor.Green); Console.WriteLine("Requesting file..."); - TcpClient tcpClient = new TcpClient(); + using TcpClient tcpClient = new TcpClient(); tcpClient.Connect(ipAddress!, host.Port); tcpClient.ReceiveBufferSize = 64000; @@ -290,19 +443,20 @@ internal class InputHandler } string fileName = parts[1].ToFileName(); - string filepath = $"./Downloads/{fileName}"; + 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("./Downloads")) + if (!Directory.Exists(directoryPath)) { - Directory.CreateDirectory("./Downloads"); + Directory.CreateDirectory(directoryPath); } - using FileStream? fileStream = new FileStream(filepath, FileMode.Create); + using FileStream? fileStream = new FileStream(filePath, FileMode.Create); int bytesInOneSecond = 0; int unitsPerSecond = 0; @@ -362,16 +516,16 @@ internal class InputHandler Console.WriteLine(); Console.WriteLine("Validating file..."); - if (FileValidator.ValidateHash(filepath, hash)) + if (FileValidator.ValidateHash(filePath, hash)) { - _ = filesManager.TryAdd(filepath, out _, out _); + _ = 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)}"); + Console.WriteLine($"File saved at: {Path.GetFullPath(filePath)}"); ConsoleExt.WriteLine("Done", ConsoleColor.Green); stopWatch.Stop(); hostsManager.SaveHosts();