From dfa437a639b95712222020a2f60bd27e2e61b724 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Sat, 8 Aug 2020 23:44:51 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=AE=8C=E5=96=84hls=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E8=AF=BB=E5=8F=96=202.=E6=B7=BB=E5=8A=A0http=E5=8D=8F?= =?UTF-8?q?=E8=B0=83=E5=99=A8=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JT1078.Gateway.TestNormalHosting.csproj | 6 +++ .../wwwroot/demo/demo.m3u8 | 1 + .../wwwroot/demo/demo.ts | 1 + .../Configurations/JT1078Configuration.cs | 4 ++ .../Extensions/JT1078HttpContextExtensions.cs | 5 ++ .../JT1078CoordinatorHttpClient.cs | 29 ++++++++++ src/JT1078.Gateway/JT1078HttpServer.cs | 54 ++++++++++++++++++- 7 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.m3u8 create mode 100644 src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.ts create mode 100644 src/JT1078.Gateway/JT1078CoordinatorHttpClient.cs diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj index cde7db3..a88eb40 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/JT1078.Gateway.TestNormalHosting.csproj @@ -20,5 +20,11 @@ Always + + Always + + + Always + diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.m3u8 b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.m3u8 new file mode 100644 index 0000000..de79cca --- /dev/null +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.m3u8 @@ -0,0 +1 @@ +m3u8 demo \ No newline at end of file diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.ts b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.ts new file mode 100644 index 0000000..1660b9e --- /dev/null +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/demo/demo.ts @@ -0,0 +1 @@ +ts demo \ No newline at end of file diff --git a/src/JT1078.Gateway/Configurations/JT1078Configuration.cs b/src/JT1078.Gateway/Configurations/JT1078Configuration.cs index 2793fcd..57f582e 100644 --- a/src/JT1078.Gateway/Configurations/JT1078Configuration.cs +++ b/src/JT1078.Gateway/Configurations/JT1078Configuration.cs @@ -29,6 +29,10 @@ namespace JT1078.Gateway.Configurations /// Udp 60s检查一次 /// public int UdpReceiveTimeoutCheckTimeSeconds { get; set; } = 60; + /// + /// Hls根目录 + /// + public string HlsRootDirectory { get; set; } = "wwwroot"; public JT1078Configuration Value => this; } diff --git a/src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs b/src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs index 2253eb2..95f6374 100644 --- a/src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs +++ b/src/JT1078.Gateway/Extensions/JT1078HttpContextExtensions.cs @@ -19,6 +19,7 @@ namespace JT1078.Gateway.Extensions context.Response.ContentLength64 = b.Length; var output = context.Response.OutputStream; await output.WriteAsync(b, 0, b.Length); + context.Response.OutputStream.Close(); context.Response.Close(); } @@ -30,6 +31,7 @@ namespace JT1078.Gateway.Extensions context.Response.ContentLength64 = b.Length; var output = context.Response.OutputStream; await output.WriteAsync(b, 0, b.Length); + context.Response.OutputStream.Close(); context.Response.Close(); } @@ -37,6 +39,7 @@ namespace JT1078.Gateway.Extensions { context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.KeepAlive = false; + context.Response.OutputStream.Close(); context.Response.Close(); } @@ -48,6 +51,7 @@ namespace JT1078.Gateway.Extensions context.Response.ContentLength64 = b.Length; var output = context.Response.OutputStream; await output.WriteAsync(b, 0, b.Length); + context.Response.OutputStream.Close(); context.Response.Close(); } @@ -72,6 +76,7 @@ namespace JT1078.Gateway.Extensions context.Context.Response.ContentLength64 = b.Length; var output = context.Context.Response.OutputStream; await output.WriteAsync(b, 0, b.Length); + context.Context.Response.OutputStream.Close(); context.Context.Response.Close(); } diff --git a/src/JT1078.Gateway/JT1078CoordinatorHttpClient.cs b/src/JT1078.Gateway/JT1078CoordinatorHttpClient.cs new file mode 100644 index 0000000..93bd045 --- /dev/null +++ b/src/JT1078.Gateway/JT1078CoordinatorHttpClient.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; + +namespace JT1078.Gateway +{ + /// + /// 协调器客户端 + /// + public class JT1078CoordinatorHttpClient + { + private HttpClient httpClient; + + public JT1078CoordinatorHttpClient(HttpClient httpClient) + { + this.httpClient = httpClient; + } + + /// + /// 发送心跳至协调器中 + /// + /// + public async void Heartbeat(string content) + { + await httpClient.PostAsync("/heartbeat", new StringContent(content)); + } + } +} diff --git a/src/JT1078.Gateway/JT1078HttpServer.cs b/src/JT1078.Gateway/JT1078HttpServer.cs index 3b827f5..bc9c078 100644 --- a/src/JT1078.Gateway/JT1078HttpServer.cs +++ b/src/JT1078.Gateway/JT1078HttpServer.cs @@ -88,13 +88,65 @@ namespace JT1078.Gateway return Task.CompletedTask; } + private const string m3u8Mime = "application/x-mpegURL"; + private const string tsMime = "video/MP2T"; + private async ValueTask ProcessRequestAsync(HttpListenerContext context, IPrincipal principal) { if(context.Request.RawUrl.StartsWith("/favicon.ico")) { context.Http404(); + return; + } + var queryStringIndex = context.Request.RawUrl.IndexOf("?"); + string url = ""; + if (queryStringIndex > 0) + { + url = context.Request.RawUrl.Substring(1, queryStringIndex-1); + } + else + { + url = context.Request.RawUrl; + } + if (url.EndsWith(".m3u8") || url.EndsWith(".ts")) + { + string filename = Path.GetFileName(url); + string filepath = Path.Combine(Configuration.HlsRootDirectory, Path.GetFileNameWithoutExtension(filename), filename); + if (!File.Exists(filepath)) + { + context.Http404(); + return; + } + try + { + using (FileStream sr = new FileStream(filepath, FileMode.Open)) + { + context.Response.ContentLength64 = sr.Length; + await sr.CopyToAsync(context.Response.OutputStream); + } + string ext = Path.GetExtension(filename); + if (ext == ".m3u8") + { + context.Response.ContentType = m3u8Mime; + } + else if (ext == ".ts") + { + context.Response.ContentType = tsMime; + } + context.Response.StatusCode = (int)HttpStatusCode.OK; + } + catch (Exception ex) + { + Logger.LogError(ex, $"{context.Request.RawUrl}"); + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + } + finally + { + context.Response.OutputStream.Close(); + context.Response.Close(); + } + return; } - //todo:.m3u8 .ts if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}");