Merge pull request #2 from Stone-Red-Code/develop

Develop
This commit is contained in:
Stone_Red
2023-02-06 15:41:19 +01:00
committed by GitHub
15 changed files with 281 additions and 294 deletions
+2 -8
View File
@@ -3,11 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339 VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HyperbolicDownloaderCli", "HyperbolicDownloader\HyperbolicDownloaderCli.csproj", "{7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HyperbolicDownloader", "HyperbolicDownloader\HyperbolicDownloader.csproj", "{7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HyperbolicDownloaderGUI", "HyperbolicDownloaderGUI\HyperbolicDownloaderGUI.csproj", "{E1CE6E07-F8A6-447F-837D-9D1943A42E96}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HyperbolicDownloaderApi", "HyperbolicDownloaderApi\HyperbolicDownloaderApi.csproj", "{45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyperbolicDownloaderApi", "HyperbolicDownloaderApi\HyperbolicDownloaderApi.csproj", "{45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CA4F21C6-5B63-46C1-8576-91BB3FAE4FA7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CA4F21C6-5B63-46C1-8576-91BB3FAE4FA7}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
@@ -24,10 +22,6 @@ Global
{7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Debug|Any CPU.Build.0 = Debug|Any CPU {7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Release|Any CPU.Build.0 = Release|Any CPU {7BA90CAF-36A1-4D55-9CE2-E498ECC1B62D}.Release|Any CPU.Build.0 = Release|Any CPU
{E1CE6E07-F8A6-447F-837D-9D1943A42E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1CE6E07-F8A6-447F-837D-9D1943A42E96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1CE6E07-F8A6-447F-837D-9D1943A42E96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1CE6E07-F8A6-447F-837D-9D1943A42E96}.Release|Any CPU.Build.0 = Release|Any CPU
{45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Debug|Any CPU.Build.0 = Debug|Any CPU {45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Release|Any CPU.ActiveCfg = Release|Any CPU {45ACEEC6-9AE4-4DA5-9A08-E22F1EBA7E22}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -12,7 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Console.Commander.NET" Version="1.0.0" /> <PackageReference Include="Console.Commander.NET" Version="1.0.1" />
<PackageReference Include="Stone_Red-C-Sharp-Utilities" Version="1.0.3.1" /> <PackageReference Include="Stone_Red-C-Sharp-Utilities" Version="1.0.3.1" />
</ItemGroup> </ItemGroup>
+22 -29
View File
@@ -2,14 +2,14 @@
using HyperbolicDownloaderApi.Commands; using HyperbolicDownloaderApi.Commands;
using HyperbolicDownloaderApi.FileProcessing; using HyperbolicDownloaderApi.FileProcessing;
using HyperbolicDownloaderApi.Networking;
using Stone_Red_Utilities.ConsoleExtentions; using Stone_Red_Utilities.ConsoleExtentions;
namespace HyperbolicDownloaderApi; namespace HyperbolicDownloader;
internal class InputHandler internal class InputHandler
{ {
private readonly HostsManager hostsManager;
private readonly Commander commander = new Commander(); private readonly Commander commander = new Commander();
private bool exit = false; private bool exit = false;
@@ -20,32 +20,31 @@ internal class InputHandler
DownloadCommands downloadCommands = new DownloadCommands(hostsManager, filesManager); DownloadCommands downloadCommands = new DownloadCommands(hostsManager, filesManager);
ClientCommands clientCommands = new ClientCommands(); ClientCommands clientCommands = new ClientCommands();
this.hostsManager = hostsManager; _ = 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((_) => Console.Clear(), "clear", "cls"); Command getCommand = commander.Register(downloadCommands.GetFile, (HelpText)"Attempts to retrieve a file from another host using a hash.", "get");
commander.Register(Exit, "exit", "quit"); _ = getCommand.Register(downloadCommands.GetFileFrom, (HelpText)"Attempts to retrieve a file from another host using a .hyper file.", "from");
commander.Register(clientCommands.ShowInfo, "info", "inf");
commander.Register(hostCommands.Discover, "discover", "disc");
Command getCommand = commander.Register(downloadCommands.GetFile, "get"); Command generateCommad = commander.Register(fileCommands.GenerateFileFull, (HelpText)"Generates a .hyper file from a file hash.", "generate", "gen");
getCommand.Register(downloadCommands.GetFileFrom, "from"); _ = generateCommad.Register(fileCommands.GenerateFileSingle, (HelpText)"Generates a .hyper file from a file hash without checking the known hosts. This adds only the local host to the file.", "noscan");
Command generateCommad = commander.Register(fileCommands.GenerateFileFull, "generate", "gen"); Command addCommand = commander.Register(fileCommands.AddFile, (HelpText)"Adds a file to the tracking list.", "add");
generateCommad.Register(fileCommands.GenerateFileSingle, "noscan"); _ = addCommand.Register(fileCommands.AddFile, (HelpText)"Adds a file to the tracking list.", "file");
_ = addCommand.Register(hostCommands.AddHost, (HelpText)"Adds a host to the list of known hosts.", "host");
Command addCommand = commander.Register(fileCommands.AddFile, "add"); Command removeCommand = commander.Register(fileCommands.RemoveFile, (HelpText)"Removes a file from the tracking list.", "remove", "rm");
addCommand.Register(hostCommands.AddHost, "host"); _ = removeCommand.Register(fileCommands.RemoveFile, (HelpText)"Removes a file from the tracking list.", "file");
addCommand.Register(fileCommands.AddFile, "file"); _ = removeCommand.Register(hostCommands.RemoveHost, (HelpText)"Removes a host from the list of known hosts.", "host");
Command removeCommand = commander.Register(fileCommands.RemoveFile, "remove", "rm"); Command listCommand = commander.Register(fileCommands.ListFiles, (HelpText)"Lists all files.", "list", "ls");
removeCommand.Register(hostCommands.RemoveHost, "host"); _ = listCommand.Register(fileCommands.ListFiles, (HelpText)"Lists all files.", "files");
removeCommand.Register(fileCommands.RemoveFile, "file"); _ = listCommand.Register(hostCommands.ListHosts, (HelpText)"lists all hosts.", "hosts");
Command listCommand = commander.Register(fileCommands.ListFiles, "list", "ls"); _ = commander.Register(hostCommands.CheckActiveHosts, (HelpText)"Checks the status of known hosts.", "status", "check");
listCommand.Register(fileCommands.ListFiles, "files");
listCommand.Register(hostCommands.ListHosts, "hosts");
commander.Register(hostCommands.CheckActiveHosts, "status", "check");
} }
public void ReadInput() public void ReadInput()
@@ -61,7 +60,7 @@ internal class InputHandler
Console.CursorVisible = false; Console.CursorVisible = false;
try try
{ {
if (!commander.Execute(input)) if (!commander.Execute(input, out _))
{ {
ConsoleExt.WriteLine("Unknown command!", ConsoleColor.Red); ConsoleExt.WriteLine("Unknown command!", ConsoleColor.Red);
} }
@@ -72,10 +71,4 @@ internal class InputHandler
} }
} }
} }
private void Exit(string _)
{
hostsManager.SaveHosts();
exit = true;
}
} }
+16 -8
View File
@@ -6,7 +6,7 @@ using Stone_Red_Utilities.ConsoleExtentions;
using System.Text.Json; using System.Text.Json;
namespace HyperbolicDownloaderApi; namespace HyperbolicDownloader;
internal static class Program internal static class Program
{ {
@@ -14,7 +14,7 @@ internal static class Program
private static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
Console.CancelKeyPress += Console_CancelKeyPress; Console.CancelKeyPress += (_, _) => Close();
Console.CursorVisible = false; Console.CursorVisible = false;
ApiManager.OnNotificationMessageRecived += ApiManager_OnNotificationMessageRecived; ApiManager.OnNotificationMessageRecived += ApiManager_OnNotificationMessageRecived;
@@ -35,7 +35,7 @@ internal static class Program
if (args.Length > 0 && File.Exists(args[0])) if (args.Length > 0 && File.Exists(args[0]))
{ {
Commands.DownloadCommands downloadCommands = new Commands.DownloadCommands(apiManager.HostsManager, apiManager.FilesManager); HyperbolicDownloaderApi.Commands.DownloadCommands downloadCommands = new HyperbolicDownloaderApi.Commands.DownloadCommands(apiManager.HostsManager, apiManager.FilesManager);
downloadCommands.GetFileFrom(args[0]); downloadCommands.GetFileFrom(args[0]);
Console.WriteLine("Do you want to continue using this instance? [y/N]"); Console.WriteLine("Do you want to continue using this instance? [y/N]");
if (char.ToLower(Console.ReadKey().KeyChar) != 'y') if (char.ToLower(Console.ReadKey().KeyChar) != 'y')
@@ -45,6 +45,14 @@ internal static class Program
Console.WriteLine(); Console.WriteLine();
} }
await Initialize();
inputHandler.ReadInput();
Close();
}
private static async Task Initialize()
{
Console.WriteLine("Searching for a UPnP/NAT-PMP device..."); Console.WriteLine("Searching for a UPnP/NAT-PMP device...");
_ = await ApiManager.OpenPorts(); _ = await ApiManager.OpenPorts();
@@ -52,7 +60,10 @@ internal static class Program
ConsoleExt.WriteLine($"The private port is: {ApiConfiguration.PrivatePort}", ConsoleColor.Green); ConsoleExt.WriteLine($"The private port is: {ApiConfiguration.PrivatePort}", ConsoleColor.Green);
Console.WriteLine("Starting TCP listener..."); Console.WriteLine("Starting TCP listener...");
apiManager.StartTcpListener(); if (!apiManager.StartTcpListener())
{
_ = Console.ReadLine();
}
Console.WriteLine("Starting broadcast listener..."); Console.WriteLine("Starting broadcast listener...");
apiManager.StartBroadcastListener(); apiManager.StartBroadcastListener();
@@ -74,9 +85,6 @@ internal static class Program
Console.WriteLine($"{activeHostsCount} active host(s)."); Console.WriteLine($"{activeHostsCount} active host(s).");
ConsoleExt.WriteLine("Ready", ConsoleColor.Green); ConsoleExt.WriteLine("Ready", ConsoleColor.Green);
inputHandler.ReadInput();
ApiManager.ClosePorts();
} }
private static void ApiManager_OnNotificationMessageRecived(object? sender, NotificationMessageEventArgs e) private static void ApiManager_OnNotificationMessageRecived(object? sender, NotificationMessageEventArgs e)
@@ -90,7 +98,7 @@ internal static class Program
} }
} }
private static void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) private static void Close()
{ {
ApiManager.ClosePorts(); ApiManager.ClosePorts();
apiManager.HostsManager.SaveHosts(); apiManager.HostsManager.SaveHosts();
@@ -152,7 +152,7 @@ public class DownloadCommands
if (!Directory.Exists(directoryPath)) if (!Directory.Exists(directoryPath))
{ {
Directory.CreateDirectory(directoryPath); _ = Directory.CreateDirectory(directoryPath);
} }
using FileStream? fileStream = new FileStream(filePath, FileMode.Create); using FileStream? fileStream = new FileStream(filePath, FileMode.Create);
@@ -72,7 +72,7 @@ public class FileCommands
string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles"); string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles");
if (!Directory.Exists(directoryPath)) if (!Directory.Exists(directoryPath))
{ {
Directory.CreateDirectory(directoryPath); _ = Directory.CreateDirectory(directoryPath);
} }
hash = hash.Trim().ToLower(); hash = hash.Trim().ToLower();
@@ -111,7 +111,7 @@ public class FileCommands
string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles"); string directoryPath = Path.Combine(ApiConfiguration.BasePath, "GeneratedFiles");
if (!Directory.Exists(directoryPath)) if (!Directory.Exists(directoryPath))
{ {
Directory.CreateDirectory(directoryPath); _ = Directory.CreateDirectory(directoryPath);
} }
hash = hash.Trim().ToLower(); hash = hash.Trim().ToLower();
@@ -19,8 +19,13 @@ public class HostCommands
public void Discover(string _) public void Discover(string _)
{ {
ApiManager.SendNotificationMessageNewLine("Running local discovery routine...", NotificationMessageType.Info); ApiManager.SendNotificationMessageNewLine("Running local discovery routine...", NotificationMessageType.Info);
int hostsCountBefore = hostsManager.Count;
BroadcastClient.Send(ApiConfiguration.BroadcastPort, ApiConfiguration.PrivatePort.ToString()); BroadcastClient.Send(ApiConfiguration.BroadcastPort, ApiConfiguration.PrivatePort.ToString());
Thread.Sleep(3000); Thread.Sleep(3000);
ApiManager.SendNotificationMessageNewLine($"Found {hostsManager.Count - hostsCountBefore} host(s)", NotificationMessageType.Info);
} }
public void CheckActiveHosts(string _) public void CheckActiveHosts(string _)
@@ -72,7 +77,7 @@ public class HostCommands
string portInput = parts[1]; string portInput = parts[1];
_ = int.TryParse(portInput, out int port); _ = int.TryParse(portInput, out int port);
if (port < 1000 || port >= 6000) if (port is < 1000 or >= 6000)
{ {
ApiManager.SendNotificationMessageNewLine("Invalid port number!", NotificationMessageType.Error); ApiManager.SendNotificationMessageNewLine("Invalid port number!", NotificationMessageType.Error);
return; return;
@@ -112,7 +117,7 @@ public class HostCommands
_ = int.TryParse(portInput, out int port); _ = int.TryParse(portInput, out int port);
if (port < 1000 || port >= 6000) if (port is < 1000 or >= 6000)
{ {
ApiManager.SendNotificationMessageNewLine("Invalid port number!", NotificationMessageType.Error); ApiManager.SendNotificationMessageNewLine("Invalid port number!", NotificationMessageType.Error);
return; return;
@@ -1,6 +1,7 @@
using System.Reflection; using System.Reflection;
namespace HyperbolicDownloaderApi.Managment; namespace HyperbolicDownloaderApi.Managment;
public static class ApiConfiguration public static class ApiConfiguration
{ {
public const int BroadcastPort = 2155; public const int BroadcastPort = 2155;
@@ -9,5 +10,4 @@ public static class ApiConfiguration
public static string BasePath { get; } = Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) ?? string.Empty; 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 HostsFilePath { get; } = Path.Combine(BasePath, "Hosts.json");
public static string FilesInfoPath { get; } = Path.Combine(BasePath, "Files.json"); public static string FilesInfoPath { get; } = Path.Combine(BasePath, "Files.json");
}
}
@@ -35,10 +35,10 @@ public class ApiManager
if (device is not null) if (device is not null)
{ {
ipAddress = (device.GetExternalIPAsync()).GetAwaiter().GetResult()?.ToString(); ipAddress = device.GetExternalIPAsync().GetAwaiter().GetResult()?.ToString();
} }
if (ipAddress is null || ipAddress == "0.0.0.0") if (ipAddress is null or "0.0.0.0")
{ {
ipAddress = NetworkUtilities.GetIP4Adress()?.ToString(); ipAddress = NetworkUtilities.GetIP4Adress()?.ToString();
port = ApiConfiguration.PrivatePort; port = ApiConfiguration.PrivatePort;
@@ -115,7 +115,7 @@ public class ApiManager
broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived; broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived;
} }
public void StartTcpListener() public bool StartTcpListener()
{ {
try try
{ {
@@ -128,30 +128,35 @@ public class ApiManager
catch (SocketException ex) catch (SocketException ex)
{ {
SendNotificationMessageNewLine($"An error occurred while starting the TCP listener! Error message: {ex.Message}", NotificationMessageType.Error); // net stop hens && net start hns SendNotificationMessageNewLine($"An error occurred while starting the TCP listener! Error message: {ex.Message}", NotificationMessageType.Error); // net stop hens && net start hns
Console.ReadKey(); return false;
} }
return true;
} }
private async void BroadcastClient_OnBroadcastRecived(object? sender, BroadcastRecivedEventArgs recivedEventArgs) private async void BroadcastClient_OnBroadcastRecived(object? sender, BroadcastRecivedEventArgs recivedEventArgs)
{ {
Debug.WriteLine($"Received broadcast \"{recivedEventArgs.Message}\" from {recivedEventArgs.IPEndPoint.Address}"); IPAddress remoteIpAddress = recivedEventArgs.IPEndPoint.Address;
Debug.WriteLine($"Received broadcast \"{recivedEventArgs.Message}\" from {remoteIpAddress}");
List<NetworkSocket> hostsToSend = HostsManager.ToList(); List<NetworkSocket> hostsToSend = HostsManager.ToList();
NetworkSocket? localSocket = GetLocalSocket(); NetworkSocket? localSocket = GetLocalSocket();
if (localSocket is null) if (localSocket is null || remoteIpAddress.Equals(PublicIpAddress) || remoteIpAddress.Equals(NetworkUtilities.GetIP4Adress()))
{ {
Debug.WriteLine("Invalid broadcast!");
return; return;
} }
hostsToSend.RemoveAll(x => x.IPAddress == recivedEventArgs.IPEndPoint.Address.ToString()); _ = hostsToSend.RemoveAll(x => x.IPAddress == remoteIpAddress.ToString());
hostsToSend.Add(localSocket); hostsToSend.Add(localSocket);
bool success = int.TryParse(recivedEventArgs.Message, out int remotePort); bool success = int.TryParse(recivedEventArgs.Message, out int remotePort);
if (success) if (success)
{ {
HostsManager.Add(new NetworkSocket(recivedEventArgs.IPEndPoint.Address.ToString(), remotePort, DateTime.Now)); HostsManager.Add(new NetworkSocket(remoteIpAddress.ToString(), remotePort, DateTime.Now));
try try
{ {
await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend); await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend);
@@ -180,7 +185,7 @@ public class ApiManager
return; return;
} }
hostsToSend.RemoveAll(x => x.IPAddress == recivedEventArgs.IpAddress.ToString()); _ = hostsToSend.RemoveAll(x => x.IPAddress == recivedEventArgs.IpAddress.ToString());
hostsToSend.Add(localSocket); hostsToSend.Add(localSocket);
if (recivedEventArgs.Data.Port != 0) if (recivedEventArgs.Data.Port != 0)
@@ -43,7 +43,7 @@ internal class BroadcastClient
byte[] sendbuf = Encoding.ASCII.GetBytes(message); byte[] sendbuf = Encoding.ASCII.GetBytes(message);
IPEndPoint ep = new IPEndPoint(broadcast, port); IPEndPoint ep = new IPEndPoint(broadcast, port);
socket.SendTo(sendbuf, ep); _ = socket.SendTo(sendbuf, ep);
} }
public void StartListening(int port) public void StartListening(int port)
@@ -58,7 +58,7 @@ internal class BroadcastClient
udpListener = new UdpClient(port); udpListener = new UdpClient(port);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port); IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);
Task.Run(() => _ = Task.Run(() =>
{ {
while (IsListening) while (IsListening)
{ {
@@ -1,14 +1,13 @@
namespace HyperbolicDownloaderApi namespace HyperbolicDownloaderApi.Networking;
{
internal class DataContainer
{
public string EventName { get; set; }
public string JsonData { get; set; }
public DataContainer(string eventName, string jsonData) internal class DataContainer
{ {
JsonData = jsonData; public string EventName { get; set; }
EventName = eventName; public string JsonData { get; set; }
}
public DataContainer(string eventName, string jsonData)
{
JsonData = jsonData;
EventName = eventName;
} }
} }
@@ -1,10 +1,9 @@
using HyperbolicDownloaderApi.Managment; using HyperbolicDownloaderApi.Managment;
using HyperbolicDownloaderApi.Networking;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text.Json; using System.Text.Json;
namespace HyperbolicDownloaderApi; namespace HyperbolicDownloaderApi.Networking;
public class HostsManager public class HostsManager
{ {
@@ -15,10 +14,7 @@ public class HostsManager
{ {
foreach (NetworkSocket host in hosts) foreach (NetworkSocket host in hosts)
{ {
if (!Contains(host)) Add(host);
{
this.hosts.Add(host);
}
} }
SaveHosts(); SaveHosts();
@@ -37,7 +33,7 @@ public class HostsManager
{ {
if (DateTime.Now - host.LastActive >= new TimeSpan(24, 0, 0) || forceRemove) 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.IPAddress == host.IPAddress && x.Port == host.Port);
} }
SaveHosts(); SaveHosts();
} }
@@ -58,7 +54,7 @@ public class HostsManager
try try
{ {
tcpClient.ConnectAsync(host.IPAddress, host.Port).Wait(500); _ = tcpClient.ConnectAsync(host.IPAddress, host.Port).Wait(500);
Console.CursorLeft = 0; Console.CursorLeft = 0;
if (tcpClient.Connected) if (tcpClient.Connected)
{ {
@@ -88,7 +84,7 @@ public class HostsManager
foreach (NetworkSocket host in hostsToRemove) foreach (NetworkSocket host in hostsToRemove)
{ {
hosts.Remove(host); _ = hosts.Remove(host);
} }
SaveHosts(); SaveHosts();
@@ -3,32 +3,31 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
namespace HyperbolicDownloaderApi namespace HyperbolicDownloaderApi.Networking;
internal class MessageRecivedEventArgs<T> : EventArgs
{ {
internal class MessageRecivedEventArgs<T> : EventArgs private readonly NetworkStream networkStream;
public MessageRecivedEventArgs(NetworkStream networkStream, IPAddress ipAddress, T data)
{ {
private readonly NetworkStream networkStream; this.networkStream = networkStream;
Data = data;
IpAddress = ipAddress;
}
public MessageRecivedEventArgs(NetworkStream networkStream, IPAddress ipAddress, T data) public T Data { get; set; }
{
this.networkStream = networkStream;
Data = data;
IpAddress = ipAddress;
}
public T Data { get; set; } public IPAddress IpAddress { get; set; }
public IPAddress IpAddress { get; set; } public async Task SendResponseAsync(object response)
{
byte[] bytesToSend = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(response));
await networkStream.WriteAsync(bytesToSend);
}
public async Task SendResponseAsync(object response) public void SendResponse(object response)
{ {
byte[] bytesToSend = Encoding.ASCII.GetBytes(JsonSerializer.Serialize(response)); SendResponseAsync(response).GetAwaiter().GetResult();
await networkStream.WriteAsync(bytesToSend);
}
public void SendResponse(object response)
{
SendResponseAsync(response).GetAwaiter().GetResult();
}
} }
} }
@@ -6,205 +6,200 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
namespace HyperbolicDownloaderApi.Networking namespace HyperbolicDownloaderApi.Networking;
internal class NetworkClient
{ {
internal class NetworkClient public bool IsListening { get; private set; } = false;
private TcpListener? tcpListener;
private readonly FilesManager filesManager;
private readonly Dictionary<string, (Type type, Delegate method)> events = new();
public NetworkClient(FilesManager filesManager)
{ {
public bool IsListening { get; private set; } = false; this.filesManager = filesManager;
}
private TcpListener? tcpListener; public static async Task<T?> SendAsync<T>(IPAddress remoteIp, int remotePort, string eventName, object data)
private readonly FilesManager filesManager; {
private readonly Dictionary<string, (Type type, Delegate method)> events = new(); if (remoteIp is null)
public NetworkClient(FilesManager filesManager)
{ {
this.filesManager = filesManager; throw new ArgumentNullException(nameof(remoteIp));
} }
public static async Task<T?> SendAsync<T>(IPAddress remoteIp, int remotePort, string eventName, object data) TcpClient client = new TcpClient();
await client.ConnectAsync(remoteIp, remotePort);
NetworkStream nwStream = client.GetStream();
string stringData = JsonSerializer.Serialize(new DataContainer(eventName, JsonSerializer.Serialize(data)));
byte[] bytesToSend = Encoding.ASCII.GetBytes(stringData);
await nwStream.WriteAsync(bytesToSend);
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = await nwStream.ReadAsync(bytesToRead.AsMemory(0, client.ReceiveBufferSize));
string response = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
client.Close();
if (string.IsNullOrWhiteSpace(response))
{ {
if (remoteIp is null) return default;
}
else
{
return JsonSerializer.Deserialize<T>(response);
}
}
public static async Task SendAsync(IPAddress remoteIp, int remotePort, string eventName, object data)
{
if (remoteIp is null)
{
throw new ArgumentNullException(nameof(remoteIp));
}
TcpClient client = new TcpClient();
await client.ConnectAsync(remoteIp, remotePort);
NetworkStream nwStream = client.GetStream();
string stringData = JsonSerializer.Serialize(new DataContainer(eventName, JsonSerializer.Serialize(data)));
byte[] bytesToSend = Encoding.ASCII.GetBytes(stringData);
await nwStream.WriteAsync(bytesToSend);
client.Close();
}
public static T? Send<T>(IPAddress remoteIp, int remotePort, string eventName, object data)
{
return SendAsync<T>(remoteIp, remotePort, eventName, data).GetAwaiter().GetResult();
}
public static void Send(IPAddress remoteIp, int remotePort, string eventName, object data)
{
SendAsync(remoteIp, remotePort, eventName, data).GetAwaiter().GetResult();
}
public void StartListening(int port)
{
if (IsListening)
{
throw new InvalidOperationException("Already listening!");
}
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
IsListening = true;
_ = Task.Run(async () =>
{
while (IsListening)
{ {
throw new ArgumentNullException(nameof(remoteIp)); try
{
TcpClient client = tcpListener.AcceptTcpClient();
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = await nwStream.ReadAsync(buffer.AsMemory(0, client.ReceiveBufferSize));
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
if (dataReceived.StartsWith("Download"))
{
_ = Upload(client, dataReceived[8..]);
continue;
}
if (string.IsNullOrWhiteSpace(dataReceived))
{
client.Close();
continue;
}
DataContainer? dataContainer = JsonSerializer.Deserialize<DataContainer>(dataReceived);
if (dataContainer is not null && events.ContainsKey(dataContainer.EventName))
{
(Type type, Delegate method) = events[dataContainer.EventName];
Type eventArgsType = typeof(MessageRecivedEventArgs<>).MakeGenericType(type);
object? eventArgs = Activator.CreateInstance(
eventArgsType,
nwStream,
(client.Client.RemoteEndPoint as IPEndPoint)?.Address,
JsonSerializer.Deserialize(dataContainer.JsonData, type));
_ = (method?.DynamicInvoke(this, eventArgs));
}
client.Close();
}
catch (SocketException ex)
{
if (ex.SocketErrorCode != SocketError.Interrupted)
{
throw;
}
}
} }
tcpListener.Stop();
});
}
TcpClient client = new TcpClient(); private async Task Upload(TcpClient client, string hash)
{
await client.ConnectAsync(remoteIp, remotePort); try
{
byte[] bytesToSend;
hash = hash.Trim();
NetworkStream nwStream = client.GetStream(); NetworkStream nwStream = client.GetStream();
client.SendBufferSize = 64000;
string stringData = JsonSerializer.Serialize(new DataContainer(eventName, JsonSerializer.Serialize(data))); if (filesManager.TryGet(hash, out PrivateHyperFileInfo? hyperFileInfo) && File.Exists(hyperFileInfo?.FilePath))
byte[] bytesToSend = Encoding.ASCII.GetBytes(stringData);
await nwStream.WriteAsync(bytesToSend);
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = await nwStream.ReadAsync(bytesToRead.AsMemory(0, client.ReceiveBufferSize));
string response = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
client.Close();
if (string.IsNullOrWhiteSpace(response))
{ {
return default; 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 else
{ {
return JsonSerializer.Deserialize<T>(response); bytesToSend = Encoding.ASCII.GetBytes("File not found!");
await nwStream.WriteAsync(bytesToSend);
} }
} }
catch (Exception ex)
public static async Task SendAsync(IPAddress remoteIp, int remotePort, string eventName, object data) {
Debug.WriteLine(ex);
}
finally
{ {
if (remoteIp is null)
{
throw new ArgumentNullException(nameof(remoteIp));
}
TcpClient client = new TcpClient();
await client.ConnectAsync(remoteIp, remotePort);
NetworkStream nwStream = client.GetStream();
string stringData = JsonSerializer.Serialize(new DataContainer(eventName, JsonSerializer.Serialize(data)));
byte[] bytesToSend = Encoding.ASCII.GetBytes(stringData);
await nwStream.WriteAsync(bytesToSend);
client.Close(); client.Close();
} }
}
public static T? Send<T>(IPAddress remoteIp, int remotePort, string eventName, object data) public void StopListening()
{ {
return SendAsync<T>(remoteIp, remotePort, eventName, data).GetAwaiter().GetResult(); tcpListener?.Stop();
} IsListening = false;
}
public static void Send(IPAddress remoteIp, int remotePort, string eventName, object data) public void ListenTo<T>(string eventName, EventHandler<MessageRecivedEventArgs<T>> eventHandler)
{ {
SendAsync(remoteIp, remotePort, eventName, data).GetAwaiter().GetResult(); events.Add(eventName, (typeof(T), eventHandler));
}
public void StartListening(int port)
{
if (IsListening)
{
throw new InvalidOperationException("Already listening!");
}
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
IsListening = true;
Task.Run(async () =>
{
while (IsListening)
{
try
{
TcpClient client = tcpListener.AcceptTcpClient();
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = await nwStream.ReadAsync(buffer.AsMemory(0, client.ReceiveBufferSize));
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
if (dataReceived.StartsWith("Download"))
{
_ = Upload(client, dataReceived[8..]);
continue;
}
if (string.IsNullOrWhiteSpace(dataReceived))
{
client.Close();
continue;
}
DataContainer? dataContainer = JsonSerializer.Deserialize<DataContainer>(dataReceived);
if (dataContainer is not null && events.ContainsKey(dataContainer.EventName))
{
(Type type, Delegate method) = events[dataContainer.EventName];
Type eventArgsType = typeof(MessageRecivedEventArgs<>).MakeGenericType(type);
object? eventArgs = Activator.CreateInstance(
eventArgsType,
nwStream,
(client.Client.RemoteEndPoint as IPEndPoint)?.Address,
JsonSerializer.Deserialize(dataContainer.JsonData, type));
method?.DynamicInvoke(this, eventArgs);
}
client.Close();
}
catch (SocketException ex)
{
if (ex.SocketErrorCode != SocketError.Interrupted)
{
throw;
}
}
}
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))
{
if (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();
}
}
public void StopListening()
{
tcpListener?.Stop();
IsListening = false;
}
public void ListenTo<T>(string eventName, EventHandler<MessageRecivedEventArgs<T>> eventHandler)
{
events.Add(eventName, (typeof(T), eventHandler));
}
} }
} }
+4 -11
View File
@@ -25,7 +25,6 @@ You can generate `.hyper` files with your client using the [generate](https://gi
These files contain the hash value of the actual file and the hosts that should have the requested file. These files contain the hash value of the actual file and the hosts that should have the requested file.
You can use the [get from](https://github.com/Stone-Red-Code/HyperbolicDownloader#getfrom) command to retrieve the file or if you are using Windows you can right-click the `.hyper` file, select `open with` and select the HyperbolicDownloader executable. You can use the [get from](https://github.com/Stone-Red-Code/HyperbolicDownloader#getfrom) command to retrieve the file or if you are using Windows you can right-click the `.hyper` file, select `open with` and select the HyperbolicDownloader executable.
## Disclaimer ## Disclaimer
Keep in mind that all network traffic is not encrypted. So, do not send sensitive information with HyperbolicDownloader. Keep in mind that all network traffic is not encrypted. So, do not send sensitive information with HyperbolicDownloader.
@@ -41,31 +40,26 @@ Since none of the files are stored anywhere centralized, the quality of the file
**Description:** Exits the application.\ **Description:** Exits the application.\
**Parameter:** `none` **Parameter:** `none`
### `clear` | `cls` ### `clear` | `cls`
**Description:** Clears the console.\ **Description:** Clears the console.\
**Parameter:** `none` **Parameter:** `none`
### `info` | `inf` ### `info` | `inf`
**Description:** Displays the private and public IP address.\ **Description:** Displays the private and public IP address.\
**Parameter:** `none` **Parameter:** `none`
### `discover` | `disc` ### `discover` | `disc`
**Description:** Tries to find other active hosts on the local network.\ **Description:** Tries to find other active hosts on the local network.\
**parameter:** `none` **parameter:** `none`
### `check` | `status` ### `check` | `status`
**Description:** Checks the status of known hosts.\ **Description:** Checks the status of known hosts.\
**parameter:** `none` **parameter:** `none`
### `list` | `ls` ### `list` | `ls`
**Description:** Lists all files\ **Description:** Lists all files\
@@ -73,15 +67,14 @@ Since none of the files are stored anywhere centralized, the quality of the file
#### `<list> files` #### `<list> files`
**Description:** Lists all files\ **Description:** Lists all files.\
**parameter:** `none` **parameter:** `none`
#### `<list> hosts` #### `<list> hosts`
**description:** lists all hosts **description:** Lists all hosts.\
**parameter:** `none` **parameter:** `none`
### `add` ### `add`
**Description:** Adds a file to the tracking list.\ **Description:** Adds a file to the tracking list.\
@@ -97,7 +90,6 @@ Since none of the files are stored anywhere centralized, the quality of the file
**Description:** Adds a host to the list of known hosts.\ **Description:** Adds a host to the list of known hosts.\
**parameter:** `<IpAddress:port>` **parameter:** `<IpAddress:port>`
### `remove` | `rm` ### `remove` | `rm`
**Description:** Removes a file from the tracking list.\ **Description:** Removes a file from the tracking list.\
@@ -113,19 +105,20 @@ Since none of the files are stored anywhere centralized, the quality of the file
**Description:** Removes a host from the list of known hosts.\ **Description:** Removes a host from the list of known hosts.\
**parameter:** `<IpAddress:Port>` **parameter:** `<IpAddress:Port>`
### `get` ### `get`
**Description:** Attempts to retrieve a file from another host using a hash.\ **Description:** Attempts to retrieve a file from another host using a hash.\
**parameter:** `<FileHash>` **parameter:** `<FileHash>`
<a name="#getfrom"></a> <a name="#getfrom"></a>
#### `<get> from` #### `<get> from`
**Description:** Attempts to retrieve a file from another host using a .hyper file.\ **Description:** Attempts to retrieve a file from another host using a .hyper file.\
**Parameter:** `<FilePathToHyperFile>` **Parameter:** `<FilePathToHyperFile>`
<a name="#generate"></a> <a name="#generate"></a>
### `generate` | `gen` ### `generate` | `gen`
**Description:** Generates a .hyper file from a file hash.\ **Description:** Generates a .hyper file from a file hash.\