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.
 
 
 

479 lines
16 KiB

using System.Collections.Concurrent;
using Newtonsoft.Json.Linq;
namespace LTEMvcApp.Models
{
/// <summary>
/// 统计数据模型
/// </summary>
public class StatisticsData
{
/// <summary>
/// 消息类型
/// </summary>
public string Message { get; set; } = "";
/// <summary>
/// 实例ID
/// </summary>
public string InstanceId { get; set; } = "";
/// <summary>
/// CPU信息
/// </summary>
public CpuInfo Cpu { get; set; } = new CpuInfo();
/// <summary>
/// RF信息
/// </summary>
public RfInfo Rf { get; set; } = new RfInfo();
/// <summary>
/// 样本信息
/// </summary>
public SamplesInfo Samples { get; set; } = new SamplesInfo();
/// <summary>
/// 小区信息
/// </summary>
public Dictionary<string, CellInfo> Cells { get; set; } = new Dictionary<string, CellInfo>();
/// <summary>
/// RF端口信息
/// </summary>
public Dictionary<string, RfPortInfo> RfPorts { get; set; } = new Dictionary<string, RfPortInfo>();
/// <summary>
/// 计数器信息
/// </summary>
public CountersInfo Counters { get; set; } = new CountersInfo();
/// <summary>
/// 持续时间
/// </summary>
public double Duration { get; set; }
/// <summary>
/// 消息ID
/// </summary>
public int MessageId { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public double Time { get; set; }
/// <summary>
/// 接收时间
/// </summary>
public DateTime ReceivedAt { get; set; } = DateTime.Now;
/// <summary>
/// 客户端名称
/// </summary>
public string ClientName { get; set; } = "";
/// <summary>
/// 从JObject创建StatisticsData
/// </summary>
public static StatisticsData FromJObject(JObject data, string clientName)
{
var stats = new StatisticsData
{
Message = data["message"]?.ToString() ?? "",
InstanceId = data["instance_id"]?.ToString() ?? "",
Duration = data["duration"]?.Value<double>() ?? 0,
MessageId = data["message_id"]?.Value<int>() ?? 0,
Time = data["time"]?.Value<double>() ?? 0,
ClientName = clientName
};
// 解析CPU信息
ParseCpuInfo(data, stats);
// 解析RF信息
ParseRfInfo(data, stats);
// 解析样本信息
ParseSamplesInfo(data, stats);
// 解析小区信息
ParseCellsInfo(data, stats);
// 解析RF端口信息
ParseRfPortsInfo(data, stats);
// 解析全局计数器
ParseGlobalCounters(data, stats);
return stats;
}
/// <summary>
/// 解析CPU信息
/// </summary>
private static void ParseCpuInfo(JObject data, StatisticsData stats)
{
if (data["cpu"] is JObject cpuObj)
{
stats.Cpu.Global = cpuObj["global"]?.Value<double>() ?? 0;
}
}
/// <summary>
/// 解析RF信息
/// </summary>
private static void ParseRfInfo(JObject data, StatisticsData stats)
{
if (data["rf"] is JObject rfObj)
{
stats.Rf.RxSampleRate = rfObj["rx_sample_rate"]?.Value<double>() ?? 0;
stats.Rf.TxSampleRate = rfObj["tx_sample_rate"]?.Value<double>() ?? 0;
stats.Rf.RxCpuTime = rfObj["rx_cpu_time"]?.Value<double>() ?? 0;
stats.Rf.TxCpuTime = rfObj["tx_cpu_time"]?.Value<double>() ?? 0;
stats.Rf.RxtxDelayMin = rfObj["rxtx_delay_min"]?.Value<double>() ?? 0;
stats.Rf.RxtxDelayAvg = rfObj["rxtx_delay_avg"]?.Value<double>() ?? 0;
stats.Rf.RxtxDelayMax = rfObj["rxtx_delay_max"]?.Value<double>() ?? 0;
stats.Rf.RxtxDelaySd = rfObj["rxtx_delay_sd"]?.Value<double>() ?? 0;
}
}
/// <summary>
/// 解析样本信息
/// </summary>
private static void ParseSamplesInfo(JObject data, StatisticsData stats)
{
if (data["samples"] is JObject samplesObj)
{
// 解析TX样本
if (samplesObj["tx"] is JArray txArray)
{
foreach (var txSample in txArray)
{
if (txSample is JObject txObj)
{
stats.Samples.TxSamples.Add(new SampleInfo
{
Rms = txObj["rms"]?.Value<double>() ?? 0,
Max = txObj["max"]?.Value<double>() ?? 0,
Sat = txObj["sat"]?.Value<int>() ?? 0,
Count = txObj["count"]?.Value<long>() ?? 0
});
}
}
}
// 解析RX样本
if (samplesObj["rx"] is JArray rxArray)
{
foreach (var rxSample in rxArray)
{
if (rxSample is JObject rxObj)
{
stats.Samples.RxSamples.Add(new SampleInfo
{
Rms = rxObj["rms"]?.Value<double>() ?? 0,
Max = rxObj["max"]?.Value<double>() ?? 0,
Sat = rxObj["sat"]?.Value<int>() ?? 0,
Count = rxObj["count"]?.Value<long>() ?? 0
});
}
}
}
}
}
/// <summary>
/// 解析小区信息
/// </summary>
private static void ParseCellsInfo(JObject data, StatisticsData stats)
{
if (data["cells"] is JObject cellsObj)
{
foreach (var cell in cellsObj)
{
if (cell.Value is JObject cellObj)
{
var cellInfo = new CellInfo
{
DlBitrate = cellObj["dl_bitrate"]?.Value<double>() ?? 0,
UlBitrate = cellObj["ul_bitrate"]?.Value<double>() ?? 0,
DlTx = cellObj["dl_tx"]?.Value<double>() ?? 0,
UlTx = cellObj["ul_tx"]?.Value<double>() ?? 0,
DlRetx = cellObj["dl_retx"]?.Value<double>() ?? 0,
UlRetx = cellObj["ul_retx"]?.Value<double>() ?? 0,
DlUseMin = cellObj["dl_use_min"]?.Value<double>() ?? 0,
DlUseMax = cellObj["dl_use_max"]?.Value<double>() ?? 0,
DlUseAvg = cellObj["dl_use_avg"]?.Value<double>() ?? 0,
UlUseMin = cellObj["ul_use_min"]?.Value<double>() ?? 0,
UlUseMax = cellObj["ul_use_max"]?.Value<double>() ?? 0,
UlUseAvg = cellObj["ul_use_avg"]?.Value<double>() ?? 0,
DlSchedUsersMin = cellObj["dl_sched_users_min"]?.Value<double>() ?? 0,
DlSchedUsersMax = cellObj["dl_sched_users_max"]?.Value<double>() ?? 0,
DlSchedUsersAvg = cellObj["dl_sched_users_avg"]?.Value<double>() ?? 0,
UlSchedUsersMin = cellObj["ul_sched_users_min"]?.Value<double>() ?? 0,
UlSchedUsersMax = cellObj["ul_sched_users_max"]?.Value<double>() ?? 0,
UlSchedUsersAvg = cellObj["ul_sched_users_avg"]?.Value<double>() ?? 0,
UeCountMin = cellObj["ue_count_min"]?.Value<double>() ?? 0,
UeCountMax = cellObj["ue_count_max"]?.Value<double>() ?? 0,
UeCountAvg = cellObj["ue_count_avg"]?.Value<double>() ?? 0,
ErabCountMin = cellObj["erab_count_min"]?.Value<double>() ?? 0,
ErabCountMax = cellObj["erab_count_max"]?.Value<double>() ?? 0,
ErabCountAvg = cellObj["erab_count_avg"]?.Value<double>() ?? 0,
DlGbrUseMin = cellObj["dl_gbr_use_min"]?.Value<double>() ?? 0,
DlGbrUseMax = cellObj["dl_gbr_use_max"]?.Value<double>() ?? 0,
DlGbrUseAvg = cellObj["dl_gbr_use_avg"]?.Value<double>() ?? 0,
UlGbrUseMin = cellObj["ul_gbr_use_min"]?.Value<double>() ?? 0,
UlGbrUseMax = cellObj["ul_gbr_use_max"]?.Value<double>() ?? 0,
UlGbrUseAvg = cellObj["ul_gbr_use_avg"]?.Value<double>() ?? 0
};
// 解析小区计数器
ParseCounters(cellObj, cellInfo.Counters);
stats.Cells[cell.Key] = cellInfo;
}
}
}
}
/// <summary>
/// 解析RF端口信息
/// </summary>
private static void ParseRfPortsInfo(JObject data, StatisticsData stats)
{
if (data["rf_ports"] is JObject rfPortsObj)
{
foreach (var port in rfPortsObj)
{
if (port.Value is JObject portObj)
{
var rfPortInfo = new RfPortInfo();
if (portObj["rxtx_delay"] is JObject delayObj)
{
foreach (var delay in delayObj)
{
rfPortInfo.RxtxDelay[delay.Key] = delay.Value?.Value<double>() ?? 0;
}
}
stats.RfPorts[port.Key] = rfPortInfo;
}
}
}
}
/// <summary>
/// 解析全局计数器
/// </summary>
private static void ParseGlobalCounters(JObject data, StatisticsData stats)
{
if (data["counters"] is JObject globalCountersObj)
{
ParseCounters(globalCountersObj, stats.Counters);
}
}
/// <summary>
/// 解析计数器信息
/// </summary>
private static void ParseCounters(JObject countersObj, CountersInfo counters)
{
if (countersObj["messages"] is JObject messagesObj)
{
foreach (var msg in messagesObj)
{
counters.Messages[msg.Key] = msg.Value?.Value<int>() ?? 0;
}
}
if (countersObj["errors"] is JObject errorsObj)
{
foreach (var err in errorsObj)
{
counters.Errors[err.Key] = err.Value?.Value<int>() ?? 0;
}
}
}
}
/// <summary>
/// CPU信息
/// </summary>
public class CpuInfo
{
public double Global { get; set; }
}
/// <summary>
/// RF信息
/// </summary>
public class RfInfo
{
public double RxSampleRate { get; set; }
public double TxSampleRate { get; set; }
public double RxCpuTime { get; set; }
public double TxCpuTime { get; set; }
public double RxtxDelayMin { get; set; }
public double RxtxDelayAvg { get; set; }
public double RxtxDelayMax { get; set; }
public double RxtxDelaySd { get; set; }
}
/// <summary>
/// 样本信息
/// </summary>
public class SamplesInfo
{
public List<SampleInfo> TxSamples { get; set; } = new List<SampleInfo>();
public List<SampleInfo> RxSamples { get; set; } = new List<SampleInfo>();
}
/// <summary>
/// 单个样本信息
/// </summary>
public class SampleInfo
{
public double Rms { get; set; }
public double Max { get; set; }
public int Sat { get; set; }
public long Count { get; set; }
}
/// <summary>
/// 小区信息
/// </summary>
public class CellInfo
{
public double DlBitrate { get; set; }
public double UlBitrate { get; set; }
public double DlTx { get; set; }
public double UlTx { get; set; }
public double DlRetx { get; set; }
public double UlRetx { get; set; }
public double DlUseMin { get; set; }
public double DlUseMax { get; set; }
public double DlUseAvg { get; set; }
public double UlUseMin { get; set; }
public double UlUseMax { get; set; }
public double UlUseAvg { get; set; }
public double DlSchedUsersMin { get; set; }
public double DlSchedUsersMax { get; set; }
public double DlSchedUsersAvg { get; set; }
public double UlSchedUsersMin { get; set; }
public double UlSchedUsersMax { get; set; }
public double UlSchedUsersAvg { get; set; }
public double UeCountMin { get; set; }
public double UeCountMax { get; set; }
public double UeCountAvg { get; set; }
public double ErabCountMin { get; set; }
public double ErabCountMax { get; set; }
public double ErabCountAvg { get; set; }
public double DlGbrUseMin { get; set; }
public double DlGbrUseMax { get; set; }
public double DlGbrUseAvg { get; set; }
public double UlGbrUseMin { get; set; }
public double UlGbrUseMax { get; set; }
public double UlGbrUseAvg { get; set; }
public CountersInfo Counters { get; set; } = new CountersInfo();
}
/// <summary>
/// RF端口信息
/// </summary>
public class RfPortInfo
{
public Dictionary<string, double> RxtxDelay { get; set; } = new Dictionary<string, double>();
}
/// <summary>
/// 计数器信息
/// </summary>
public class CountersInfo
{
public Dictionary<string, int> Messages { get; set; } = new Dictionary<string, int>();
public Dictionary<string, int> Errors { get; set; } = new Dictionary<string, int>();
}
/// <summary>
/// 统计数据队列管理器
/// </summary>
public class StatisticsQueueManager
{
private readonly ConcurrentQueue<StatisticsData> _statsQueue = new ConcurrentQueue<StatisticsData>();
private readonly int _maxQueueSize = 1000; // 最大队列大小
private readonly object _lockObject = new object();
/// <summary>
/// 添加统计数据到队列
/// </summary>
public void EnqueueStats(StatisticsData stats)
{
lock (_lockObject)
{
_statsQueue.Enqueue(stats);
// 维持队列大小
while (_statsQueue.Count > _maxQueueSize)
{
_statsQueue.TryDequeue(out _);
}
}
}
/// <summary>
/// 获取队列中的所有统计数据
/// </summary>
public List<StatisticsData> GetAllStats()
{
lock (_lockObject)
{
var result = new List<StatisticsData>();
foreach (var item in _statsQueue)
{
if (item != null)
result.Add(item);
}
return result;
}
}
/// <summary>
/// 获取最新的统计数据
/// </summary>
public StatisticsData? GetLatestStats()
{
lock (_lockObject)
{
return _statsQueue.TryPeek(out var stats) ? stats : null;
}
}
/// <summary>
/// 清空队列
/// </summary>
public void Clear()
{
lock (_lockObject)
{
while (_statsQueue.TryDequeue(out _))
{
// 清空所有数据
}
}
}
/// <summary>
/// 获取队列大小
/// </summary>
public int Count
{
get
{
lock (_lockObject)
{
return _statsQueue.Count;
}
}
}
}
}