From 8a587ee62794b90db38e1af7733ed576cf253f07 Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed, 13 Dec 2023 21:34:57 +0100 Subject: [PATCH] Add new `log` command and some general command improvments --- HyperbolicDownloader/GlobalSuppressions.cs | 8 ++ HyperbolicDownloader/InputHandler.cs | 2 + HyperbolicDownloader/LogCommands.cs | 77 +++++++++++++++ HyperbolicDownloader/Program.cs | 11 ++- .../Commands/DownloadCommands.cs | 61 ++++++++---- .../Commands/FileCommands.cs | 73 +++++++++++--- .../Commands/HostCommands.cs | 26 ++++- .../FileProcessing/FilesManager.cs | 2 +- .../Managment/ApiManager.cs | 56 +++++++---- .../Managment/NotificationMessageEventArgs.cs | 1 + .../Networking/BroadcastClient.cs | 7 +- .../Networking/HostsManager.cs | 17 +--- .../Networking/NetworkClient.cs | 96 ++++++++++--------- 13 files changed, 319 insertions(+), 118 deletions(-) create mode 100644 HyperbolicDownloader/GlobalSuppressions.cs create mode 100644 HyperbolicDownloader/LogCommands.cs diff --git a/HyperbolicDownloader/GlobalSuppressions.cs b/HyperbolicDownloader/GlobalSuppressions.cs new file mode 100644 index 0000000..82505d5 --- /dev/null +++ b/HyperbolicDownloader/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Critical Code Smell", "S3998:Threads should not lock on objects with weak identity", Justification = "Not a problem in this case", Scope = "member", Target = "~M:HyperbolicDownloader.LogCommands.OnNotificationMessageRecived(System.Object,HyperbolicDownloaderApi.Managment.NotificationMessageEventArgs)")] \ No newline at end of file diff --git a/HyperbolicDownloader/InputHandler.cs b/HyperbolicDownloader/InputHandler.cs index 3755c4f..1e25aa6 100644 --- a/HyperbolicDownloader/InputHandler.cs +++ b/HyperbolicDownloader/InputHandler.cs @@ -19,12 +19,14 @@ internal class InputHandler FileCommands fileCommands = new FileCommands(hostsManager, filesManager); DownloadCommands downloadCommands = new DownloadCommands(hostsManager, filesManager); ClientCommands clientCommands = new ClientCommands(); + LogCommands logCommands = new LogCommands(); _ = commander.Register(input => commander.PrintHelp(input), "help"); _ = commander.Register(_ => Console.Clear(), (HelpText)"Clears the console.", "clear", "cls"); _ = commander.Register(_ => exit = true, (HelpText)"Exits the application.", "exit", "quit"); _ = commander.Register(clientCommands.ShowInfo, (HelpText)"Displays the private and public IP address.", "info", "inf"); _ = commander.Register(hostCommands.Discover, (HelpText)"Tries to find other active hosts on the local network.", "discover", "disc"); + _ = commander.Register(logCommands.Log, (HelpText)"Displays live log.", "log"); Command getCommand = commander.Register(downloadCommands.GetFile, (HelpText)"Attempts to retrieve a file from another host using a hash.", "get"); _ = getCommand.Register(downloadCommands.GetFileFrom, (HelpText)"Attempts to retrieve a file from another host using a .hyper file.", "from"); diff --git a/HyperbolicDownloader/LogCommands.cs b/HyperbolicDownloader/LogCommands.cs new file mode 100644 index 0000000..e47c0d8 --- /dev/null +++ b/HyperbolicDownloader/LogCommands.cs @@ -0,0 +1,77 @@ +using HyperbolicDownloaderApi.Managment; + +using Stone_Red_Utilities.ConsoleExtentions; + +using System.Net; + +namespace HyperbolicDownloader; + +internal class LogCommands +{ + public void Log(string _) + { + Console.Clear(); + + ApiManager.OnNotificationMessageRecived += OnNotificationMessageRecived; + + char c = ' '; + + do + { + if (c != '\0') + { + Console.WriteLine("Press 'q' to exit"); + } + c = Console.ReadKey(true).KeyChar; + } while (c != 'q'); + + ApiManager.OnNotificationMessageRecived -= OnNotificationMessageRecived; + + Console.Clear(); + + Console.WriteLine("Log closed"); + } + + private void OnNotificationMessageRecived(object? sender, NotificationMessageEventArgs e) + { + if (e.NotificationMessageType == NotificationMessageType.Log) + { + lock (Console.Out) + { + if (e.Message?.Contains('>') == true && IPAddress.TryParse(e.Message[..e.Message.IndexOf('>')].Trim(), out IPAddress? ipAddress)) + { + ConsoleExt.Write($"[{DateTime.Now}] ", ConsoleColor.DarkGray); + + byte[] ipAddressBytes = ipAddress.GetAddressBytes(); + + Array.Resize(ref ipAddressBytes, 8); + + ConsoleColor consoleColor = (BitConverter.ToInt64(ipAddressBytes) % 12) switch + { + 0 => ConsoleColor.Red, + 1 => ConsoleColor.Green, + 2 => ConsoleColor.Yellow, + 3 => ConsoleColor.Blue, + 4 => ConsoleColor.Magenta, + 5 => ConsoleColor.Cyan, + 6 => ConsoleColor.DarkRed, + 7 => ConsoleColor.DarkGreen, + 8 => ConsoleColor.DarkYellow, + 9 => ConsoleColor.DarkBlue, + 10 => ConsoleColor.DarkMagenta, + 11 => ConsoleColor.DarkCyan, + _ => ConsoleColor.White + }; + + ConsoleExt.Write(e.Message[..e.Message.IndexOf('>')], consoleColor); + ConsoleExt.Write(e.Message[e.Message.IndexOf('>')..], ConsoleColor.White); + } + else + { + ConsoleExt.Write($"[{DateTime.Now}] ", ConsoleColor.DarkGray); + ConsoleExt.Write(e.Message, ConsoleColor.White); + } + } + } + } +} \ No newline at end of file diff --git a/HyperbolicDownloader/Program.cs b/HyperbolicDownloader/Program.cs index a6af901..90ce820 100644 --- a/HyperbolicDownloader/Program.cs +++ b/HyperbolicDownloader/Program.cs @@ -22,7 +22,7 @@ internal static class Program if (File.Exists(ApiConfiguration.HostsFilePath)) { string hostsJson = await File.ReadAllTextAsync(ApiConfiguration.HostsFilePath); - apiManager.HostsManager.AddRange(JsonSerializer.Deserialize>(hostsJson) ?? new()); + _ = apiManager.HostsManager.AddRange(JsonSerializer.Deserialize>(hostsJson) ?? new()); } if (File.Exists(ApiConfiguration.FilesInfoPath)) @@ -63,10 +63,15 @@ internal static class Program if (!apiManager.StartTcpListener()) { _ = Console.ReadLine(); + Environment.Exit(-1); } - Console.WriteLine("Starting broadcast listener..."); - apiManager.StartBroadcastListener(); + Console.WriteLine("Starting UDP listener..."); + if (!apiManager.StartBroadcastListener()) + { + _ = Console.ReadLine(); + Environment.Exit(-2); + } int activeHostsCount = 0; if (apiManager.HostsManager.Count > 0) diff --git a/HyperbolicDownloaderApi/Commands/DownloadCommands.cs b/HyperbolicDownloaderApi/Commands/DownloadCommands.cs index 574077b..63dd3ce 100644 --- a/HyperbolicDownloaderApi/Commands/DownloadCommands.cs +++ b/HyperbolicDownloaderApi/Commands/DownloadCommands.cs @@ -47,7 +47,7 @@ public class DownloadCommands return; } - hostsManager.AddRange(publicHyperFileInfo.Hosts); + _ = hostsManager.AddRange(publicHyperFileInfo.Hosts); GetFile(publicHyperFileInfo.Hash); } @@ -109,7 +109,7 @@ public class DownloadCommands byte[] bytesToSend = Encoding.ASCII.GetBytes($"Download {hash}"); nwStream.Write(bytesToSend); - nwStream.ReadTimeout = 30000; + nwStream.ReadTimeout = 5000; int bytesRead; try @@ -157,9 +157,8 @@ public class DownloadCommands using FileStream? fileStream = new FileStream(filePath, FileMode.Create); - int bytesInOneSecond = 0; - int unitsPerSecond = 0; - string unit = "Kb"; + int bytesPerSecond = 0; + int transferRate = 0; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); @@ -182,26 +181,16 @@ public class DownloadCommands fileStream.Write(reciveBuffer, 0, bytesRead); totalBytesRead += bytesRead; - bytesInOneSecond += bytesRead; + bytesPerSecond += bytesRead; if (stopWatch.Elapsed.TotalSeconds >= 1) { - unitsPerSecond = (int)(bytesInOneSecond * stopWatch.Elapsed.TotalSeconds); - if (unitsPerSecond > 125000) - { - unitsPerSecond /= 125000; - unit = "Mb"; - } - else - { - unitsPerSecond /= 125; - unit = "Kb"; - } - bytesInOneSecond = 0; + transferRate = bytesPerSecond; + bytesPerSecond = 0; stopWatch.Restart(); } - ApiManager.SendNotificationMessage($"\rDownloading: {Math.Clamp(Math.Ceiling(100d / fileSize * totalBytesRead), 0, 100)}% {totalBytesRead / 1000}/{fileSize / 1000}KB [{unitsPerSecond}{unit}/s] "); + ApiManager.SendNotificationMessage($"\rDownloading: {Math.Clamp(Math.Ceiling(100d / fileSize * totalBytesRead), 0, 100)}% {DisplayFileSize(totalBytesRead)}/{DisplayFileSize(fileSize)} [{DisplayTransferRate(transferRate)}] "); } fileStream.Close(); @@ -233,4 +222,38 @@ public class DownloadCommands ApiManager.SendNotificationMessageNewLine("None of the available hosts have the requested file!", NotificationMessageType.Error); hostsManager.SaveHosts(); } + + private string DisplayTransferRate(long bytesPerSecond) + { + string[] ordinals = new[] { "", "K", "M", "G", "T", "P", "E" }; + + decimal rate = bytesPerSecond * 8; + + int ordinal = 0; + + while (rate > 1000) + { + rate /= 1000; + ordinal++; + } + + return $"{Math.Round(rate, 0, MidpointRounding.AwayFromZero)}{ordinals[ordinal]}bps"; + } + + private string DisplayFileSize(long bytes) + { + string[] ordinals = new[] { "", "K", "M", "G", "T", "P", "E" }; + + decimal rate = bytes; + + int ordinal = 0; + + while (rate > 1000) + { + rate /= 1000; + ordinal++; + } + + return $"{Math.Round(rate, 0, MidpointRounding.AwayFromZero)}{ordinals[ordinal]}B"; + } } \ No newline at end of file diff --git a/HyperbolicDownloaderApi/Commands/FileCommands.cs b/HyperbolicDownloaderApi/Commands/FileCommands.cs index e15fbf9..60d337f 100644 --- a/HyperbolicDownloaderApi/Commands/FileCommands.cs +++ b/HyperbolicDownloaderApi/Commands/FileCommands.cs @@ -32,11 +32,24 @@ public class FileCommands } } - public void RemoveFile(string hash) + public void RemoveFile(string args) { - hash = hash.Trim().ToLower(); + args = args.Trim().ToLower(); - if (filesManager.TryRemove(hash)) + if (int.TryParse(args, out int index)) + { + List fileInfos = filesManager.ToList(); + + if (index < 1 || index > fileInfos.Count) + { + ApiManager.SendNotificationMessageNewLine("Invalid index!", NotificationMessageType.Error); + return; + } + + args = fileInfos[index - 1].Hash; + } + + if (filesManager.TryRemove(args)) { ApiManager.SendNotificationMessageNewLine($"Successfully removed file!", NotificationMessageType.Success); } @@ -46,7 +59,7 @@ public class FileCommands } } - public void ListFiles(string _) + public void ListFiles(string searchString) { int index = 0; List fileInfos = filesManager.ToList(); @@ -60,6 +73,12 @@ public class FileCommands foreach (PrivateHyperFileInfo fileInfo in fileInfos) { index++; + + if (!string.IsNullOrWhiteSpace(searchString) && !fileInfo.FilePath.Contains(searchString, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + ApiManager.SendNotificationMessageNewLine($"{index}) {fileInfo.FilePath}"); ApiManager.SendNotificationMessageNewLine($"Hash: {fileInfo.Hash}"); ApiManager.SendNotificationMessageNewLine(string.Empty); @@ -67,7 +86,7 @@ public class FileCommands Console.CursorTop--; } - public void GenerateFileSingle(string hash) + public void GenerateFileSingle(string args) { string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles"); if (!Directory.Exists(directoryPath)) @@ -75,9 +94,23 @@ public class FileCommands _ = Directory.CreateDirectory(directoryPath); } - hash = hash.Trim().ToLower(); + args = args.Trim().ToLower(); - if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) + PrivateHyperFileInfo? localHyperFileInfo; + + if (int.TryParse(args, out int index)) + { + List fileInfos = filesManager.ToList(); + + if (index < 1 || index > fileInfos.Count) + { + ApiManager.SendNotificationMessageNewLine("Invalid index!", NotificationMessageType.Error); + return; + } + + localHyperFileInfo = fileInfos[index - 1]; + } + else if (!filesManager.TryGet(args, out localHyperFileInfo)) { ApiManager.SendNotificationMessageNewLine("The file is not being tracked!", NotificationMessageType.Error); return; @@ -86,7 +119,7 @@ public class FileCommands string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); - PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); + PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(args); NetworkSocket? localHost = ApiManager.GetLocalSocket(); if (localHost is null) @@ -106,7 +139,7 @@ public class FileCommands ApiManager.SendNotificationMessageNewLine($"File saved at: {Path.GetFullPath(filePath)}"); } - public void GenerateFileFull(string hash) + public void GenerateFileFull(string args) { string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles"); if (!Directory.Exists(directoryPath)) @@ -114,9 +147,23 @@ public class FileCommands _ = Directory.CreateDirectory(directoryPath); } - hash = hash.Trim().ToLower(); + args = args.Trim().ToLower(); - if (!filesManager.TryGet(hash, out PrivateHyperFileInfo? localHyperFileInfo)) + PrivateHyperFileInfo? localHyperFileInfo; + + if (int.TryParse(args, out int index)) + { + List fileInfos = filesManager.ToList(); + + if (index < 1 || index > fileInfos.Count) + { + ApiManager.SendNotificationMessageNewLine("Invalid index!", NotificationMessageType.Error); + return; + } + + localHyperFileInfo = fileInfos[index - 1]; + } + else if (!filesManager.TryGet(args, out localHyperFileInfo)) { ApiManager.SendNotificationMessageNewLine("The file is not being tracked!", NotificationMessageType.Error); return; @@ -125,7 +172,7 @@ public class FileCommands string fileName = Path.GetFileName(localHyperFileInfo!.FilePath); string filePath = Path.Combine(directoryPath, $"{fileName}.hyper"); - PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(hash); + PublicHyperFileInfo publicHyperFileInfo = new PublicHyperFileInfo(args); NetworkSocket? localHost = ApiManager.GetLocalSocket(); if (localHost is null) @@ -148,7 +195,7 @@ public class FileCommands Console.CursorLeft = 0; - Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", hash); + Task sendTask = NetworkClient.SendAsync(ipAddress!, host.Port, "HasFile", args); _ = sendTask.Wait(1000); diff --git a/HyperbolicDownloaderApi/Commands/HostCommands.cs b/HyperbolicDownloaderApi/Commands/HostCommands.cs index 86d307d..8bc86da 100644 --- a/HyperbolicDownloaderApi/Commands/HostCommands.cs +++ b/HyperbolicDownloaderApi/Commands/HostCommands.cs @@ -67,6 +67,20 @@ public class HostCommands { string[] parts = args.Split(":"); + if (int.TryParse(args, out int index)) + { + if (hostsManager.Count < index || index < 1) + { + ApiManager.SendNotificationMessageNewLine("Invalid index!", NotificationMessageType.Error); + return; + } + + hostsManager.Remove(hostsManager.ToList()[index - 1], true); + ApiManager.SendNotificationMessageNewLine($"Successfully Removed host!", NotificationMessageType.Success); + + return; + } + if (parts.Length != 2) { ApiManager.SendNotificationMessageNewLine("Invalid format! Use this format: (xxx.xxx.xxx.xxx:yyyy)", NotificationMessageType.Error); @@ -144,7 +158,17 @@ public class HostCommands { ApiManager.SendNotificationMessageNewLine("Waiting for response...", NotificationMessageType.Info); NetworkSocket? localSocket = ApiManager.GetLocalSocket() ?? new NetworkSocket("0.0.0.0", 0, DateTime.MinValue); - List? recivedHosts = NetworkClient.Send>(ipAddress, port, "GetHostsList", localSocket); + Task?> sendTask = NetworkClient.SendAsync>(ipAddress, port, "GetHostsList", localSocket); + + _ = sendTask.Wait(5000); + + if (!sendTask.IsCompletedSuccessfully) + { + ApiManager.SendNotificationMessageNewLine($"No response from {ipAddress}:{port}", NotificationMessageType.Error); + return; + } + + List? recivedHosts = sendTask.Result; if (recivedHosts is not null) { diff --git a/HyperbolicDownloaderApi/FileProcessing/FilesManager.cs b/HyperbolicDownloaderApi/FileProcessing/FilesManager.cs index d586503..12d9f83 100644 --- a/HyperbolicDownloaderApi/FileProcessing/FilesManager.cs +++ b/HyperbolicDownloaderApi/FileProcessing/FilesManager.cs @@ -83,7 +83,7 @@ public class FilesManager public bool Contains(string? hash) { - return files.Any(f => f.Hash == hash); + return files.Exists(f => f.Hash == hash); } public List ToList() diff --git a/HyperbolicDownloaderApi/Managment/ApiManager.cs b/HyperbolicDownloaderApi/Managment/ApiManager.cs index 213bd87..38ee6f1 100644 --- a/HyperbolicDownloaderApi/Managment/ApiManager.cs +++ b/HyperbolicDownloaderApi/Managment/ApiManager.cs @@ -13,15 +13,14 @@ public class ApiManager { public static event EventHandler? OnNotificationMessageRecived; - public static IPAddress? PublicIpAddress => device?.GetExternalIPAsync().GetAwaiter().GetResult(); - public FilesManager FilesManager { get; } = new(); - public HostsManager HostsManager { get; } = new(); - private static readonly Random random = new(); private static NatDevice? device; private static Mapping? portMapping; private readonly BroadcastClient broadcastClient = new BroadcastClient(); private readonly NetworkClient networkClient; + public static IPAddress? PublicIpAddress => device?.GetExternalIPAsync().GetAwaiter().GetResult(); + public FilesManager FilesManager { get; } = new(); + public HostsManager HostsManager { get; } = new(); public ApiManager() { @@ -106,7 +105,7 @@ public class ApiManager } catch (Exception ex) { - SendNotificationMessageNewLine(ex.ToString(), NotificationMessageType.Error); + SendNotificationMessageNewLine(ex.Message, NotificationMessageType.Error); } } @@ -114,10 +113,20 @@ public class ApiManager Environment.Exit(0); } - public void StartBroadcastListener() + public bool StartBroadcastListener() { - broadcastClient.StartListening(ApiConfiguration.BroadcastPort); - broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived; + try + { + broadcastClient.StartListening(ApiConfiguration.BroadcastPort); + broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived; + } + catch (SocketException ex) + { + SendNotificationMessageNewLine($"An error occurred while starting the TCP listener! Error message: {ex.Message}", NotificationMessageType.Error); // net stop hens && net start hns + return false; + } + + return true; } public bool StartTcpListener() @@ -139,6 +148,16 @@ public class ApiManager return true; } + internal static void SendNotificationMessage(string message, NotificationMessageType messageType = NotificationMessageType.Info) + { + OnNotificationMessageRecived?.Invoke(null, new NotificationMessageEventArgs(messageType, message)); + } + + internal static void SendNotificationMessageNewLine(string message, NotificationMessageType messageType = NotificationMessageType.Info) + { + OnNotificationMessageRecived?.Invoke(null, new NotificationMessageEventArgs(messageType, message + Environment.NewLine)); + } + private async void BroadcastClient_OnBroadcastRecived(object? sender, BroadcastRecivedEventArgs recivedEventArgs) { IPAddress remoteIpAddress = recivedEventArgs.IPEndPoint.Address; @@ -161,7 +180,7 @@ public class ApiManager if (success) { - HostsManager.Add(new NetworkSocket(remoteIpAddress.ToString(), remotePort, DateTime.Now)); + _ = HostsManager.Add(new NetworkSocket(remoteIpAddress.ToString(), remotePort, DateTime.Now)); try { await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend); @@ -176,11 +195,14 @@ public class ApiManager private void DiscoverAnswer(object? sender, MessageRecivedEventArgs> recivedEventArgs) { SendNotificationMessageNewLine($"Received answer from {recivedEventArgs.IpAddress}. Returned {recivedEventArgs.Data.Count} host(s).", NotificationMessageType.Info); - HostsManager.AddRange(recivedEventArgs.Data); + SendNotificationMessageNewLine($"{recivedEventArgs.IpAddress} > Discovery answer {string.Join(", ", recivedEventArgs.Data)}", NotificationMessageType.Log); + _ = HostsManager.AddRange(recivedEventArgs.Data); } private async void GetHostList(object? sender, MessageRecivedEventArgs recivedEventArgs) { + SendNotificationMessageNewLine($"{recivedEventArgs.IpAddress} > Requesting file list", NotificationMessageType.Log); + List hostsToSend = HostsManager.ToList(); NetworkSocket? localSocket = GetLocalSocket(); @@ -195,7 +217,7 @@ public class ApiManager if (recivedEventArgs.Data.Port != 0) { - HostsManager.Add(recivedEventArgs.Data); + _ = HostsManager.Add(recivedEventArgs.Data); } await recivedEventArgs.SendResponseAsync(hostsToSend); @@ -203,6 +225,8 @@ public class ApiManager private async void HasFile(object? sender, MessageRecivedEventArgs recivedEventArgs) { + SendNotificationMessageNewLine($"{recivedEventArgs.IpAddress} > Check if file exists [{recivedEventArgs.Data}]", NotificationMessageType.Log); + await recivedEventArgs.SendResponseAsync(FilesManager.Contains(recivedEventArgs.Data)); } @@ -210,14 +234,4 @@ public class ApiManager { SendNotificationMessageNewLine($"Received \"{recivedEventArgs.Data}\" from {recivedEventArgs.IpAddress}.", NotificationMessageType.Info); } - - internal static void SendNotificationMessage(string message, NotificationMessageType messageType = NotificationMessageType.Info) - { - OnNotificationMessageRecived?.Invoke(null, new NotificationMessageEventArgs(messageType, message)); - } - - internal static void SendNotificationMessageNewLine(string message, NotificationMessageType messageType = NotificationMessageType.Info) - { - OnNotificationMessageRecived?.Invoke(null, new NotificationMessageEventArgs(messageType, message + Environment.NewLine)); - } } \ No newline at end of file diff --git a/HyperbolicDownloaderApi/Managment/NotificationMessageEventArgs.cs b/HyperbolicDownloaderApi/Managment/NotificationMessageEventArgs.cs index 24aba57..0f0aad5 100644 --- a/HyperbolicDownloaderApi/Managment/NotificationMessageEventArgs.cs +++ b/HyperbolicDownloaderApi/Managment/NotificationMessageEventArgs.cs @@ -15,6 +15,7 @@ public class NotificationMessageEventArgs : EventArgs public enum NotificationMessageType { Info, + Log, Success, Warning, Error diff --git a/HyperbolicDownloaderApi/Networking/BroadcastClient.cs b/HyperbolicDownloaderApi/Networking/BroadcastClient.cs index 24684b8..324397c 100644 --- a/HyperbolicDownloaderApi/Networking/BroadcastClient.cs +++ b/HyperbolicDownloaderApi/Networking/BroadcastClient.cs @@ -11,9 +11,8 @@ internal class BroadcastClient { public event EventHandler? OnBroadcastRecived; - public bool IsListening { get; private set; } = false; - private UdpClient? udpListener; + public bool IsListening { get; private set; } = false; public static void Send(int port, string message) { @@ -58,7 +57,7 @@ internal class BroadcastClient udpListener = new UdpClient(port); IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port); - _ = Task.Run(() => + _ = new TaskFactory().StartNew(() => { while (IsListening) { @@ -67,7 +66,7 @@ internal class BroadcastClient OnBroadcastRecived?.Invoke(this, new BroadcastRecivedEventArgs(groupEP, message)); } - }); + }, TaskCreationOptions.LongRunning); } public void StopListening() diff --git a/HyperbolicDownloaderApi/Networking/HostsManager.cs b/HyperbolicDownloaderApi/Networking/HostsManager.cs index 7281f47..9029f61 100644 --- a/HyperbolicDownloaderApi/Networking/HostsManager.cs +++ b/HyperbolicDownloaderApi/Networking/HostsManager.cs @@ -12,16 +12,7 @@ public class HostsManager public int AddRange(IEnumerable hosts) { - int newHosts = 0; - - foreach (NetworkSocket host in hosts) - { - if (Add(host)) - { - newHosts++; - } - } - + int newHosts = hosts.Count(Add); SaveHosts(); return newHosts; @@ -44,14 +35,14 @@ public class HostsManager { if (DateTime.Now - host.LastActive >= new TimeSpan(24, 0, 0) || forceRemove) { - _ = hosts.RemoveAll(x => x.IPAddress == host.IPAddress && x.Port == host.Port); + _ = hosts.RemoveAll(x => x.Equals(host)); } SaveHosts(); } public bool Contains(NetworkSocket host) { - return hosts.Any(x => x.IPAddress == host.IPAddress && x.Port == host.Port); + return hosts.Exists(x => x.Equals(host)); } public int CheckHostsActivity() @@ -65,7 +56,7 @@ public class HostsManager try { - _ = tcpClient.ConnectAsync(host.IPAddress, host.Port).Wait(500); + _ = tcpClient.ConnectAsync(host.IPAddress, host.Port).Wait(1000); Console.CursorLeft = 0; if (tcpClient.Connected) { diff --git a/HyperbolicDownloaderApi/Networking/NetworkClient.cs b/HyperbolicDownloaderApi/Networking/NetworkClient.cs index 18c44c9..5c62d06 100644 --- a/HyperbolicDownloaderApi/Networking/NetworkClient.cs +++ b/HyperbolicDownloaderApi/Networking/NetworkClient.cs @@ -1,4 +1,5 @@ using HyperbolicDownloaderApi.FileProcessing; +using HyperbolicDownloaderApi.Managment; using System.Diagnostics; using System.Net; @@ -10,11 +11,10 @@ namespace HyperbolicDownloaderApi.Networking; internal class NetworkClient { - public bool IsListening { get; private set; } = false; - - private TcpListener? tcpListener; private readonly FilesManager filesManager; private readonly Dictionary events = new(); + private TcpListener? tcpListener; + public bool IsListening { get; private set; } = false; public NetworkClient(FilesManager filesManager) { @@ -98,7 +98,7 @@ internal class NetworkClient tcpListener.Start(); IsListening = true; - _ = Task.Run(async () => + _ = new TaskFactory().StartNew(async () => { while (IsListening) { @@ -151,45 +151,7 @@ internal class NetworkClient } } tcpListener.Stop(); - }); - } - - private async Task Upload(TcpClient client, string hash) - { - try - { - byte[] bytesToSend; - hash = hash.Trim(); - NetworkStream nwStream = client.GetStream(); - client.SendBufferSize = 64000; - if (filesManager.TryGet(hash, out PrivateHyperFileInfo? hyperFileInfo) && File.Exists(hyperFileInfo?.FilePath)) - { - FileInfo fileInfo = new FileInfo(hyperFileInfo.FilePath); - - bytesToSend = Encoding.ASCII.GetBytes($"{fileInfo.Length}/{Path.GetFileName(hyperFileInfo.FilePath)}"); - - Array.Resize(ref bytesToSend, 1000); - - await nwStream.WriteAsync(bytesToSend); - foreach (byte[]? chunk in FileCompressor.ReadChunks(hyperFileInfo.FilePath, 64000).Where(chunk => chunk is not null)) - { - await nwStream.WriteAsync(chunk); - } - } - else - { - bytesToSend = Encoding.ASCII.GetBytes("File not found!"); - await nwStream.WriteAsync(bytesToSend); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - finally - { - client.Close(); - } + }, TaskCreationOptions.LongRunning); } public void StopListening() @@ -202,4 +164,52 @@ internal class NetworkClient { events.Add(eventName, (typeof(T), eventHandler)); } + + private async Task Upload(TcpClient client, string hash) + { + try + { + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > Requesting file download [{hash}]", NotificationMessageType.Log); + byte[] bytesToSend; + hash = hash.Trim(); + NetworkStream nwStream = client.GetStream(); + client.SendBufferSize = 64000; + if (filesManager.TryGet(hash, out PrivateHyperFileInfo? hyperFileInfo) && File.Exists(hyperFileInfo?.FilePath)) + { + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > Accepting file download [{Path.GetFileName(hyperFileInfo.FilePath)}] [{hash}]", NotificationMessageType.Log); + + FileInfo fileInfo = new FileInfo(hyperFileInfo.FilePath); + + bytesToSend = Encoding.ASCII.GetBytes($"{fileInfo.Length}/{Path.GetFileName(hyperFileInfo.FilePath)}"); + + Array.Resize(ref bytesToSend, 1000); + + await nwStream.WriteAsync(bytesToSend); + + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > Starting file download of file [{Path.GetFileName(hyperFileInfo.FilePath)}] [{hash}]", NotificationMessageType.Log); + + foreach (byte[]? chunk in FileCompressor.ReadChunks(hyperFileInfo.FilePath, 64000).Where(chunk => chunk is not null)) + { + await nwStream.WriteAsync(chunk); + } + + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > Completed download of file [{Path.GetFileName(hyperFileInfo.FilePath)}] [{hash}]", NotificationMessageType.Log); + } + else + { + bytesToSend = Encoding.ASCII.GetBytes("File not found!"); + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > File not found [{hash}]", NotificationMessageType.Log); + await nwStream.WriteAsync(bytesToSend); + } + } + catch (Exception ex) + { + ApiManager.SendNotificationMessageNewLine($"{(client.Client.RemoteEndPoint as IPEndPoint)?.Address} > Error downloading file {ex.Message} [{hash}]", NotificationMessageType.Log); + Debug.WriteLine(ex); + } + finally + { + client.Close(); + } + } } \ No newline at end of file