|
|
@ -39,6 +39,13 @@ namespace LTEMvcApp.Services |
|
|
|
private const int ServerMessageCacheLimit = 1000; |
|
|
|
private readonly ConcurrentQueue<string> _sentMessages = new ConcurrentQueue<string>(); |
|
|
|
private readonly ConcurrentQueue<string> _receivedMessages = new ConcurrentQueue<string>(); |
|
|
|
|
|
|
|
// 统计更新相关字段
|
|
|
|
private int _statsPollDelay = 1000; // 默认1秒,对应JavaScript版本的_statsPolldelay
|
|
|
|
private bool _isFirstStatsUpdate = true; |
|
|
|
|
|
|
|
// 防止重复调用的标志
|
|
|
|
private bool _isSocketReady = false; |
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 事件
|
|
|
@ -191,6 +198,7 @@ namespace LTEMvcApp.Services |
|
|
|
{ |
|
|
|
SetState(ClientState.Stop); |
|
|
|
StopTimers(); |
|
|
|
_isSocketReady = false; // 重置连接状态标志
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
@ -394,6 +402,31 @@ namespace LTEMvcApp.Services |
|
|
|
_logGetId = SendMessage(message, LogGetParse); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 手动触发统计更新
|
|
|
|
/// </summary>
|
|
|
|
public void TriggerStatsUpdate() |
|
|
|
{ |
|
|
|
UpdateStats(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 重置统计信息
|
|
|
|
/// </summary>
|
|
|
|
public void ResetStatistics() |
|
|
|
{ |
|
|
|
ResetStats(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 获取当前统计更新间隔
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>统计更新间隔(毫秒)</returns>
|
|
|
|
public int GetStatsUpdateInterval() |
|
|
|
{ |
|
|
|
return _statsPollDelay; |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 私有方法
|
|
|
@ -419,6 +452,9 @@ namespace LTEMvcApp.Services |
|
|
|
|
|
|
|
StopTimers(); |
|
|
|
CloseComponents(); |
|
|
|
|
|
|
|
// 重置连接状态标志
|
|
|
|
_isSocketReady = false; |
|
|
|
|
|
|
|
if (State == ClientState.Connected) |
|
|
|
{ |
|
|
@ -504,7 +540,14 @@ namespace LTEMvcApp.Services |
|
|
|
/// </summary>
|
|
|
|
private void OnSocketReady() |
|
|
|
{ |
|
|
|
if (_webSocket == null) return; |
|
|
|
if (_webSocket == null || _isSocketReady) |
|
|
|
{ |
|
|
|
_logger.LogDebug($"[{_config.Name}] OnSocketReady被跳过: WebSocket={_webSocket != null}, IsSocketReady={_isSocketReady}"); |
|
|
|
return; // 防止重复调用
|
|
|
|
} |
|
|
|
|
|
|
|
_logger.LogInformation($"[{_config.Name}] WebSocket准备就绪,开始初始化"); |
|
|
|
_isSocketReady = true; // 设置标志
|
|
|
|
|
|
|
|
// 切换到正常的消息处理函数
|
|
|
|
_webSocket.MessageReceived -= OnSocketMessage0; |
|
|
@ -516,9 +559,11 @@ namespace LTEMvcApp.Services |
|
|
|
var firstCon = _config.Logs.Layers.Count == 0; |
|
|
|
|
|
|
|
// 获取配置
|
|
|
|
_logger.LogDebug($"[{_config.Name}] 发送config_get请求"); |
|
|
|
SendMessage(new JObject { ["message"] = "config_get" }, config => |
|
|
|
{ |
|
|
|
Console.WriteLine("配置已接收"); |
|
|
|
_logger.LogInformation($"[{_config.Name}] 配置已接收"); |
|
|
|
|
|
|
|
_client.ResetLogs(); |
|
|
|
|
|
|
@ -552,6 +597,8 @@ namespace LTEMvcApp.Services |
|
|
|
foreach (var cell in cells) |
|
|
|
{ |
|
|
|
// 添加小区配置
|
|
|
|
|
|
|
|
_client.AddCell(Convert.ToInt32(cell.Key), cells); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -571,6 +618,9 @@ namespace LTEMvcApp.Services |
|
|
|
{ |
|
|
|
SetLogsConfig(_config.Logs); |
|
|
|
} |
|
|
|
|
|
|
|
// 启动统计更新(对应JavaScript版本的_updateStats(true))
|
|
|
|
UpdateStats(true); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
@ -693,58 +743,73 @@ namespace LTEMvcApp.Services |
|
|
|
{ |
|
|
|
if (logItem is JObject logObj) |
|
|
|
{ |
|
|
|
//var logData = logObj.ToObject<Dictionary<string, object>>() ?? new Dictionary<string, object>();
|
|
|
|
|
|
|
|
// 创建LTELog对象
|
|
|
|
var log = JsonConvert.DeserializeObject<LTELog>(logObj.ToString()); //new LTELog(logData);
|
|
|
|
|
|
|
|
// 处理消息和数据
|
|
|
|
if (log.Data is List<string> dataList && dataList.Count > 0) |
|
|
|
try |
|
|
|
{ |
|
|
|
log.Message = dataList[0]; |
|
|
|
dataList.RemoveAt(0); |
|
|
|
} |
|
|
|
// 使用JsonConvert反序列化创建LTELog对象
|
|
|
|
var log = JsonConvert.DeserializeObject<LTELog>(logObj.ToString()); |
|
|
|
if (log == null) continue; |
|
|
|
|
|
|
|
// 设置方向
|
|
|
|
log.Direction = _client.DirConvert(log); |
|
|
|
// 处理消息和数据 - 从data中提取第一条作为Message(与JavaScript版本保持一致)
|
|
|
|
if (log.Data is List<string> dataList && dataList.Count > 0) |
|
|
|
{ |
|
|
|
log.Message = dataList[0]; |
|
|
|
dataList.RemoveAt(0); |
|
|
|
} |
|
|
|
|
|
|
|
// 处理信息字段
|
|
|
|
if (log.Info != null) |
|
|
|
{ |
|
|
|
log.Info = _client.StringToId(log.Info.ToString()); |
|
|
|
} |
|
|
|
// 设置方向(与JavaScript版本保持一致)
|
|
|
|
log.Direction = _client.DirConvert(log); |
|
|
|
|
|
|
|
// 处理PHY层的信号记录
|
|
|
|
if (log.Layer == "PHY" && log.Data is List<string> data) |
|
|
|
{ |
|
|
|
var signalRecord = new Dictionary<string, object>(); |
|
|
|
for (int j = data.Count - 1; j >= 0; j--) |
|
|
|
// 处理信息字段(与JavaScript版本保持一致)
|
|
|
|
if (log.Info != null) |
|
|
|
{ |
|
|
|
var line = data[j]; |
|
|
|
var match = Regex.Match(line, @"Link:\s([\w\d]+)@(\d+)"); |
|
|
|
if (match.Success) |
|
|
|
{ |
|
|
|
var linkName = match.Groups[1].Value; |
|
|
|
var offset = uint.Parse(match.Groups[2].Value); |
|
|
|
signalRecord[linkName] = new { offset = offset }; |
|
|
|
data.RemoveAt(j); |
|
|
|
} |
|
|
|
log.Info = _client.StringToId(log.Info.ToString()); |
|
|
|
} |
|
|
|
|
|
|
|
if (signalRecord.Count > 0) |
|
|
|
// 处理PHY层的信号记录(与JavaScript版本保持一致)
|
|
|
|
if (log.Layer == "PHY" && log.Data is List<string> data) |
|
|
|
{ |
|
|
|
//log.SignalRecord = signalRecord;
|
|
|
|
_client.HasSignalRecord = true; |
|
|
|
var signalRecord = new Dictionary<string, object>(); |
|
|
|
for (int j = data.Count - 1; j >= 0; j--) |
|
|
|
{ |
|
|
|
var line = data[j]; |
|
|
|
var match = Regex.Match(line, @"Link:\s([\w\d]+)@(\d+)"); |
|
|
|
if (match.Success) |
|
|
|
{ |
|
|
|
var linkName = match.Groups[1].Value; |
|
|
|
var offset = uint.Parse(match.Groups[2].Value); |
|
|
|
signalRecord[linkName] = new { offset = offset }; |
|
|
|
data.RemoveAt(j); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (signalRecord.Count > 0) |
|
|
|
{ |
|
|
|
log.SignalRecord = signalRecord; // 修复:正确设置信号记录
|
|
|
|
_client.HasSignalRecord = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
log.Client = _client; |
|
|
|
logList.Add(log); |
|
|
|
log.Client = _client; |
|
|
|
logList.Add(log); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
_logger.LogError(ex, $"[{_config.Name}] 解析日志项时出错: {ex.Message}"); |
|
|
|
// 继续处理下一个日志项,不中断整个流程
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
_client.ParseLogList(logList, true); |
|
|
|
//_client.ParseLogList(logList, true);
|
|
|
|
LogsReceived?.Invoke(this, logList); |
|
|
|
|
|
|
|
// 调用日志解析(与JavaScript版本保持一致)
|
|
|
|
if (logList.Count > 0) |
|
|
|
{ |
|
|
|
_client.ParseLogList(logList, true); |
|
|
|
|
|
|
|
// 更新日志管理器(对应JavaScript版本的lteLogs.updateLogs())
|
|
|
|
_client.LogsManager.UpdateLogs(); |
|
|
|
|
|
|
|
LogsReceived?.Invoke(this, logList); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -811,8 +876,8 @@ namespace LTEMvcApp.Services |
|
|
|
_reconnectTimer?.Dispose(); |
|
|
|
_reconnectTimer = null; |
|
|
|
|
|
|
|
_statsTimer?.Dispose(); |
|
|
|
_statsTimer = null; |
|
|
|
StopStatsTimer(); // 使用专门的统计定时器停止方法
|
|
|
|
ResetStats(); // 重置统计信息
|
|
|
|
|
|
|
|
_messageDeferTimer?.Dispose(); |
|
|
|
_messageDeferTimer = null; |
|
|
@ -886,6 +951,129 @@ namespace LTEMvcApp.Services |
|
|
|
Console.WriteLine("需要认证,请输入密码"); |
|
|
|
} |
|
|
|
|
|
|
|
#region 统计更新相关方法
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 设置刷新延迟时间
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="delay">延迟时间(毫秒)</param>
|
|
|
|
public void SetRefreshDelay(int delay) |
|
|
|
{ |
|
|
|
_statsPollDelay = delay; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 获取刷新延迟时间
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>延迟时间(毫秒)</returns>
|
|
|
|
public int GetRefreshDelay() |
|
|
|
{ |
|
|
|
return _statsPollDelay; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 更新统计信息(对应JavaScript版本的_updateStats)
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="first">是否为第一次更新</param>
|
|
|
|
private void UpdateStats(bool first = false) |
|
|
|
{ |
|
|
|
if (_disposed || _webSocket?.State != WebSocketState.Open) return; |
|
|
|
|
|
|
|
var msg = new JObject { ["message"] = "stats" }; |
|
|
|
|
|
|
|
// 准备统计消息(对应JavaScript版本的tab.statsPrepare)
|
|
|
|
PrepareStatsMessage(msg); |
|
|
|
|
|
|
|
SendMessage(msg, response => |
|
|
|
{ |
|
|
|
if (_disposed) return; |
|
|
|
|
|
|
|
// 第一次调用会重置统计
|
|
|
|
if (first || _isFirstStatsUpdate) |
|
|
|
{ |
|
|
|
ResetStats(); |
|
|
|
_isFirstStatsUpdate = false; |
|
|
|
|
|
|
|
// 第一次调用后启动定时器循环
|
|
|
|
StartStatsTimer(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 发送统计事件(对应JavaScript版本的sendEvent)
|
|
|
|
StatsReceived?.Invoke(this, response); |
|
|
|
|
|
|
|
// 添加统计到统计面板(对应JavaScript版本的lteStatsTab.add)
|
|
|
|
AddStatsToPanel(response); |
|
|
|
|
|
|
|
// 设置下一次统计更新(对应JavaScript版本的定时器循环)
|
|
|
|
StartStatsTimer(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 准备统计消息
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="msg">统计消息</param>
|
|
|
|
private void PrepareStatsMessage(JObject msg) |
|
|
|
{ |
|
|
|
// 这里可以添加统计消息的准备工作
|
|
|
|
// 对应JavaScript版本中的tab.statsPrepare(msg)
|
|
|
|
_logger.LogDebug($"[{_config.Name}] 准备统计消息: {msg}"); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 重置统计信息(对应JavaScript版本的_resetStats)
|
|
|
|
/// </summary>
|
|
|
|
private void ResetStats() |
|
|
|
{ |
|
|
|
// 重置统计信息,对应JavaScript版本的lteStatsTab.add(this.getName(), {cpu: {global: 0}})
|
|
|
|
var resetStats = new JObject |
|
|
|
{ |
|
|
|
["cpu"] = new JObject { ["global"] = 0 } |
|
|
|
}; |
|
|
|
|
|
|
|
AddStatsToPanel(resetStats); |
|
|
|
_logger.LogDebug($"[{_config.Name}] 重置统计信息"); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 添加统计到面板
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="stats">统计信息</param>
|
|
|
|
private void AddStatsToPanel(JObject stats) |
|
|
|
{ |
|
|
|
// 这里应该将统计信息添加到统计面板
|
|
|
|
// 对应JavaScript版本中的lteStatsTab.add(this.getName(), resp)
|
|
|
|
_logger.LogDebug($"[{_config.Name}] 添加统计到面板: {stats}"); |
|
|
|
|
|
|
|
// 可以在这里实现具体的统计面板更新逻辑
|
|
|
|
// 或者通过事件通知其他组件更新统计信息
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 启动统计更新定时器
|
|
|
|
/// </summary>
|
|
|
|
private void StartStatsTimer() |
|
|
|
{ |
|
|
|
if (_statsTimer != null) |
|
|
|
{ |
|
|
|
_statsTimer.Dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
_statsTimer = new Timer(_ => UpdateStats(), null, _statsPollDelay, Timeout.Infinite); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 停止统计更新定时器
|
|
|
|
/// </summary>
|
|
|
|
private void StopStatsTimer() |
|
|
|
{ |
|
|
|
_statsTimer?.Dispose(); |
|
|
|
_statsTimer = null; |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region IDisposable
|
|
|
|