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
230 lines
7.2 KiB
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 GetSummary()
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|