using Microsoft.AspNetCore.Mvc; using LTEMvcApp.Models; using LTEMvcApp.Services; using Newtonsoft.Json.Linq; using Microsoft.Extensions.Logging; using System.Threading.Tasks; using System.Linq; using System.Threading; using System.IO; using System.Text; namespace LTEMvcApp.Controllers { /// /// WebSocket控制器 - 提供LTE客户端WebSocket管理API /// [ApiController] [Route("api/[controller]")] public class WebSocketController : ControllerBase { private readonly WebSocketManagerService _webSocketManager; private readonly ILogger _logger; private readonly string _logsDirectory = "ClientMessageLogs"; public WebSocketController(WebSocketManagerService webSocketManager, ILogger logger) { _webSocketManager = webSocketManager; _logger = logger; // 确保日志目录存在 if (!Directory.Exists(_logsDirectory)) { Directory.CreateDirectory(_logsDirectory); } } /// /// 获取所有客户端状态 /// /// 客户端状态列表 [HttpGet("clients")] public ActionResult> GetClientStates() { _logger.LogInformation("获取所有客户端状态"); var states = _webSocketManager.GetAllClientStates(); return Ok(states); } /// /// 获取客户端配置 /// /// 客户端名称 /// 客户端配置 [HttpGet("clients/{clientName}/config")] public ActionResult GetClientConfig(string clientName) { var config = _webSocketManager.GetClientConfig(clientName); if (config == null) return NotFound($"客户端 '{clientName}' 不存在"); return Ok(config); } /// /// 获取所有客户端配置 /// /// 客户端配置列表 [HttpGet("configs")] public ActionResult> GetAllConfigs() { var configs = _webSocketManager.GetAllClientConfigs(); return Ok(configs); } /// /// 添加客户端配置 /// /// 客户端配置 /// 操作结果 [HttpPost("configs")] public ActionResult AddClientConfig([FromBody] ClientConfig config) { if (string.IsNullOrEmpty(config.Name)) return BadRequest("客户端名称不能为空"); var success = _webSocketManager.AddClientConfig(config); if (success) return Ok(new { message = $"客户端 '{config.Name}' 配置已添加" }); else return BadRequest("添加客户端配置失败"); } /// /// 启动客户端 /// /// 客户端名称 /// 操作结果 [HttpPost("clients/{clientName}/start")] public ActionResult StartClient(string clientName) { _logger.LogInformation($"API请求: 启动客户端 {clientName}"); var success = _webSocketManager.StartClient(clientName); if (success) { _logger.LogInformation($"客户端 {clientName} 启动成功"); return Ok(new { message = $"客户端 '{clientName}' 已启动" }); } else { _logger.LogWarning($"客户端 {clientName} 启动失败"); return BadRequest($"启动客户端 '{clientName}' 失败"); } } /// /// 停止客户端 /// /// 客户端名称 /// 操作结果 [HttpPost("clients/{clientName}/stop")] public ActionResult StopClient(string clientName) { var success = _webSocketManager.StopClient(clientName); if (success) return Ok(new { message = $"客户端 '{clientName}' 已停止" }); else return BadRequest($"停止客户端 '{clientName}' 失败"); } /// /// 播放/暂停客户端 /// /// 客户端名称 /// 操作结果 [HttpPost("clients/{clientName}/playpause")] public ActionResult PlayPauseClient(string clientName) { var success = _webSocketManager.PlayPauseClient(clientName); if (success) return Ok(new { message = $"客户端 '{clientName}' 播放/暂停状态已切换" }); else return BadRequest($"切换客户端 '{clientName}' 播放/暂停状态失败"); } /// /// 重置客户端日志 /// /// 客户端名称 /// 操作结果 [HttpPost("clients/{clientName}/reset-logs")] public ActionResult ResetClientLogs(string clientName) { var success = _webSocketManager.ResetClientLogs(clientName); if (success) return Ok(new { message = $"客户端 '{clientName}' 日志已重置" }); else return BadRequest($"重置客户端 '{clientName}' 日志失败"); } /// /// 获取客户端日志 /// /// 客户端名称 /// 日志数量限制 /// 日志列表 [HttpGet("clients/{clientName}/logs")] public ActionResult?> GetClientLogs(string clientName, [FromQuery] int limit = 100) { var logs = _webSocketManager.GetClientLogs(clientName); if (logs == null) return NotFound($"客户端 '{clientName}' 不存在或未连接"); // 限制返回的日志数量 var limitedLogs = logs.TakeLast(limit).ToList(); return Ok(limitedLogs); } /// /// 设置客户端日志配置 /// /// 客户端名称 /// 请求体 [HttpPost("clients/{clientName}/logs-config")] public ActionResult SetClientLogsConfig(string clientName, [FromBody] ClientLogsConfig request) { var success = _webSocketManager.SetClientLogsConfig(clientName, request); if (success) { return Ok(new { message = "日志配置已更新" }); } else { return NotFound(new { message = $"客户端 '{clientName}' 未找到或更新失败" }); } } /// /// 发送消息到客户端 /// /// 客户端名称 /// 消息内容 /// 操作结果 [HttpPost("clients/{clientName}/send-message")] public ActionResult SendMessage(string clientName, [FromBody] JObject message) { var messageId = _webSocketManager.SendMessageToClient(clientName, message); if (messageId >= 0) return Ok(new { messageId, message = $"消息已发送到客户端 '{clientName}'" }); else return BadRequest($"发送消息到客户端 '{clientName}' 失败"); } /// /// 获取连接统计信息 /// /// 统计信息 [HttpGet("statistics")] public ActionResult GetStatistics() { var stats = _webSocketManager.GetConnectionStatistics(); return Ok(stats); } /// /// 启动所有已配置的客户端 /// /// 操作结果 [HttpPost("start-all")] public ActionResult StartAllClients() { _webSocketManager.StartAllConfiguredClients(); return Ok(new { message = "所有已配置的客户端已启动" }); } /// /// 停止所有客户端 /// /// 操作结果 [HttpPost("stop-all")] public ActionResult StopAllClients() { _webSocketManager.StopAllClients(); return Ok(new { message = "所有客户端已停止" }); } /// /// 移除客户端配置 /// /// 客户端名称 /// 操作结果 [HttpDelete("configs/{clientName}")] public ActionResult RemoveClientConfig(string clientName) { var success = _webSocketManager.RemoveClientConfig(clientName); if (success) return Ok(new { message = $"客户端 '{clientName}' 配置已移除" }); else return BadRequest($"移除客户端 '{clientName}' 配置失败"); } /// /// 使用 Server-Sent Events (SSE) 实时推送客户端消息 /// /// 客户端名称 [HttpGet("clients/{clientName}/messages/stream")] public async Task StreamClientMessages(string clientName) { try { Response.ContentType = "text/event-stream"; Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Connection", "keep-alive"); Response.Headers.Append("Access-Control-Allow-Origin", "*"); var client = _webSocketManager.GetClientInstance(clientName); if (client == null) { // 发送一个错误事件然后关闭 await SendSseEvent("error", new { message = "客户端未连接或不存在", clientName }); return; } // 发送一个连接成功事件 await SendSseEvent("open", new { message = "成功连接到服务器事件流", clientName, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(HttpContext.RequestAborted); int lastSentCount = 0; int lastReceivedCount = 0; var cancellationToken = HttpContext.RequestAborted; // 创建日志文件路径 var sentLogFilePath = Path.Combine(_logsDirectory, $"{clientName}_sent_messages.log"); var receivedLogFilePath = Path.Combine(_logsDirectory, $"{clientName}_received_messages.log"); while (!cancellationToken.IsCancellationRequested) { try { bool hasNewMessages = false; // 检查并高效地发送新的"已发送"消息 var currentSentCount = client.SentMessagesCount; if (currentSentCount > lastSentCount) { var sentMessages = client.SentMessages?.ToList() ?? new List(); if (sentMessages.Count > lastSentCount) { var newMessages = sentMessages.Skip(lastSentCount).ToList(); if (newMessages.Any()) { // 记录发送的消息到日志文件 await LogMessagesToFile(sentLogFilePath, newMessages, "SENT", clientName); await SendSseEvent("update", new { type = "sent", messages = newMessages, totalCount = currentSentCount, newCount = newMessages.Count }); lastSentCount = currentSentCount; hasNewMessages = true; } } } // 检查并高效地发送新的"已接收"消息 var currentReceivedCount = client.ReceivedMessagesCount; if (currentReceivedCount > lastReceivedCount) { var receivedMessages = client.ReceivedMessages?.ToList() ?? new List(); if (receivedMessages.Count > lastReceivedCount) { var newMessages = receivedMessages.Skip(lastReceivedCount).ToList(); if (newMessages.Any()) { // 记录接收的消息到日志文件 await LogMessagesToFile(receivedLogFilePath, newMessages, "RECEIVED", clientName); await SendSseEvent("update", new { type = "received", messages = newMessages, totalCount = currentReceivedCount, newCount = newMessages.Count }); lastReceivedCount = currentReceivedCount; hasNewMessages = true; } } } if (hasNewMessages) { await Response.Body.FlushAsync(cancellationToken); } await Task.Delay(250, cancellationToken); // 每250毫秒检查一次新消息 } catch (OperationCanceledException) { // 正常的取消操作,退出循环 break; } catch (Exception ex) { _logger.LogError(ex, "StreamClientMessages 循环中发生错误,客户端: {ClientName}", clientName); await SendSseEvent("error", new { message = "处理消息流时发生错误", error = ex.Message, clientName, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); // 等待一段时间后继续,避免频繁错误 await Task.Delay(1000, cancellationToken); } } // 发送断开连接事件 await SendSseEvent("disconnected", new { message = "客户端消息流连接已断开", clientName, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); } catch (OperationCanceledException) { _logger.LogInformation("StreamClientMessages 连接被客户端取消,客户端: {ClientName}", clientName); } catch (Exception ex) { _logger.LogError(ex, "StreamClientMessages 方法执行时发生未处理的异常,客户端: {ClientName}", clientName); try { await SendSseEvent("fatal_error", new { message = "服务器内部错误", error = ex.Message, clientName, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(); } catch { // 忽略发送错误事件时的异常 } } } /// /// 将消息记录到日志文件 /// /// 日志文件路径 /// 消息列表 /// 消息类型(SENT/RECEIVED) /// 客户端名称 private async Task LogMessagesToFile(string logFilePath, List messages, string messageType, string clientName) { try { var logBuilder = new StringBuilder(); var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); foreach (var message in messages) { logBuilder.AppendLine($"[{timestamp}] [{clientName}] [{messageType}] {message}"); logBuilder.AppendLine(new string('-', 80)); // 分隔线 } await System.IO.File.AppendAllTextAsync(logFilePath, logBuilder.ToString(), Encoding.UTF8); _logger.LogDebug("已记录 {Count} 条 {MessageType} 消息到文件: {FilePath}", messages.Count, messageType, logFilePath); } catch (Exception ex) { _logger.LogError(ex, "记录消息到文件时发生错误: {FilePath}", logFilePath); } } private async Task SendSseEvent(string eventName, object data) { try { if (string.IsNullOrEmpty(eventName)) { _logger.LogWarning("尝试发送空事件名称的SSE事件"); return; } if (data == null) { _logger.LogWarning("尝试发送空数据的SSE事件: {EventName}", eventName); return; } var json = Newtonsoft.Json.JsonConvert.SerializeObject(data); var eventData = $"event: {eventName}\ndata: {json}\n\n"; _logger.LogDebug("SendSseEvent: 发送事件 {EventName}, 数据长度: {DataLength}, 事件数据长度: {EventDataLength}", eventName, json.Length, eventData.Length); await Response.WriteAsync(eventData); _logger.LogDebug("SendSseEvent: 事件 {EventName} 发送成功", eventName); } catch (Exception ex) { _logger.LogError(ex, "发送SSE事件时发生错误: {EventName}", eventName); // 不重新抛出异常,避免影响整个流 } } /// /// 获取测试客户端配置 /// /// 测试客户端配置 [HttpGet("test-client-config")] public ActionResult GetTestClientConfig() { var testConfig = _webSocketManager.GetTestClientConfig(); return Ok(testConfig); } /// /// 设置测试客户端配置 /// /// 测试客户端配置 /// 操作结果 [HttpPost("test-client-config")] public ActionResult SetTestClientConfig([FromBody] ClientConfig config) { if (string.IsNullOrEmpty(config.Name)) return BadRequest("客户端名称不能为空"); var success = _webSocketManager.SetTestClientConfig(config); if (success) return Ok(new { message = "测试客户端配置已更新" }); else return BadRequest("更新测试客户端配置失败"); } /// /// 启动测试客户端 /// /// 操作结果 [HttpPost("test-client/start")] public ActionResult StartTestClient() { var success = _webSocketManager.StartTestClient(); if (success) return Ok(new { message = "测试客户端已启动" }); else return BadRequest("启动测试客户端失败"); } /// /// 停止测试客户端 /// /// 操作结果 [HttpPost("test-client/stop")] public ActionResult StopTestClient() { _logger.LogInformation("API 请求: 停止测试客户端"); var success = _webSocketManager.StopTestClient(); if (success) return Ok(new { message = "测试客户端停止成功" }); else return BadRequest("停止测试客户端失败"); } /// /// 获取日志缓存统计信息 /// /// 统计信息 [HttpGet("logs/stats")] public ActionResult GetLogCacheStats() { try { var stats = new { totalLogs = _webSocketManager.GetLogCacheCount(), cacheSize = 10000, // LogCacheSize timestamp = DateTime.UtcNow }; return Ok(stats); } catch (Exception ex) { _logger.LogError(ex, "获取日志缓存统计信息时发生错误"); return StatusCode(500, new { message = "获取统计信息失败", error = ex.Message }); } } /// /// 清空全局日志缓存 /// /// 操作结果 [HttpPost("logs/clear")] public ActionResult ClearLogCache() { try { _webSocketManager.ClearLogCache(); return Ok(new { message = "日志缓存已清空" }); } catch (Exception ex) { _logger.LogError(ex, "清空日志缓存时发生错误"); return StatusCode(500, new { message = "清空日志缓存失败", error = ex.Message }); } } /// /// 重置全局日志缓存 /// /// 操作结果 [HttpPost("logs/reset")] public ActionResult ResetLogCache() { try { _webSocketManager.ResetLogCache(); return Ok(new { message = "日志缓存已重置" }); } catch (Exception ex) { _logger.LogError(ex, "重置日志缓存时发生错误"); return StatusCode(500, new { message = "重置日志缓存失败", error = ex.Message }); } } /// /// 添加测试日志数据 /// /// 操作结果 [HttpPost("logs/add-test-data")] public ActionResult AddTestLogData() { try { var testLogs = new List { }; // 手动添加到日志缓存 _webSocketManager.AddLogsToCache(testLogs); return Ok(new { message = $"已添加 {testLogs.Count} 条测试日志" }); } catch (Exception ex) { _logger.LogError(ex, "添加测试日志数据时发生错误"); return StatusCode(500, new { message = "添加测试日志失败", error = ex.Message }); } } /// /// 使用 Server-Sent Events (SSE) 实时推送全局日志 /// [HttpGet("logs/stream")] public async Task StreamLogs(CancellationToken cancellationToken) { try { Response.ContentType = "text/event-stream"; Response.Headers.Append("Cache-Control", "no-cache"); Response.Headers.Append("Connection", "keep-alive"); Response.Headers.Append("Access-Control-Allow-Origin", "*"); // 发送连接成功事件 await SendSseEvent("connected", new { message = "日志流连接已建立", timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); int lastLogCount = 0; var lastLogs = new List(); var lastLogHash = string.Empty; // 添加日志内容哈希值用于比较 // 首先,一次性推送所有已缓存的日志 try { var initialLogs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); _logger.LogInformation("StreamLogs: 获取到初始日志 {Count} 条", initialLogs.Count); if (initialLogs.Any()) { _logger.LogInformation("StreamLogs: 发送历史日志事件,日志数量: {Count}", initialLogs.Count); await SendSseEvent("history", new { logs = initialLogs, totalCount = initialLogs.Count }); await Response.Body.FlushAsync(cancellationToken); lastLogCount = initialLogs.Count; lastLogs = initialLogs.ToList(); // 保存副本用于比较 lastLogHash = CalculateLogsHash(initialLogs); // 计算初始日志哈希值 } else { _logger.LogInformation("StreamLogs: 没有历史日志数据"); } } catch (Exception ex) { _logger.LogError(ex, "获取初始日志时发生错误"); await SendSseEvent("error", new { message = "获取初始日志失败", error = ex.Message }); await Response.Body.FlushAsync(cancellationToken); } while (!cancellationToken.IsCancellationRequested) { try { var currentLogs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); var currentLogHash = CalculateLogsHash(currentLogs); // 检查是否有新日志(通过数量和内容哈希双重检查) bool hasNewLogs = false; List newLogs = new List(); if (currentLogs.Count > lastLogCount) { // 数量增加,计算新增的日志 newLogs = currentLogs.Skip(lastLogCount).ToList(); hasNewLogs = newLogs.Any(); } else if (currentLogs.Count == lastLogCount && currentLogHash != lastLogHash) { // 数量相同但内容变化,可能是日志被替换或更新 // 比较每个日志项,找出变化的日志 newLogs = GetChangedLogs(lastLogs, currentLogs); hasNewLogs = newLogs.Any(); } else if (currentLogs.Count < lastLogCount) { // 日志被清空或重置的情况 _logger.LogInformation("检测到日志缓存被重置,重新同步"); await SendSseEvent("reset", new { message = "日志缓存已重置", totalCount = currentLogs.Count }); await Response.Body.FlushAsync(cancellationToken); lastLogCount = currentLogs.Count; lastLogs = currentLogs.ToList(); lastLogHash = currentLogHash; continue; // 跳过本次循环,等待下次检查 } if (hasNewLogs && newLogs.Any()) { _logger.LogInformation("StreamLogs: 发送新日志事件,新增日志数量: {NewCount}, 总日志数量: {TotalCount}", newLogs.Count, currentLogs.Count); _logger.LogDebug("StreamLogs: 新日志详情 - 第一条: {FirstLog}, 最后一条: {LastLog}", newLogs.FirstOrDefault()?.Message, newLogs.LastOrDefault()?.Message); var eventData = new { logs = newLogs, totalCount = currentLogs.Count, newCount = newLogs.Count }; _logger.LogDebug("StreamLogs: 准备发送事件数据: {EventData}", Newtonsoft.Json.JsonConvert.SerializeObject(eventData)); await SendSseEvent("new_logs", eventData); await Response.Body.FlushAsync(cancellationToken); _logger.LogInformation("StreamLogs: 新日志事件发送完成"); // 更新索引和缓存 lastLogCount = currentLogs.Count; lastLogs = currentLogs.ToList(); lastLogHash = currentLogHash; } await Task.Delay(250, cancellationToken); } catch (OperationCanceledException) { // 正常的取消操作,退出循环 break; } catch (Exception ex) { _logger.LogError(ex, "StreamLogs 循环中发生错误"); await SendSseEvent("error", new { message = "处理日志流时发生错误", error = ex.Message, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); // 等待一段时间后继续,避免频繁错误 await Task.Delay(1000, cancellationToken); } } // 发送断开连接事件 await SendSseEvent("disconnected", new { message = "日志流连接已断开", timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(cancellationToken); } catch (OperationCanceledException) { _logger.LogInformation("StreamLogs 连接被客户端取消"); } catch (Exception ex) { _logger.LogError(ex, "StreamLogs 方法执行时发生未处理的异常"); try { await SendSseEvent("fatal_error", new { message = "服务器内部错误", error = ex.Message, timestamp = DateTime.UtcNow }); await Response.Body.FlushAsync(); } catch { // 忽略发送错误事件时的异常 } } } /// /// 计算日志列表的哈希值,用于检测内容变化 /// /// 日志列表 /// 哈希值字符串 private string CalculateLogsHash(List logs) { if (logs == null || !logs.Any()) return string.Empty; try { // 使用日志的关键字段计算哈希值 var hashInput = string.Join("|", logs.Select(log => $"{log.Timestamp}_{log.Layer}_{log.Message}")); using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var bytes = System.Text.Encoding.UTF8.GetBytes(hashInput); var hash = sha256.ComputeHash(bytes); return Convert.ToBase64String(hash); } } catch (Exception ex) { _logger.LogError(ex, "计算日志哈希值时发生错误"); return string.Empty; } } /// /// 获取变化的日志项 /// /// 旧日志列表 /// 新日志列表 /// 变化的日志列表 private List GetChangedLogs(List oldLogs, List newLogs) { var changedLogs = new List(); if (oldLogs.Count != newLogs.Count) { // 数量不同,返回所有新日志 return newLogs; } // 比较每个日志项 for (int i = 0; i < newLogs.Count; i++) { if (i < oldLogs.Count) { var oldLog = oldLogs[i]; var newLog = newLogs[i]; // 比较关键字段 if (oldLog.Timestamp != newLog.Timestamp || oldLog.Layer != newLog.Layer || oldLog.Message != newLog.Message) { changedLogs.Add(newLog); } } else { // 新增的日志 changedLogs.Add(newLogs[i]); } } return changedLogs; } /// /// 获取客户端消息日志文件列表 /// /// 日志文件列表 [HttpGet("clients/message-logs")] public ActionResult GetClientMessageLogFiles() { try { if (!Directory.Exists(_logsDirectory)) { return Ok(new { files = new List(), message = "日志目录不存在" }); } var logFiles = Directory.GetFiles(_logsDirectory, "*.log") .Select(filePath => new { fileName = Path.GetFileName(filePath), filePath = filePath, size = new System.IO.FileInfo(filePath).Length, lastModified = System.IO.File.GetLastWriteTime(filePath), clientName = Path.GetFileNameWithoutExtension(filePath).Replace("_sent_messages", "").Replace("_received_messages", ""), type = filePath.Contains("_sent_messages") ? "发送消息" : "接收消息" }) .OrderByDescending(f => f.lastModified) .ToList(); return Ok(new { files = logFiles, totalCount = logFiles.Count }); } catch (Exception ex) { _logger.LogError(ex, "获取客户端消息日志文件列表时发生错误"); return StatusCode(500, new { message = "获取日志文件列表失败", error = ex.Message }); } } /// /// 获取客户端消息日志文件内容 /// /// 文件名 /// 返回的行数(默认100行) /// 日志文件内容 [HttpGet("clients/message-logs/{fileName}")] public ActionResult GetClientMessageLogContent(string fileName, [FromQuery] int lines = 100) { try { var filePath = Path.Combine(_logsDirectory, fileName); if (!System.IO.File.Exists(filePath)) { return NotFound(new { message = $"日志文件 '{fileName}' 不存在" }); } var fileInfo = new System.IO.FileInfo(filePath); var allLines = System.IO.File.ReadAllLines(filePath, Encoding.UTF8); var lastLines = allLines.TakeLast(lines).ToList(); return Ok(new { fileName = fileName, filePath = filePath, totalLines = allLines.Length, returnedLines = lastLines.Count, fileSize = fileInfo.Length, lastModified = fileInfo.LastWriteTime, content = lastLines }); } catch (Exception ex) { _logger.LogError(ex, "获取客户端消息日志文件内容时发生错误: {FileName}", fileName); return StatusCode(500, new { message = "获取日志文件内容失败", error = ex.Message }); } } /// /// 清空客户端消息日志文件 /// /// 文件名(可选,如果不提供则清空所有日志文件) /// 操作结果 [HttpDelete("clients/message-logs")] public ActionResult ClearClientMessageLogs([FromQuery] string? fileName = null) { try { if (!Directory.Exists(_logsDirectory)) { return Ok(new { message = "日志目录不存在,无需清空" }); } int clearedCount = 0; if (string.IsNullOrEmpty(fileName)) { // 清空所有日志文件 var logFiles = Directory.GetFiles(_logsDirectory, "*.log"); foreach (var filePath in logFiles) { System.IO.File.WriteAllText(filePath, string.Empty); clearedCount++; } _logger.LogInformation("已清空 {Count} 个客户端消息日志文件", clearedCount); return Ok(new { message = $"已清空 {clearedCount} 个客户端消息日志文件" }); } else { // 清空指定日志文件 var filePath = Path.Combine(_logsDirectory, fileName); if (!System.IO.File.Exists(filePath)) { return NotFound(new { message = $"日志文件 '{fileName}' 不存在" }); } System.IO.File.WriteAllText(filePath, string.Empty); _logger.LogInformation("已清空客户端消息日志文件: {FileName}", fileName); return Ok(new { message = $"已清空客户端消息日志文件 '{fileName}'" }); } } catch (Exception ex) { _logger.LogError(ex, "清空客户端消息日志文件时发生错误"); return StatusCode(500, new { message = "清空日志文件失败", error = ex.Message }); } } /// /// 删除客户端消息日志文件 /// /// 文件名(可选,如果不提供则删除所有日志文件) /// 操作结果 [HttpDelete("clients/message-logs/delete")] public ActionResult DeleteClientMessageLogs([FromQuery] string? fileName = null) { try { if (!Directory.Exists(_logsDirectory)) { return Ok(new { message = "日志目录不存在,无需删除" }); } int deletedCount = 0; if (string.IsNullOrEmpty(fileName)) { // 删除所有日志文件 var logFiles = Directory.GetFiles(_logsDirectory, "*.log"); foreach (var filePath in logFiles) { System.IO.File.Delete(filePath); deletedCount++; } _logger.LogInformation("已删除 {Count} 个客户端消息日志文件", deletedCount); return Ok(new { message = $"已删除 {deletedCount} 个客户端消息日志文件" }); } else { // 删除指定日志文件 var filePath = Path.Combine(_logsDirectory, fileName); if (!System.IO.File.Exists(filePath)) { return NotFound(new { message = $"日志文件 '{fileName}' 不存在" }); } System.IO.File.Delete(filePath); _logger.LogInformation("已删除客户端消息日志文件: {FileName}", fileName); return Ok(new { message = $"已删除客户端消息日志文件 '{fileName}'" }); } } catch (Exception ex) { _logger.LogError(ex, "删除客户端消息日志文件时发生错误"); return StatusCode(500, new { message = "删除日志文件失败", error = ex.Message }); } } /// /// 获取日志缓存详细状态(调试用) /// /// 日志缓存详细状态 [HttpGet("logs/debug")] public ActionResult GetLogCacheDebugInfo() { try { var logs = _webSocketManager.GetLogCache()?.ToList() ?? new List(); var logCount = _webSocketManager.GetLogCacheCount(); var debugInfo = new { totalLogs = logCount, actualLogsCount = logs.Count, cacheSize = 10000, // LogCacheSize timestamp = DateTime.UtcNow, sampleLogs = logs.TakeLast(5).Select(log => new { timestamp = log.Timestamp, layer = log.Layer, //level = log.Level, message = log.Message?.Substring(0, Math.Min(100, log.Message?.Length ?? 0)) + "..." }).ToList(), logHash = CalculateLogsHash(logs) }; return Ok(debugInfo); } catch (Exception ex) { _logger.LogError(ex, "获取日志缓存调试信息时发生错误"); return StatusCode(500, new { message = "获取调试信息失败", error = ex.Message }); } } /// /// 获取SSE连接状态(调试用) /// /// 连接状态信息 [HttpGet("logs/connection-status")] public ActionResult GetSseConnectionStatus() { try { var status = new { timestamp = DateTime.UtcNow, requestHeaders = Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), userAgent = Request.Headers["User-Agent"].ToString(), accept = Request.Headers["Accept"].ToString(), cacheControl = Request.Headers["Cache-Control"].ToString(), connection = Request.Headers["Connection"].ToString(), isHttps = Request.IsHttps, host = Request.Host.ToString(), path = Request.Path.ToString(), queryString = Request.QueryString.ToString(), method = Request.Method, contentType = Request.ContentType, contentLength = Request.ContentLength }; return Ok(status); } catch (Exception ex) { _logger.LogError(ex, "获取SSE连接状态时发生错误"); return StatusCode(500, new { message = "获取连接状态失败", error = ex.Message }); } } } /// /// 日志配置请求 /// public class LogsConfigRequest { /// /// 日志配置 /// public Dictionary Config { get; set; } = new(); /// /// 是否保存配置 /// public bool Save { get; set; } = false; } }