You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
7.2 KiB

1 month ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LTEMvcApp.Models;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System.Text;
namespace LTEMvcApp.Services
{
/// <summary>
/// 统计服务 - 管理统计数据的队列和SSE推送
/// </summary>
public class StatisticsService
{
private readonly ILogger<StatisticsService> _logger;
private readonly StatisticsQueueManager _statsQueue;
private readonly ConcurrentDictionary<string, StatisticsData> _latestStatsByClient;
private readonly ConcurrentDictionary<string, List<StatisticsData>> _statsHistoryByClient;
private readonly int _maxHistorySize = 100; // 每个客户端最多保存100条历史记录
/// <summary>
/// 统计数据更新事件
/// </summary>
public event EventHandler<StatisticsData>? StatsUpdated;
/// <summary>
/// 构造函数
/// </summary>
public StatisticsService(ILogger<StatisticsService> logger)
{
_logger = logger;
_statsQueue = new StatisticsQueueManager();
_latestStatsByClient = new ConcurrentDictionary<string, StatisticsData>();
_statsHistoryByClient = new ConcurrentDictionary<string, List<StatisticsData>>();
_logger.LogInformation("StatisticsService 初始化完成");
}
/// <summary>
/// 处理接收到的统计数据
/// </summary>
public void ProcessStatsData(JObject data, string clientName)
{
try
{
var statsData = StatisticsData.FromJObject(data, clientName);
// 添加到队列
_statsQueue.EnqueueStats(statsData);
// 更新最新统计数据
_latestStatsByClient[clientName] = statsData;
// 添加到历史记录
AddToHistory(clientName, statsData);
// 触发事件
StatsUpdated?.Invoke(this, statsData);
_logger.LogDebug($"处理统计数据: 客户端 {clientName}, 消息ID {statsData.MessageId}, 小区数量 {statsData.Cells.Count}");
}
catch (Exception ex)
{
_logger.LogError(ex, $"处理统计数据时出错: 客户端 {clientName}");
}
}
/// <summary>
/// 添加统计数据到历史记录
/// </summary>
private void AddToHistory(string clientName, StatisticsData statsData)
{
if (!_statsHistoryByClient.TryGetValue(clientName, out var history))
{
history = new List<StatisticsData>();
_statsHistoryByClient[clientName] = history;
}
lock (history)
{
history.Add(statsData);
// 维持历史记录大小
while (history.Count > _maxHistorySize)
{
history.RemoveAt(0);
}
}
}
/// <summary>
/// 获取所有统计数据
/// </summary>
public List<StatisticsData> GetAllStats()
{
return _statsQueue.GetAllStats();
}
/// <summary>
/// 获取最新的统计数据
/// </summary>
public StatisticsData? GetLatestStats()
{
return _statsQueue.GetLatestStats();
}
/// <summary>
/// 获取指定客户端的最新统计数据
/// </summary>
public StatisticsData? GetLatestStatsByClient(string clientName)
{
_latestStatsByClient.TryGetValue(clientName, out var stats);
return stats;
}
/// <summary>
/// 获取指定客户端的历史统计数据
/// </summary>
public List<StatisticsData> GetStatsHistoryByClient(string clientName)
{
_statsHistoryByClient.TryGetValue(clientName, out var history);
return history ?? new List<StatisticsData>();
}
/// <summary>
/// 获取所有客户端的最新统计数据
/// </summary>
public Dictionary<string, StatisticsData> GetAllLatestStats()
{
return _latestStatsByClient.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
/// <summary>
/// 清空统计数据
/// </summary>
public void ClearStats()
{
_statsQueue.Clear();
_latestStatsByClient.Clear();
_statsHistoryByClient.Clear();
_logger.LogInformation("统计数据已清空");
}
/// <summary>
/// 获取统计摘要信息
/// </summary>
public object GetStatsSummary()
{
var summary = new
{
TotalStatsCount = _statsQueue.Count,
ClientCount = _latestStatsByClient.Count,
Clients = _latestStatsByClient.Keys.ToList(),
LastUpdateTime = _latestStatsByClient.Values
.OrderByDescending(s => s.ReceivedAt)
.FirstOrDefault()?.ReceivedAt
};
return summary;
}
/// <summary>
/// 获取SSE格式的统计数据
/// </summary>
public string GetStatsAsSSE()
{
var latestStats = GetAllLatestStats();
var sseData = new
{
type = "stats_update",
timestamp = DateTime.UtcNow,
data = latestStats
};
var json = System.Text.Json.JsonSerializer.Serialize(sseData, new System.Text.Json.JsonSerializerOptions
{
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
});
return $"data: {json}\n\n";
}
/// <summary>
/// 获取指定客户端的SSE格式统计数据
/// </summary>
public string GetClientStatsAsSSE(string clientName)
{
var stats = GetLatestStatsByClient(clientName);
if (stats == null)
{
return $"data: {System.Text.Json.JsonSerializer.Serialize(new { type = "error", message = "Client not found" })}\n\n";
}
var sseData = new
{
type = "client_stats_update",
clientName = clientName,
timestamp = DateTime.UtcNow,
data = stats
};
var json = System.Text.Json.JsonSerializer.Serialize(sseData, new System.Text.Json.JsonSerializerOptions
{
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
});
return $"data: {json}\n\n";
}
/// <summary>
/// 获取队列大小
/// </summary>
public int GetQueueCount()
{
return _statsQueue.Count;
}
/// <summary>
/// 获取客户端数量
/// </summary>
public int GetClientCount()
{
return _latestStatsByClient.Count;
}
}
}