diff --git a/CSharp-OpenBMCLAPI/Modules/Cluster.cs b/CSharp-OpenBMCLAPI/Modules/Cluster.cs index 5f2c5f5..248d7f6 100644 --- a/CSharp-OpenBMCLAPI/Modules/Cluster.cs +++ b/CSharp-OpenBMCLAPI/Modules/Cluster.cs @@ -156,7 +156,7 @@ private void InitializeService() { //var builder = WebApplication.CreateBuilder(); X509Certificate2 cert = LoadAndConvertCert(); - SimpleWebServer server = new(ClusterRequiredData.Config.PORT, cert);//cert); + SimpleWebServer server = new(ClusterRequiredData.Config.PORT, cert, this);//cert); server.Start(); /* builder.WebHost.UseKestrel(options => diff --git a/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs b/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs index edfcead..0c3ec1b 100644 --- a/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs +++ b/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs @@ -68,8 +68,8 @@ public static async Task Measure(HttpContext context, Cluster cluster) public static async Task DownloadHash(HttpContext context, Cluster cluster) { FileAccessInfo fai = default; - var pairs = Utils.GetQueryStrings(context.Request.QueryString); - string? hash = context.Request.Path.Split('/').LastOrDefault(); + var pairs = Utils.GetQueryStrings(context.Request.Path.Split('?').Last()); + string? hash = context.Request.Path.Split('/').LastOrDefault()?.Split('?').First(); string? s = pairs.GetValueOrDefault("s"); string? e = pairs.GetValueOrDefault("e"); @@ -79,10 +79,14 @@ public static async Task DownloadHash(HttpContext context, Clust { try { - if (context.Request.Header.Select(f => f.Key).Contains("Range")) + if (context.Request.Header.ContainsKey("Range")) { (long from, long to) = ToRangeByte(context.Request.Header["Range"].Split("=").Last().Split("-")); - //TODO: Range 请求 + context.Response.Header["Content-Length"] = (to - from).ToString(); + using Stream file = cluster.storage.ReadFileStream(Utils.HashToFileName(hash)); + file.Seek(from, SeekOrigin.Begin); + file.CopyTo(context.Response.Stream); + context.Response.StatusCode = 206; } else { @@ -98,6 +102,7 @@ public static async Task DownloadHash(HttpContext context, Clust else { context.Response.StatusCode = 403; + context.Response.Header.Remove("Content-Length"); await context.Response.WriteAsync($"Access to \"{context.Request.Path}\" has been blocked due to your request timeout or invalidity."); } return fai; @@ -107,7 +112,7 @@ private static (long from, long to) ToRangeByte(string[]? rangeHeader) { int from, to; if (string.IsNullOrWhiteSpace(rangeHeader?.FirstOrDefault())) - from = -1; + from = 0; else from = Convert.ToInt32(rangeHeader?.FirstOrDefault()); if (string.IsNullOrWhiteSpace(rangeHeader?.LastOrDefault())) diff --git a/CSharp-OpenBMCLAPI/Modules/Utils.cs b/CSharp-OpenBMCLAPI/Modules/Utils.cs index e0452ee..5ec2f4d 100644 --- a/CSharp-OpenBMCLAPI/Modules/Utils.cs +++ b/CSharp-OpenBMCLAPI/Modules/Utils.cs @@ -202,7 +202,7 @@ static long ToDecimal(string hex) public static Dictionary GetQueryStrings(string? query) { Dictionary pairs = new(); - query?[1..].Split('&').ForEach(s => + query?.Split('&').ForEach(s => { var pair = s.Split('='); pairs[pair[0]] = pair[1]; diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs index 06194e1..e465984 100644 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs +++ b/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs @@ -11,6 +11,6 @@ public class HttpContext { public required Request Request { get; set; } public required Response Response { get; set; } - public required IPEndPoint RemoteIPAddress { get; set; } + public required EndPoint RemoteIPAddress { get; set; } } } diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs index 6aabfe0..0fd5af9 100644 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs +++ b/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs @@ -15,10 +15,11 @@ public class Response public async Task Call(Client client, Request request, bool needCopy = true) { - Header.Set("Content-Length", Stream.Length); + if (!Header.ContainsKey("Content-Length")) Header.Set("Content-Length", Stream.Length); Header.Set("Server", "CSharp-SaltWood"); string responseHeader = $"HTTP/1.1 {StatusCode} {GetStatusMsg(StatusCode)}\r\n{Header}\r\n"; await client.Write(responseHeader.Encode()); + Stream.Position = 0; if (needCopy) Stream.CopyTo(client.Stream); } diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs index 76253d0..1e8db57 100644 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs +++ b/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs @@ -11,6 +11,7 @@ using TeraIO.Runnable; using System.Text.RegularExpressions; using TeraIO.Extension; +using System.Diagnostics; namespace CSharpOpenBMCLAPI.Modules.WebServer { @@ -18,12 +19,15 @@ public class SimpleWebServer : RunnableBase { private int Port = 0; // TCP 随机端口 private readonly X509Certificate2? _certificate; // SSL证书 + private Cluster cluster; private readonly int bufferSize = 8192; - public SimpleWebServer(int port, X509Certificate2? certificate) + public SimpleWebServer(int port, X509Certificate2? certificate, Cluster cluster) { Port = port; _certificate = certificate; + _certificate = null; + this.cluster = cluster; } protected override int Run(string[] args) @@ -52,33 +56,36 @@ protected async Task AsyncRun() while (true) { TcpClient tcpClient = await listener.AcceptTcpClientAsync(); - _ = Task.Run(() => + _ = Task.Run(() => HandleRequest(tcpClient)); + } + } + + protected void HandleRequest(TcpClient tcpClient) + { + try + { + Stream stream = tcpClient.GetStream(); + if (_certificate != null) + { + SslStream sslStream = new SslStream(stream, false, ValidateServerCertificate, null); + sslStream.AuthenticateAsServer(this._certificate, false, false); + stream = sslStream; + } + if (Handle(new Client(tcpClient, stream)).Result && tcpClient.Connected) { - try - { - Stream stream = tcpClient.GetStream(); - if (_certificate != null) - { - SslStream sslStream = new SslStream(stream, true, ValidateServerCertificate, null); - sslStream.AuthenticateAsServer(this._certificate, false, false); - stream = sslStream; - } - if (Handle(new Client(tcpClient, stream)).Result && tcpClient.Connected) - { - stream.Close(); - tcpClient.Close(); - } - } - catch (Exception ex) - { - Logger.Instance.LogError(ex.ExceptionToDetail()); - } - }); + stream.Close(); + tcpClient.Close(); + } + } + catch (Exception ex) + { + Logger.Instance.LogError(ex.ExceptionToDetail()); } } protected async Task Handle(Client client) // 返回值代表是否关闭连接? { + byte[] buffer = await client.Read(this.bufferSize); Request request = new Request(client, buffer); Response response = new Response(); @@ -88,9 +95,18 @@ protected async Task Handle(Client client) // 返回值代表是否关闭 response.Header.Add("Content-Type", "application/octet-stream"); - var filePath = Path.Combine(ClusterRequiredData.Config.cacheDirectory, Utils.HashToFileName(match.Groups[1].Value)); - FileInfo fileInfo = new FileInfo(filePath); - response.Stream = File.OpenRead(filePath); + HttpContext context = new HttpContext() { Request = request, RemoteIPAddress = client.TcpClient.Client.RemoteEndPoint!, Response = response }; + + try + { + var count = match.Groups.Count; + if (count == 0) return true; + await HttpServiceProvider.DownloadHash(context, cluster); + } + catch + { + Debugger.Break(); + } await response.Call(client, request); // 可以多次调用Response diff --git a/CSharp-OpenBMCLAPI/Program.cs b/CSharp-OpenBMCLAPI/Program.cs index 8d13f98..f35fc65 100644 --- a/CSharp-OpenBMCLAPI/Program.cs +++ b/CSharp-OpenBMCLAPI/Program.cs @@ -96,45 +96,53 @@ protected Config GetConfig() protected override int Run(string[] args) { - ClusterRequiredData.Config = GetConfig(); - LoadPlugins(); - PluginManager.Instance.TriggerEvent(this, ProgramEventType.ProgramStarted); + try + { + ClusterRequiredData.Config = GetConfig(); + LoadPlugins(); + PluginManager.Instance.TriggerEvent(this, ProgramEventType.ProgramStarted); - int returns = 0; + int returns = 0; - if (File.Exists("totals.bson")) - { - DataStatistician t = Utils.BsonDeserializeObject(File.ReadAllBytes("totals.bson")).ThrowIfNull(); - ClusterRequiredData.DataStatistician = t; - } - else - { - const string bsonFilePath = "totals.bson"; - using (var file = File.Create(bsonFilePath)) + if (File.Exists("totals.bson")) { - file.Write(Utils.BsonSerializeObject(ClusterRequiredData.DataStatistician)); + DataStatistician t = Utils.BsonDeserializeObject(File.ReadAllBytes("totals.bson")).ThrowIfNull(); + ClusterRequiredData.DataStatistician = t; + } + else + { + const string bsonFilePath = "totals.bson"; + using (var file = File.Create(bsonFilePath)) + { + file.Write(Utils.BsonSerializeObject(ClusterRequiredData.DataStatistician)); + } } - } - // 从 .env.json 读取密钥然后 FetchToken - ClusterInfo info = JsonConvert.DeserializeObject(File.ReadAllTextAsync(".env.json").Result); - ClusterRequiredData requiredData = new(info); - Logger.Instance.LogSystem($"Cluster id: {info.ClusterID}"); - TokenManager token = new TokenManager(info); - token.FetchToken().Wait(); + // 从 .env.json 读取密钥然后 FetchToken + ClusterInfo info = JsonConvert.DeserializeObject(File.ReadAllTextAsync(".env.json").Result); + ClusterRequiredData requiredData = new(info); + Logger.Instance.LogSystem($"Cluster id: {info.ClusterID}"); + TokenManager token = new TokenManager(info); + token.FetchToken().Wait(); - requiredData.Token = token; + requiredData.Token = token; - Cluster cluster = new(requiredData); - Logger.Instance.LogSystem($"成功创建 Cluster 实例"); - AppDomain.CurrentDomain.ProcessExit += (sender, e) => Utils.ExitCluster(cluster).Wait(); - Console.CancelKeyPress += (sender, e) => Utils.ExitCluster(cluster).Wait(); + Cluster cluster = new(requiredData); + Logger.Instance.LogSystem($"成功创建 Cluster 实例"); + AppDomain.CurrentDomain.ProcessExit += (sender, e) => Utils.ExitCluster(cluster).Wait(); + Console.CancelKeyPress += (sender, e) => Utils.ExitCluster(cluster).Wait(); - cluster.Start(); - cluster.WaitForStop(); + cluster.Start(); + cluster.WaitForStop(); - requiredData.PluginManager.TriggerEvent(this, ProgramEventType.ProgramStopped); - return returns; + requiredData.PluginManager.TriggerEvent(this, ProgramEventType.ProgramStopped); + return returns; + } + catch (Exception ex) + { + Console.WriteLine(ex.ExceptionToDetail()); + return -1; + } } } }