From eda1b7da7b75cba263980278239fc2ca32015266 Mon Sep 17 00:00:00 2001 From: root <295172551@qq.com> Date: Sun, 22 Jun 2025 05:28:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9E=E6=97=B6=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=9F=A5=E7=9C=8B=E5=8A=9F=E8=83=BD=EF=BC=9A1.=20?= =?UTF-8?q?=E5=9C=A8WebSocketManagerService=E4=B8=AD=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=AD=E5=A4=AE=E6=97=A5=E5=BF=97=E7=BC=93=E5=AD=98=E9=98=9F?= =?UTF-8?q?=E5=88=97=202.=20=E5=88=9B=E5=BB=BASSE=E7=AB=AF=E7=82=B9?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=AE=9E=E6=97=B6=E6=8E=A8=E9=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97=203.=20=E6=96=B0=E5=A2=9ELogs.cshtml=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=EF=BC=8C=E6=94=AF=E6=8C=81=E8=99=9A=E6=8B=9F=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E5=92=8C=E5=8F=8C=E6=A0=8F=E5=B8=83=E5=B1=80=204.=20?= =?UTF-8?q?=E5=9C=A8=E5=AF=BC=E8=88=AA=E6=A0=8F=E6=B7=BB=E5=8A=A0=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E6=97=A5=E5=BF=97=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LTEMvcApp/Controllers/HomeController.cs | 8 + LTEMvcApp/Controllers/WebSocketController.cs | 42 ++- LTEMvcApp/Services/WebSocketManagerService.cs | 25 ++ LTEMvcApp/Views/Home/ClientMessages.cshtml | 162 ++++++----- LTEMvcApp/Views/Home/Logs.cshtml | 268 ++++++++++++++++++ LTEMvcApp/Views/Shared/_Layout.cshtml | 8 +- 6 files changed, 440 insertions(+), 73 deletions(-) create mode 100644 LTEMvcApp/Views/Home/Logs.cshtml diff --git a/LTEMvcApp/Controllers/HomeController.cs b/LTEMvcApp/Controllers/HomeController.cs index ab795fb..6a64d53 100644 --- a/LTEMvcApp/Controllers/HomeController.cs +++ b/LTEMvcApp/Controllers/HomeController.cs @@ -172,4 +172,12 @@ public class HomeController : Controller ViewBag.ClientName = clientName; return View(); } + + /// + /// 返回 Logs.cshtml 视图 + /// + public IActionResult Logs() + { + return View(); + } } diff --git a/LTEMvcApp/Controllers/WebSocketController.cs b/LTEMvcApp/Controllers/WebSocketController.cs index 0831e64..065bb04 100644 --- a/LTEMvcApp/Controllers/WebSocketController.cs +++ b/LTEMvcApp/Controllers/WebSocketController.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json.Linq; using Microsoft.Extensions.Logging; using System.Threading.Tasks; using System.Linq; +using System.Threading; namespace LTEMvcApp.Controllers { @@ -365,12 +366,51 @@ namespace LTEMvcApp.Controllers [HttpPost("test-client/stop")] public ActionResult StopTestClient() { + _logger.LogInformation("API 请求: 停止测试客户端"); var success = _webSocketManager.StopTestClient(); if (success) - return Ok(new { message = "测试客户端已停止" }); + return Ok(new { message = "测试客户端停止成功" }); else return BadRequest("停止测试客户端失败"); } + + /// + /// 使用 Server-Sent Events (SSE) 实时推送全局日志 + /// + [HttpGet("logs/stream")] + public async Task StreamLogs(CancellationToken cancellationToken) + { + Response.ContentType = "text/event-stream"; + Response.Headers.Append("Cache-Control", "no-cache"); + Response.Headers.Append("Connection", "keep-alive"); + + int logIndex = 0; + + // 首先,一次性推送所有已缓存的日志 + var initialLogs = _webSocketManager.GetLogCache().ToList(); + if (initialLogs.Any()) + { + await SendSseEvent("history", new { logs = initialLogs }); + await Response.Body.FlushAsync(cancellationToken); + logIndex = initialLogs.Count; + } + + while (!cancellationToken.IsCancellationRequested) + { + var logCache = _webSocketManager.GetLogCache(); + if (logCache.Count() > logIndex) + { + var newLogs = logCache.Skip(logIndex).ToList(); + if (newLogs.Any()) + { + await SendSseEvent("new_logs", new { logs = newLogs }); + await Response.Body.FlushAsync(cancellationToken); + logIndex = logCache.Count(); + } + } + await Task.Delay(250, cancellationToken); + } + } } /// diff --git a/LTEMvcApp/Services/WebSocketManagerService.cs b/LTEMvcApp/Services/WebSocketManagerService.cs index 5dde8fa..a45a1bc 100644 --- a/LTEMvcApp/Services/WebSocketManagerService.cs +++ b/LTEMvcApp/Services/WebSocketManagerService.cs @@ -23,6 +23,8 @@ namespace LTEMvcApp.Services private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; private ClientConfig _testClientConfig; + private const int LogCacheSize = 10000; // 服务器最多缓存10000条最新日志 + private readonly ConcurrentQueue _logCache = new ConcurrentQueue(); #endregion @@ -438,6 +440,16 @@ namespace LTEMvcApp.Services return GetClientInstance(_testClientConfig.Name); } + /// + /// 获取当前缓存的日志 + /// + public IEnumerable GetLogCache() => _logCache; + + /// + /// 获取当前缓存的日志总数 + /// + public int GetLogCacheCount() => _logCache.Count; + #endregion #region 私有方法 @@ -466,6 +478,19 @@ namespace LTEMvcApp.Services private void OnLogsReceived(string clientName, List logs) { _logger.LogInformation($"客户端 {clientName} 收到日志: {logs.Count} 条"); + + // 将新日志存入中央缓存 + foreach (var log in logs) + { + _logCache.Enqueue(log); + } + + // 维持缓存大小 + while (_logCache.Count > LogCacheSize) + { + _logCache.TryDequeue(out _); + } + LogsReceived?.Invoke(this, (clientName, logs)); } diff --git a/LTEMvcApp/Views/Home/ClientMessages.cshtml b/LTEMvcApp/Views/Home/ClientMessages.cshtml index 49e1e14..efbfbb5 100644 --- a/LTEMvcApp/Views/Home/ClientMessages.cshtml +++ b/LTEMvcApp/Views/Home/ClientMessages.cshtml @@ -26,11 +26,9 @@ 0 -
-
-
- 正在建立与服务器的连接... -
+
+
+
正在连接...
@@ -43,11 +41,9 @@ 0
-
-
-
- 正在建立与服务器的连接... -
+
+
+
正在连接...
@@ -60,92 +56,112 @@
@section Scripts { + + + + + + + + - - - - } \ No newline at end of file diff --git a/LTEMvcApp/Views/Home/Logs.cshtml b/LTEMvcApp/Views/Home/Logs.cshtml new file mode 100644 index 0000000..0fad7ea --- /dev/null +++ b/LTEMvcApp/Views/Home/Logs.cshtml @@ -0,0 +1,268 @@ +@{ + ViewData["Title"] = "实时日志"; +} + + +
+
+
+
+
+
+ 总日志条数: 0 +
+
+
+
+

请从左侧选择一条日志以查看详情

+
+
+

日志详情

+ +
+
+
+ +@section Scripts { + + + +} \ No newline at end of file diff --git a/LTEMvcApp/Views/Shared/_Layout.cshtml b/LTEMvcApp/Views/Shared/_Layout.cshtml index c887031..28300a1 100644 --- a/LTEMvcApp/Views/Shared/_Layout.cshtml +++ b/LTEMvcApp/Views/Shared/_Layout.cshtml @@ -21,7 +21,13 @@