mirror of
https://github.com/Stone-Red-Code/HyperbolicDownloader.git
synced 2026-09-04 00:56:09 +02:00
- Add command system
- Add basic file sharing
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace HyperbolicDownloader.FileProcessing;
|
namespace HyperbolicDownloader.FileProcessing;
|
||||||
|
|
||||||
internal class FileCompressor
|
internal static class FileCompressor
|
||||||
{
|
{
|
||||||
private static void CompressFile(string inputFilePath, string compressedFilePath)
|
public static void CompressFile(string inputFilePath, string compressedFilePath)
|
||||||
{
|
{
|
||||||
using FileStream originalFileStream = File.Open(inputFilePath, FileMode.Open);
|
using FileStream originalFileStream = File.Open(inputFilePath, FileMode.Open);
|
||||||
using FileStream compressedFileStream = File.Create(compressedFilePath);
|
using FileStream compressedFileStream = File.Create(compressedFilePath);
|
||||||
@@ -12,11 +12,25 @@ internal class FileCompressor
|
|||||||
originalFileStream.CopyTo(compressor);
|
originalFileStream.CopyTo(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DecompressFile(string compressedFilePath, string outputFilePath)
|
public static void DecompressFile(string compressedFilePath, string outputFilePath)
|
||||||
{
|
{
|
||||||
using FileStream compressedFileStream = File.Open(compressedFilePath, FileMode.Open);
|
using FileStream compressedFileStream = File.Open(compressedFilePath, FileMode.Open);
|
||||||
using FileStream outputFileStream = File.Create(outputFilePath);
|
using FileStream outputFileStream = File.Create(outputFilePath);
|
||||||
using GZipStream? decompressor = new GZipStream(compressedFileStream, CompressionMode.Decompress);
|
using GZipStream? decompressor = new GZipStream(compressedFileStream, CompressionMode.Decompress);
|
||||||
decompressor.CopyTo(outputFileStream);
|
decompressor.CopyTo(outputFileStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<byte[]> ReadChunks(string path, int chunkSize)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[chunkSize];
|
||||||
|
int bytesRead;
|
||||||
|
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
|
||||||
|
using (BufferedStream bs = new BufferedStream(fs))
|
||||||
|
{
|
||||||
|
while ((bytesRead = bs.Read(buffer, 0, chunkSize)) != 0)
|
||||||
|
{
|
||||||
|
yield return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,18 @@ internal class FileValidator
|
|||||||
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CalculateHash(string filePath)
|
||||||
|
{
|
||||||
|
return CalculateHashAsync(filePath).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<bool> ValidateHashAsync(string filePath, string hash)
|
public static async Task<bool> ValidateHashAsync(string filePath, string hash)
|
||||||
{
|
{
|
||||||
return await CalculateHashAsync(filePath) == hash;
|
return await CalculateHashAsync(filePath) == hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ValidateHash(string filePath, string hash)
|
||||||
|
{
|
||||||
|
return CalculateHash(filePath) == hash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace HyperbolicDownloader.FileProcessing;
|
||||||
|
|
||||||
|
internal class FilesManager
|
||||||
|
{
|
||||||
|
private readonly List<HyperFileInfo> files = new List<HyperFileInfo>();
|
||||||
|
|
||||||
|
public bool TryAdd(string filePath, out HyperFileInfo? fileInfo, out string? errorMessage)
|
||||||
|
{
|
||||||
|
string fullPath = Path.GetFullPath(filePath);
|
||||||
|
|
||||||
|
if (!File.Exists(fullPath))
|
||||||
|
{
|
||||||
|
fileInfo = null;
|
||||||
|
errorMessage = "Invalid file path!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string hash = FileValidator.CalculateHash(filePath);
|
||||||
|
|
||||||
|
if (Contains(hash))
|
||||||
|
{
|
||||||
|
fileInfo = null;
|
||||||
|
errorMessage = "File already tracked!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo = new HyperFileInfo(hash, fullPath);
|
||||||
|
|
||||||
|
files.Add(fileInfo);
|
||||||
|
|
||||||
|
SaveFiles();
|
||||||
|
|
||||||
|
errorMessage = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRange(IEnumerable<HyperFileInfo> fileInfos)
|
||||||
|
{
|
||||||
|
foreach (HyperFileInfo fileInfo in fileInfos)
|
||||||
|
{
|
||||||
|
if (File.Exists(fileInfo.FilePath) && !Contains(fileInfo.Hash))
|
||||||
|
{
|
||||||
|
files.Add(fileInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet(string hash, out HyperFileInfo? fileInfo)
|
||||||
|
{
|
||||||
|
if (Contains(hash))
|
||||||
|
{
|
||||||
|
fileInfo = files.First(x => x.Hash == hash);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileInfo = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemove(string hash)
|
||||||
|
{
|
||||||
|
files.RemoveAll(f => f.Hash == hash);
|
||||||
|
|
||||||
|
SaveFiles();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string? hash)
|
||||||
|
{
|
||||||
|
return files.Any(f => f.Hash == hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HyperFileInfo> ToList()
|
||||||
|
{
|
||||||
|
return files.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveFiles()
|
||||||
|
{
|
||||||
|
File.WriteAllText(Program.FilesInfoPath, JsonSerializer.Serialize(files));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Console.Commander.NET" Version="1.0.0" />
|
||||||
<PackageReference Include="Open.NAT" Version="2.1.0" />
|
<PackageReference Include="Open.NAT" Version="2.1.0" />
|
||||||
<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>
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
using System.Net;
|
using HyperbolicDownloader.FileProcessing;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace HyperbolicDownloader
|
namespace HyperbolicDownloader.Networking
|
||||||
{
|
{
|
||||||
internal class NetworkClient
|
internal class NetworkClient
|
||||||
{
|
{
|
||||||
public bool IsListening { get; private set; } = false;
|
public bool IsListening { get; private set; } = false;
|
||||||
|
|
||||||
private TcpListener? tcpListener;
|
private TcpListener? tcpListener;
|
||||||
|
private FilesManager filesManager;
|
||||||
private readonly Dictionary<string, (Type type, Delegate method)> events = new();
|
private readonly Dictionary<string, (Type type, Delegate method)> events = new();
|
||||||
|
|
||||||
public NetworkClient()
|
public NetworkClient(FilesManager filesManager)
|
||||||
{
|
{
|
||||||
|
this.filesManager = filesManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<T?> SendAsync<T>(IPAddress remoteIp, int remotePort, string eventName, object data)
|
public static async Task<T?> SendAsync<T>(IPAddress remoteIp, int remotePort, string eventName, object data)
|
||||||
@@ -93,22 +97,28 @@ namespace HyperbolicDownloader
|
|||||||
tcpListener.Start();
|
tcpListener.Start();
|
||||||
IsListening = true;
|
IsListening = true;
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
while (IsListening)
|
while (IsListening)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using TcpClient client = tcpListener.AcceptTcpClient();
|
TcpClient client = tcpListener.AcceptTcpClient();
|
||||||
NetworkStream nwStream = client.GetStream();
|
NetworkStream nwStream = client.GetStream();
|
||||||
byte[] buffer = new byte[client.ReceiveBufferSize];
|
byte[] buffer = new byte[client.ReceiveBufferSize];
|
||||||
|
|
||||||
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
|
int bytesRead = await nwStream.ReadAsync(buffer, 0, client.ReceiveBufferSize);
|
||||||
|
|
||||||
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||||
|
|
||||||
|
if (dataReceived.StartsWith("Download"))
|
||||||
|
{
|
||||||
|
_ = Upload(client, dataReceived[8..]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (string.IsNullOrWhiteSpace(dataReceived))
|
if (string.IsNullOrWhiteSpace(dataReceived))
|
||||||
{
|
{
|
||||||
|
client.Close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +138,8 @@ namespace HyperbolicDownloader
|
|||||||
|
|
||||||
method?.DynamicInvoke(this, eventArgs);
|
method?.DynamicInvoke(this, eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.Close();
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
@@ -141,6 +153,48 @@ namespace HyperbolicDownloader
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Upload(TcpClient client, string hash)
|
||||||
|
{
|
||||||
|
byte[] bytesToSend;
|
||||||
|
hash = hash.Trim();
|
||||||
|
NetworkStream nwStream = client.GetStream();
|
||||||
|
|
||||||
|
if (filesManager.TryGet(hash, out HyperFileInfo? 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//string compressedFilePath = $"{hash + DateTime.Now.Millisecond}.temp";
|
||||||
|
|
||||||
|
//FileCompressor.CompressFile(hyperFileInfo.FilePath, compressedFilePath);
|
||||||
|
|
||||||
|
FileInfo compressedFileInfo = new FileInfo(hyperFileInfo.FilePath);
|
||||||
|
|
||||||
|
bytesToSend = Encoding.ASCII.GetBytes(compressedFileInfo.Length.ToString());
|
||||||
|
await nwStream.WriteAsync(bytesToSend);
|
||||||
|
|
||||||
|
foreach (byte[]? chunk in FileCompressor.ReadChunks(hyperFileInfo.FilePath, 1000))
|
||||||
|
{
|
||||||
|
if (chunk is not null)
|
||||||
|
{
|
||||||
|
await nwStream.WriteAsync(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// File.Delete(compressedFilePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytesToSend = Encoding.ASCII.GetBytes("File not found!");
|
||||||
|
await nwStream.WriteAsync(bytesToSend);
|
||||||
|
}
|
||||||
|
client.Close();
|
||||||
|
}
|
||||||
|
|
||||||
public void StopListening()
|
public void StopListening()
|
||||||
{
|
{
|
||||||
tcpListener?.Stop();
|
tcpListener?.Stop();
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
internal class NetworkSocket
|
internal class NetworkSocket
|
||||||
{
|
{
|
||||||
|
public string IPAddress { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
|
||||||
public NetworkSocket(string ipAddress, int port)
|
public NetworkSocket(string ipAddress, int port)
|
||||||
{
|
{
|
||||||
IPAddress = ipAddress;
|
IPAddress = ipAddress;
|
||||||
Port = port;
|
Port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string IPAddress { get; set; }
|
|
||||||
public int Port { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
|
using HyperbolicDownloader.FileProcessing;
|
||||||
using HyperbolicDownloader.Networking;
|
using HyperbolicDownloader.Networking;
|
||||||
|
using HyperbolicDownloader.UserInterface;
|
||||||
|
|
||||||
using Open.Nat;
|
using Open.Nat;
|
||||||
|
|
||||||
@@ -15,15 +17,16 @@ namespace HyperbolicDownloader;
|
|||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
private const int BroadcastPort = 2155;
|
private const int BroadcastPort = 2155;
|
||||||
|
|
||||||
public const string HostsFilePath = "Hosts.json";
|
public const string HostsFilePath = "Hosts.json";
|
||||||
|
public const string FilesInfoPath = "Files.json";
|
||||||
|
|
||||||
private static int publicPort;
|
private static int publicPort;
|
||||||
private static readonly int privatePort = 3055;
|
private static readonly int privatePort = 3055;
|
||||||
private static NatDevice? device;
|
private static NatDevice? device;
|
||||||
private static Mapping? portMapping;
|
private static Mapping? portMapping;
|
||||||
private static readonly HostsManager hosts = new();
|
private static readonly HostsManager hostsManager = new();
|
||||||
private static readonly NetworkClient networkClient = new();
|
private static readonly FilesManager filesManager = new FilesManager();
|
||||||
|
private static readonly NetworkClient networkClient = new(filesManager);
|
||||||
private static readonly Random random = new Random();
|
private static readonly Random random = new Random();
|
||||||
|
|
||||||
private static async Task Main()
|
private static async Task Main()
|
||||||
@@ -33,7 +36,13 @@ internal class Program
|
|||||||
if (File.Exists(HostsFilePath))
|
if (File.Exists(HostsFilePath))
|
||||||
{
|
{
|
||||||
string hostsJson = await File.ReadAllTextAsync(HostsFilePath);
|
string hostsJson = await File.ReadAllTextAsync(HostsFilePath);
|
||||||
hosts.AddRange(JsonSerializer.Deserialize<List<NetworkSocket>>(hostsJson) ?? new());
|
hostsManager.AddRange(JsonSerializer.Deserialize<List<NetworkSocket>>(hostsJson) ?? new());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(FilesInfoPath))
|
||||||
|
{
|
||||||
|
string filesJson = await File.ReadAllTextAsync(FilesInfoPath);
|
||||||
|
filesManager.AddRange(JsonSerializer.Deserialize<List<HyperFileInfo>>(filesJson) ?? new());
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Searching for a UPnP/NAT-PMP device...");
|
Console.WriteLine("Searching for a UPnP/NAT-PMP device...");
|
||||||
@@ -48,6 +57,8 @@ internal class Program
|
|||||||
{
|
{
|
||||||
networkClient.ListenTo<NetworkSocket>("GetHostsList", GetHostList);
|
networkClient.ListenTo<NetworkSocket>("GetHostsList", GetHostList);
|
||||||
networkClient.ListenTo<List<NetworkSocket>>("DiscoverAnswer", DiscoverAnswer);
|
networkClient.ListenTo<List<NetworkSocket>>("DiscoverAnswer", DiscoverAnswer);
|
||||||
|
networkClient.ListenTo<string>("Message", ReciveMessage);
|
||||||
|
networkClient.ListenTo<string>("HasFile", HasFile);
|
||||||
networkClient.StartListening(privatePort);
|
networkClient.StartListening(privatePort);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
@@ -62,31 +73,33 @@ internal class Program
|
|||||||
broadcastClient.Send(BroadcastPort, privatePort.ToString());
|
broadcastClient.Send(BroadcastPort, privatePort.ToString());
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
|
|
||||||
if (hosts.Count > 0)
|
if (hostsManager.Count > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Checking if hosts are active...");
|
Console.WriteLine("Checking if hosts are active...");
|
||||||
hosts.RemoveInactiveHosts();
|
hostsManager.RemoveInactiveHosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hosts.Count == 0)
|
if (hostsManager.Count == 0)
|
||||||
{
|
{
|
||||||
hosts.AddRange(await Setup.ConfigureHost());
|
hostsManager.AddRange(await UserInterface.Setup.ConfigureHost());
|
||||||
Console.WriteLine("Checking if hosts are active...");
|
Console.WriteLine("Checking if hosts are active...");
|
||||||
hosts.RemoveInactiveHosts();
|
hostsManager.RemoveInactiveHosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"{hosts.Count} active host(s).");
|
Console.WriteLine($"{hostsManager.Count} active host(s).");
|
||||||
Console.WriteLine("Starting broadcast listener...");
|
Console.WriteLine("Starting broadcast listener...");
|
||||||
broadcastClient.StartListening(BroadcastPort);
|
broadcastClient.StartListening(BroadcastPort);
|
||||||
broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived;
|
broadcastClient.OnBroadcastRecived += BroadcastClient_OnBroadcastRecived;
|
||||||
ConsoleExt.WriteLine("Done", ConsoleColor.Green);
|
ConsoleExt.WriteLine("Done", ConsoleColor.Green);
|
||||||
await Task.Delay(-1);
|
|
||||||
|
new InputHandler(hostsManager, filesManager).ReadInput();
|
||||||
|
ClosePorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async void BroadcastClient_OnBroadcastRecived(object? sender, BroadcastRecivedEventArgs recivedEventArgs)
|
private static async void BroadcastClient_OnBroadcastRecived(object? sender, BroadcastRecivedEventArgs recivedEventArgs)
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Received broadcast \"{recivedEventArgs.Message}\" from {recivedEventArgs.IPEndPoint.Address}");
|
Debug.WriteLine($"Received broadcast \"{recivedEventArgs.Message}\" from {recivedEventArgs.IPEndPoint.Address}");
|
||||||
List<NetworkSocket> hostsToSend = hosts.ToList();
|
List<NetworkSocket> hostsToSend = hostsManager.ToList();
|
||||||
|
|
||||||
NetworkSocket? localSocket = GetLocalSocket();
|
NetworkSocket? localSocket = GetLocalSocket();
|
||||||
|
|
||||||
@@ -102,7 +115,7 @@ internal class Program
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
hosts.Add(new NetworkSocket(recivedEventArgs.IPEndPoint.Address.ToString(), remotePort));
|
hostsManager.Add(new NetworkSocket(recivedEventArgs.IPEndPoint.Address.ToString(), remotePort));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend);
|
await NetworkClient.SendAsync(recivedEventArgs.IPEndPoint.Address, remotePort, "DiscoverAnswer", hostsToSend);
|
||||||
@@ -117,12 +130,17 @@ internal class Program
|
|||||||
private static void DiscoverAnswer(object? sender, MessageRecivedEventArgs<List<NetworkSocket>> recivedEventArgs)
|
private static void DiscoverAnswer(object? sender, MessageRecivedEventArgs<List<NetworkSocket>> recivedEventArgs)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Received answer from {recivedEventArgs.IpAddress}. Returned {recivedEventArgs.Data.Count} host(s).");
|
Console.WriteLine($"Received answer from {recivedEventArgs.IpAddress}. Returned {recivedEventArgs.Data.Count} host(s).");
|
||||||
hosts.AddRange(recivedEventArgs.Data);
|
hostsManager.AddRange(recivedEventArgs.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReciveMessage(object? sender, MessageRecivedEventArgs<string> recivedEventArgs)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Received \"{recivedEventArgs.Data}\" from {recivedEventArgs.IpAddress}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async void GetHostList(object? sender, MessageRecivedEventArgs<NetworkSocket> recivedEventArgs)
|
private static async void GetHostList(object? sender, MessageRecivedEventArgs<NetworkSocket> recivedEventArgs)
|
||||||
{
|
{
|
||||||
List<NetworkSocket> hostsToSend = hosts.ToList();
|
List<NetworkSocket> hostsToSend = hostsManager.ToList();
|
||||||
|
|
||||||
NetworkSocket? localSocket = GetLocalSocket();
|
NetworkSocket? localSocket = GetLocalSocket();
|
||||||
|
|
||||||
@@ -136,12 +154,17 @@ internal class Program
|
|||||||
|
|
||||||
if (recivedEventArgs.Data.Port != 0)
|
if (recivedEventArgs.Data.Port != 0)
|
||||||
{
|
{
|
||||||
hosts.Add(recivedEventArgs.Data);
|
hostsManager.Add(recivedEventArgs.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
await recivedEventArgs.SendResponseAsync(hostsToSend);
|
await recivedEventArgs.SendResponseAsync(hostsToSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async void HasFile(object? sender, MessageRecivedEventArgs<string> recivedEventArgs)
|
||||||
|
{
|
||||||
|
await recivedEventArgs.SendResponseAsync(filesManager.Contains(recivedEventArgs.Data));
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<bool> OpenPorts()
|
public static async Task<bool> OpenPorts()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
using Commander_Net;
|
||||||
|
|
||||||
|
using HyperbolicDownloader.FileProcessing;
|
||||||
|
using HyperbolicDownloader.Networking;
|
||||||
|
|
||||||
|
using Stone_Red_Utilities.ConsoleExtentions;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
this.hostsManager = hostsManager;
|
||||||
|
commander.Register((_) => Console.Clear(), "clear");
|
||||||
|
commander.Register(Exit, "exit");
|
||||||
|
commander.Register(GetFile, "get");
|
||||||
|
commander.Register(AddFile, "add");
|
||||||
|
commander.Register(ListFiles, "list");
|
||||||
|
this.filesManager = filesManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadInput()
|
||||||
|
{
|
||||||
|
while (!exit)
|
||||||
|
{
|
||||||
|
Console.Write("> ");
|
||||||
|
string input = Console.ReadLine() ?? string.Empty;
|
||||||
|
|
||||||
|
if (!commander.Execute(input))
|
||||||
|
{
|
||||||
|
ConsoleExt.WriteLine("Unknown command!", ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetFile(string hash)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(hash))
|
||||||
|
{
|
||||||
|
Console.WriteLine("No hash value specified!");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (NetworkSocket host in hostsManager.ToList())
|
||||||
|
{
|
||||||
|
bool validIpAdress = IPAddress.TryParse(host.IPAddress, out IPAddress? ipAddress);
|
||||||
|
|
||||||
|
if (validIpAdress)
|
||||||
|
{
|
||||||
|
ConsoleExt.Write($"{host.IPAddress}:{host.Port} > ???", ConsoleColor.DarkYellow);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.CursorLeft = 0;
|
||||||
|
|
||||||
|
Task<bool> sendTask = NetworkClient.SendAsync<bool>(ipAddress!, host.Port, "HasFile", hash);
|
||||||
|
|
||||||
|
_ = sendTask.Wait(1000);
|
||||||
|
|
||||||
|
if (sendTask.Result)
|
||||||
|
{
|
||||||
|
ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Has the requested file", ConsoleColor.Green);
|
||||||
|
Console.WriteLine("Requesting file...");
|
||||||
|
|
||||||
|
TcpClient tcpClient = new TcpClient();
|
||||||
|
tcpClient.Connect(ipAddress!, host.Port);
|
||||||
|
|
||||||
|
NetworkStream nwStream = tcpClient.GetStream();
|
||||||
|
byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
|
||||||
|
byte[] reciveBuffer = new byte[1000];
|
||||||
|
|
||||||
|
byte[] bytesToSend = Encoding.ASCII.GetBytes($"Download {hash}");
|
||||||
|
nwStream.Write(bytesToSend);
|
||||||
|
int bytesRead = nwStream.Read(buffer, 0, tcpClient.ReceiveBufferSize);
|
||||||
|
|
||||||
|
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
|
||||||
|
|
||||||
|
if (int.TryParse(dataReceived, out int fileSize)) //If received data is not a size an error occurred
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Starting download...");
|
||||||
|
|
||||||
|
int totalBytesRead = 0;
|
||||||
|
|
||||||
|
using FileStream? fileStream = new FileStream($"{hash}.txt", FileMode.Create);
|
||||||
|
|
||||||
|
while (totalBytesRead < fileSize)
|
||||||
|
{
|
||||||
|
bytesRead = nwStream.Read(reciveBuffer, 0, reciveBuffer.Length);
|
||||||
|
|
||||||
|
bytesRead = Math.Min(reciveBuffer.Length, fileSize - totalBytesRead);
|
||||||
|
|
||||||
|
fileStream.Write(reciveBuffer, 0, bytesRead);
|
||||||
|
totalBytesRead += bytesRead;
|
||||||
|
|
||||||
|
Console.CursorLeft = 0;
|
||||||
|
Console.Out.WriteAsync($"Downloading: {Math.Ceiling(100d / fileSize * totalBytesRead)}% {totalBytesRead}/{fileSize}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStream.Close();
|
||||||
|
//FileCompressor.DecompressFile($"{hash}.gz", $"result.txt");
|
||||||
|
Console.WriteLine();
|
||||||
|
ConsoleExt.WriteLine("Done", ConsoleColor.Green);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConsoleExt.WriteLine(dataReceived, ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Does not have the requested file", ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException)
|
||||||
|
{
|
||||||
|
Console.CursorLeft = 0;
|
||||||
|
ConsoleExt.WriteLine($"{host.IPAddress}:{host.Port} > Inactive", ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hostsManager.Remove(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFile(string args)
|
||||||
|
{
|
||||||
|
if (filesManager.TryAdd(args, out HyperFileInfo? 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 ListFiles(string _)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
foreach (HyperFileInfo fileInfo in filesManager.ToList())
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
Console.WriteLine($"{index}) {fileInfo.FilePath}");
|
||||||
|
Console.WriteLine($"Hash: {fileInfo.Hash}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Exit(string _)
|
||||||
|
{
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using Stone_Red_Utilities.ConsoleExtentions;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace HyperbolicDownloader;
|
namespace HyperbolicDownloader.UserInterface;
|
||||||
|
|
||||||
internal static class Setup
|
internal static class Setup
|
||||||
{
|
{
|
||||||
Reference in New Issue
Block a user