diff --git a/LTEMvcApp/Controllers/StatisticsController.cs b/LTEMvcApp/Controllers/StatisticsController.cs index 5ed017b..f830080 100644 --- a/LTEMvcApp/Controllers/StatisticsController.cs +++ b/LTEMvcApp/Controllers/StatisticsController.cs @@ -161,6 +161,114 @@ namespace LTEMvcApp.Controllers } } + /// + /// 获取全局统计配置 + /// + [HttpGet] + public IActionResult GetGlobalStatisticsConfig() + { + try + { + var config = _webSocketManager.GetGlobalStatisticsConfig(); + return Json(new { success = true, data = config }); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取全局统计配置时出错"); + return Json(new { success = false, message = ex.Message }); + } + } + + /// + /// 设置全局统计配置 + /// + [HttpPost] + public IActionResult SetGlobalStatisticsConfig([FromBody] GlobalStatisticsConfig config) + { + try + { + _webSocketManager.SetGlobalStatisticsConfig(config); + return Json(new { success = true, message = "全局统计配置已更新" }); + } + catch (Exception ex) + { + _logger.LogError(ex, "设置全局统计配置时出错"); + return Json(new { success = false, message = ex.Message }); + } + } + + /// + /// 获取指定客户端的统计配置 + /// + [HttpGet] + public IActionResult GetClientStatisticsConfig(string clientName) + { + try + { + var config = _webSocketManager.GetClientStatisticsConfig(clientName); + return Json(new { success = true, data = config }); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取客户端统计配置时出错: {ClientName}", clientName); + return Json(new { success = false, message = ex.Message }); + } + } + + /// + /// 设置指定客户端的统计配置 + /// + [HttpPost] + public IActionResult SetClientStatisticsConfig([FromBody] StatisticsConfig config) + { + try + { + _webSocketManager.SetClientStatisticsConfig(config); + return Json(new { success = true, message = "客户端统计配置已更新" }); + } + catch (Exception ex) + { + _logger.LogError(ex, "设置客户端统计配置时出错: {ClientName}", config.ClientName); + return Json(new { success = false, message = ex.Message }); + } + } + + /// + /// 根据IP地址获取统计配置 + /// + [HttpGet] + public IActionResult GetStatisticsConfigByIp(string ipAddress) + { + try + { + var config = _webSocketManager.GetStatisticsConfigByIp(ipAddress); + return Json(new { success = true, data = config }); + } + catch (Exception ex) + { + _logger.LogError(ex, "根据IP获取统计配置时出错: {IpAddress}", ipAddress); + return Json(new { success = false, message = ex.Message }); + } + } + + /// + /// 获取所有客户端的统计配置 + /// + [HttpGet] + public IActionResult GetAllClientStatisticsConfigs() + { + try + { + var globalConfig = _webSocketManager.GetGlobalStatisticsConfig(); + return Json(new { success = true, data = globalConfig.ClientConfigs }); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取所有客户端统计配置时出错"); + return Json(new { success = false, message = ex.Message }); + } + } + /// /// SSE推送 - 所有统计数据 /// diff --git a/LTEMvcApp/Models/StatisticsConfig.cs b/LTEMvcApp/Models/StatisticsConfig.cs new file mode 100644 index 0000000..9e98ba4 --- /dev/null +++ b/LTEMvcApp/Models/StatisticsConfig.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; + +namespace LTEMvcApp.Models +{ + /// + /// 统计配置模型 + /// + public class StatisticsConfig + { + /// + /// 客户端IP地址 + /// + public string IpAddress { get; set; } = string.Empty; + + /// + /// 客户端名称 + /// + public string ClientName { get; set; } = string.Empty; + + /// + /// 是否启用samples参数 + /// + public bool EnableSamples { get; set; } = false; + + /// + /// 是否启用rf参数 + /// + public bool EnableRf { get; set; } = false; + + /// + /// 是否启用此配置 + /// + public bool IsEnabled { get; set; } = true; + + /// + /// 描述信息 + /// + public string Description { get; set; } = string.Empty; + } + + /// + /// 全局统计配置 + /// + public class GlobalStatisticsConfig + { + /// + /// 默认samples值 + /// + public bool DefaultSamples { get; set; } = false; + + /// + /// 默认rf值 + /// + public bool DefaultRf { get; set; } = false; + + /// + /// 客户端特定配置 + /// + public List ClientConfigs { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/LTEMvcApp/README_StatisticsConfig_Implementation.md b/LTEMvcApp/README_StatisticsConfig_Implementation.md new file mode 100644 index 0000000..458f51f --- /dev/null +++ b/LTEMvcApp/README_StatisticsConfig_Implementation.md @@ -0,0 +1,173 @@ +# 统计配置功能实现说明 + +## 概述 + +本功能实现了通过StatisticsController动态控制统计消息中的`samples`和`rf`参数,支持根据IP地址为不同客户端设置不同的统计配置。 + +## 功能特性 + +### 1. 全局统计配置 +- 设置默认的`samples`和`rf`值 +- 所有未配置特定参数的客户端将使用全局默认值 + +### 2. 客户端特定配置 +- 根据客户端名称或IP地址设置特定的统计参数 +- 支持启用/禁用配置 +- 可添加描述信息 + +### 3. 动态配置管理 +- 通过Web界面实时修改配置 +- 配置自动保存到`statistics_config.json`文件 +- 支持配置列表查看和编辑 + +## 文件结构 + +### 新增文件 +- `Models/StatisticsConfig.cs` - 统计配置模型 +- `statistics_config.json` - 统计配置文件 + +### 修改文件 +- `Services/LTEClientWebSocket.cs` - 添加统计配置支持 +- `Services/WebSocketManagerService.cs` - 添加配置管理功能 +- `Controllers/StatisticsController.cs` - 添加配置管理API +- `Views/Home/StatisticsTest.cshtml` - 添加配置管理界面 + +## 核心实现 + +### 1. 统计配置模型 + +```csharp +public class StatisticsConfig +{ + public string IpAddress { get; set; } = string.Empty; + public string ClientName { get; set; } = string.Empty; + public bool EnableSamples { get; set; } = false; + public bool EnableRf { get; set; } = false; + public bool IsEnabled { get; set; } = true; + public string Description { get; set; } = string.Empty; +} + +public class GlobalStatisticsConfig +{ + public bool DefaultSamples { get; set; } = false; + public bool DefaultRf { get; set; } = false; + public List ClientConfigs { get; set; } = new List(); +} +``` + +### 2. WebSocket客户端配置 + +在`LTEClientWebSocket`类中添加了统计配置字段和方法: + +```csharp +// 统计配置相关字段 +private bool _enableSamples = false; +private bool _enableRf = false; + +// 设置统计配置 +public void SetStatisticsConfig(bool enableSamples, bool enableRf) +{ + _enableSamples = enableSamples; + _enableRf = enableRf; +} + +// 在UpdateStats方法中使用配置 +var msg = new JObject { + ["message"] = "stats", + ["samples"] = _enableSamples, + ["rf"] = _enableRf +}; +``` + +### 3. 配置管理服务 + +在`WebSocketManagerService`中添加了配置管理功能: + +```csharp +// 加载和保存配置 +private void LoadStatisticsConfig() +private void SaveStatisticsConfig() + +// 配置管理方法 +public GlobalStatisticsConfig GetGlobalStatisticsConfig() +public void SetGlobalStatisticsConfig(GlobalStatisticsConfig config) +public StatisticsConfig? GetClientStatisticsConfig(string clientName) +public void SetClientStatisticsConfig(StatisticsConfig config) +public StatisticsConfig? GetStatisticsConfigByIp(string ipAddress) + +// 应用配置到客户端 +private void UpdateClientStatisticsConfig(string clientName) +private void UpdateAllClientsStatisticsConfig() +``` + +### 4. API接口 + +在`StatisticsController`中添加了配置管理API: + +```csharp +[HttpGet] GetGlobalStatisticsConfig() +[HttpPost] SetGlobalStatisticsConfig([FromBody] GlobalStatisticsConfig config) +[HttpGet] GetClientStatisticsConfig(string clientName) +[HttpPost] SetClientStatisticsConfig([FromBody] StatisticsConfig config) +[HttpGet] GetStatisticsConfigByIp(string ipAddress) +[HttpGet] GetAllClientStatisticsConfigs() +``` + +## 使用方法 + +### 1. 访问配置界面 +访问 `/Home/StatisticsTest` 页面,可以看到统计配置管理界面。 + +### 2. 设置全局配置 +- 在"全局统计配置"区域设置默认的samples和rf值 +- 点击"保存配置"按钮保存 + +### 3. 设置客户端特定配置 +- 在"客户端特定配置"区域输入客户端信息 +- 设置特定的samples和rf值 +- 点击"保存配置"按钮保存 + +### 4. 查看配置列表 +- 在"配置列表"区域可以看到所有已配置的客户端 +- 点击"编辑"按钮可以修改现有配置 + +## 配置优先级 + +1. **客户端特定配置** - 如果客户端有特定的配置且启用,则使用该配置 +2. **全局默认配置** - 如果客户端没有特定配置,则使用全局默认值 +3. **系统默认值** - 如果都没有配置,则使用系统默认值(samples=false, rf=false) + +## 配置文件格式 + +```json +{ + "defaultSamples": false, + "defaultRf": false, + "clientConfigs": [ + { + "ipAddress": "192.168.13.12", + "clientName": "TestClient1", + "enableSamples": true, + "enableRf": false, + "isEnabled": true, + "description": "测试客户端1 - 启用samples" + } + ] +} +``` + +## 注意事项 + +1. 配置修改后会自动应用到所有已连接的客户端 +2. 新连接的客户端会自动应用相应的配置 +3. 配置文件会在应用启动时自动加载 +4. 配置修改会实时保存到文件,重启应用后配置仍然有效 + +## 扩展功能 + +可以根据需要扩展以下功能: +- 配置模板管理 +- 配置导入/导出 +- 配置版本控制 +- 配置变更日志 +- 批量配置操作 \ No newline at end of file diff --git a/LTEMvcApp/Services/LTEClientWebSocket.cs b/LTEMvcApp/Services/LTEClientWebSocket.cs index 97c4365..aa232bc 100644 --- a/LTEMvcApp/Services/LTEClientWebSocket.cs +++ b/LTEMvcApp/Services/LTEClientWebSocket.cs @@ -46,6 +46,10 @@ namespace LTEMvcApp.Services // 防止重复调用的标志 private bool _isSocketReady = false; + + // 统计配置相关字段 + private bool _enableSamples = false; + private bool _enableRf = false; #endregion #region 事件 @@ -449,6 +453,27 @@ namespace LTEMvcApp.Services return Interlocked.CompareExchange(ref _logGetId, -1, -1); } + /// + /// 设置统计配置 + /// + /// 是否启用samples + /// 是否启用rf + public void SetStatisticsConfig(bool enableSamples, bool enableRf) + { + _enableSamples = enableSamples; + _enableRf = enableRf; + _logger.LogInformation($"[{_config.Name}] 设置统计配置: samples={enableSamples}, rf={enableRf}"); + } + + /// + /// 获取当前统计配置 + /// + /// 统计配置 + public (bool samples, bool rf) GetStatisticsConfig() + { + return (_enableSamples, _enableRf); + } + #endregion #region 私有方法 @@ -1011,7 +1036,7 @@ namespace LTEMvcApp.Services { if (_disposed || _webSocket?.State != WebSocketState.Open) return; - var msg = new JObject { ["message"] = "stats", ["samples"] = false, ["rf"]=false }; + var msg = new JObject { ["message"] = "stats", ["samples"] = _enableSamples, ["rf"]=_enableRf }; // 准备统计消息(对应JavaScript版本的tab.statsPrepare) PrepareStatsMessage(msg); diff --git a/LTEMvcApp/Services/StatisticsService.cs b/LTEMvcApp/Services/StatisticsService.cs index 8cee246..4b3d727 100644 --- a/LTEMvcApp/Services/StatisticsService.cs +++ b/LTEMvcApp/Services/StatisticsService.cs @@ -148,7 +148,7 @@ namespace LTEMvcApp.Services /// /// 获取统计摘要信息 /// - public object GetStatsSummary() + public object GetSummary() { var summary = new { diff --git a/LTEMvcApp/Services/WebSocketManagerService.cs b/LTEMvcApp/Services/WebSocketManagerService.cs index 5564a8f..aae083d 100644 --- a/LTEMvcApp/Services/WebSocketManagerService.cs +++ b/LTEMvcApp/Services/WebSocketManagerService.cs @@ -28,6 +28,8 @@ namespace LTEMvcApp.Services private readonly ConcurrentQueue _logCache = new ConcurrentQueue(); private readonly string _configsFilePath = "test_client_configs.json"; // 只保留多个配置文件路径 private readonly StatisticsService _statisticsService; // 添加统计服务 + private readonly string _statisticsConfigFilePath = "statistics_config.json"; // 统计配置文件路径 + private GlobalStatisticsConfig _globalStatisticsConfig; // 全局统计配置 #endregion @@ -73,8 +75,10 @@ namespace LTEMvcApp.Services _serviceProvider = serviceProvider; _testClientConfigs = new List(); // 初始化测试配置列表 _statisticsService = serviceProvider.GetRequiredService(); // 通过依赖注入获取统计服务 + _globalStatisticsConfig = new GlobalStatisticsConfig(); // 初始化全局统计配置 LoadTestClientConfigs(); // 加载多个测试配置 + LoadStatisticsConfig(); // 加载统计配置 // 订阅统计服务事件 _statisticsService.StatsUpdated += (sender, stats) => StatisticsUpdated?.Invoke(this, stats); @@ -127,6 +131,51 @@ namespace LTEMvcApp.Services } } + /// + /// 加载统计配置 + /// + private void LoadStatisticsConfig() + { + try + { + if (File.Exists(_statisticsConfigFilePath)) + { + var json = File.ReadAllText(_statisticsConfigFilePath); + _globalStatisticsConfig = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? new GlobalStatisticsConfig(); + _logger.LogInformation("成功从 {FilePath} 加载统计配置。", _statisticsConfigFilePath); + } + else + { + _logger.LogWarning("统计配置文件 {FilePath} 未找到,将创建默认配置。", _statisticsConfigFilePath); + _globalStatisticsConfig = new GlobalStatisticsConfig(); + SaveStatisticsConfig(); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "加载统计配置文件时出错。将使用默认配置。"); + _globalStatisticsConfig = new GlobalStatisticsConfig(); + } + } + + /// + /// 保存统计配置到文件 + /// + private void SaveStatisticsConfig() + { + try + { + var options = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + var json = JsonSerializer.Serialize(_globalStatisticsConfig, options); + File.WriteAllText(_statisticsConfigFilePath, json); + _logger.LogInformation("统计配置已成功保存到 {FilePath}。", _statisticsConfigFilePath); + } + catch (Exception ex) + { + _logger.LogError(ex, "保存统计配置文件失败。"); + } + } + #endregion #region 公共方法 @@ -205,6 +254,10 @@ namespace LTEMvcApp.Services client.StatsReceived += (sender, data) => OnStatsReceived(address, data); client.Start(); _clients[address] = client; + + // 应用统计配置 + UpdateClientStatisticsConfig(config.Name); + return true; } @@ -776,11 +829,11 @@ namespace LTEMvcApp.Services } /// - /// 获取统计摘要信息 + /// 获取统计摘要 /// public object GetStatisticsSummary() { - return _statisticsService.GetStatsSummary(); + return _statisticsService.GetSummary(); } /// @@ -815,6 +868,98 @@ namespace LTEMvcApp.Services return _statisticsService.GetClientCount(); } + /// + /// 获取全局统计配置 + /// + /// 全局统计配置 + public GlobalStatisticsConfig GetGlobalStatisticsConfig() + { + return _globalStatisticsConfig; + } + + /// + /// 设置全局统计配置 + /// + /// 统计配置 + public void SetGlobalStatisticsConfig(GlobalStatisticsConfig config) + { + _globalStatisticsConfig = config; + SaveStatisticsConfig(); + + // 更新所有客户端的统计配置 + UpdateAllClientsStatisticsConfig(); + } + + /// + /// 获取指定客户端的统计配置 + /// + /// 客户端名称 + /// 统计配置 + public StatisticsConfig? GetClientStatisticsConfig(string clientName) + { + return _globalStatisticsConfig.ClientConfigs.FirstOrDefault(c => c.ClientName == clientName); + } + + /// + /// 设置指定客户端的统计配置 + /// + /// 统计配置 + public void SetClientStatisticsConfig(StatisticsConfig config) + { + var existingConfig = _globalStatisticsConfig.ClientConfigs.FirstOrDefault(c => c.ClientName == config.ClientName); + if (existingConfig != null) + { + _globalStatisticsConfig.ClientConfigs.Remove(existingConfig); + } + _globalStatisticsConfig.ClientConfigs.Add(config); + SaveStatisticsConfig(); + + // 更新指定客户端的统计配置 + UpdateClientStatisticsConfig(config.ClientName); + } + + /// + /// 根据IP地址获取统计配置 + /// + /// IP地址 + /// 统计配置 + public StatisticsConfig? GetStatisticsConfigByIp(string ipAddress) + { + return _globalStatisticsConfig.ClientConfigs.FirstOrDefault(c => c.IpAddress == ipAddress); + } + + /// + /// 更新所有客户端的统计配置 + /// + private void UpdateAllClientsStatisticsConfig() + { + foreach (var client in _clients.Values) + { + UpdateClientStatisticsConfig(client.Config.Name); + } + } + + /// + /// 更新指定客户端的统计配置 + /// + /// 客户端名称 + private void UpdateClientStatisticsConfig(string clientName) + { + if (_clients.TryGetValue(clientName, out var client)) + { + var config = GetClientStatisticsConfig(clientName); + if (config != null && config.IsEnabled) + { + client.SetStatisticsConfig(config.EnableSamples, config.EnableRf); + } + else + { + // 使用默认配置 + client.SetStatisticsConfig(_globalStatisticsConfig.DefaultSamples, _globalStatisticsConfig.DefaultRf); + } + } + } + #endregion #endregion diff --git a/LTEMvcApp/Views/Home/StatisticsTest.cshtml b/LTEMvcApp/Views/Home/StatisticsTest.cshtml index 5f3c4e6..2ad5d33 100644 --- a/LTEMvcApp/Views/Home/StatisticsTest.cshtml +++ b/LTEMvcApp/Views/Home/StatisticsTest.cshtml @@ -25,6 +25,101 @@ +
+
+
统计配置管理
+
+
+
+
+
全局统计配置
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+
+
+
客户端特定配置
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+
+
+
+
+
+ +
+
+
配置列表
+ +
+ + + + + + + + + + + + + + +
客户端名称IP地址SamplesRF启用描述操作
+
+
+
+
测试结果
@@ -114,9 +209,145 @@ } } - // 页面加载时清空结果 + // 统计配置相关函数 + function loadGlobalConfig() { + logResult('加载全局统计配置...'); + $.get('/Statistics/GetGlobalStatisticsConfig', function(response) { + if (response.success) { + const config = response.data; + document.getElementById('globalSamples').checked = config.defaultSamples; + document.getElementById('globalRf').checked = config.defaultRf; + logResult('全局配置已加载: ' + JSON.stringify(config, null, 2)); + } else { + logResult('加载全局配置失败: ' + response.message); + } + }).fail(function(xhr, status, error) { + logResult('加载全局配置错误: ' + error); + }); + } + + function saveGlobalConfig() { + const config = { + defaultSamples: document.getElementById('globalSamples').checked, + defaultRf: document.getElementById('globalRf').checked, + clientConfigs: [] + }; + + logResult('保存全局统计配置...'); + $.ajax({ + url: '/Statistics/SetGlobalStatisticsConfig', + type: 'POST', + contentType: 'application/json', + data: JSON.stringify(config), + success: function(response) { + logResult('响应: ' + JSON.stringify(response, null, 2)); + }, + error: function(xhr, status, error) { + logResult('错误: ' + error); + } + }); + } + + function loadClientConfig() { + const clientName = document.getElementById('clientName').value; + if (!clientName) { + logResult('请输入客户端名称'); + return; + } + + logResult('加载客户端统计配置: ' + clientName); + $.get('/Statistics/GetClientStatisticsConfig', { clientName: clientName }, function(response) { + if (response.success && response.data) { + const config = response.data; + document.getElementById('clientName').value = config.clientName; + document.getElementById('clientIp').value = config.ipAddress; + document.getElementById('clientSamples').checked = config.enableSamples; + document.getElementById('clientRf').checked = config.enableRf; + document.getElementById('clientEnabled').checked = config.isEnabled; + document.getElementById('clientDescription').value = config.description; + logResult('客户端配置已加载: ' + JSON.stringify(config, null, 2)); + } else { + logResult('客户端配置未找到或加载失败'); + } + }).fail(function(xhr, status, error) { + logResult('加载客户端配置错误: ' + error); + }); + } + + function saveClientConfig() { + const config = { + clientName: document.getElementById('clientName').value, + ipAddress: document.getElementById('clientIp').value, + enableSamples: document.getElementById('clientSamples').checked, + enableRf: document.getElementById('clientRf').checked, + isEnabled: document.getElementById('clientEnabled').checked, + description: document.getElementById('clientDescription').value + }; + + if (!config.clientName) { + logResult('请输入客户端名称'); + return; + } + + logResult('保存客户端统计配置...'); + $.ajax({ + url: '/Statistics/SetClientStatisticsConfig', + type: 'POST', + contentType: 'application/json', + data: JSON.stringify(config), + success: function(response) { + logResult('响应: ' + JSON.stringify(response, null, 2)); + loadAllClientConfigs(); // 刷新配置列表 + }, + error: function(xhr, status, error) { + logResult('错误: ' + error); + } + }); + } + + function loadAllClientConfigs() { + logResult('加载所有客户端配置...'); + $.get('/Statistics/GetAllClientStatisticsConfigs', function(response) { + if (response.success) { + const configs = response.data; + const tbody = document.getElementById('configTableBody'); + tbody.innerHTML = ''; + + configs.forEach(function(config) { + const row = document.createElement('tr'); + row.innerHTML = ` + ${config.clientName} + ${config.ipAddress} + ${config.enableSamples ? '是' : '否'} + ${config.enableRf ? '是' : '否'} + ${config.isEnabled ? '是' : '否'} + ${config.description} + + + + `; + tbody.appendChild(row); + }); + + logResult('配置列表已更新,共 ' + configs.length + ' 个配置'); + } else { + logResult('加载配置列表失败: ' + response.message); + } + }).fail(function(xhr, status, error) { + logResult('加载配置列表错误: ' + error); + }); + } + + function editConfig(clientName) { + document.getElementById('clientName').value = clientName; + loadClientConfig(); + } + + // 页面加载时初始化 $(document).ready(function() { document.getElementById('testResult').textContent = ''; + loadGlobalConfig(); + loadAllClientConfigs(); }); } \ No newline at end of file diff --git a/LTEMvcApp/statistics_config.json b/LTEMvcApp/statistics_config.json new file mode 100644 index 0000000..54bf085 --- /dev/null +++ b/LTEMvcApp/statistics_config.json @@ -0,0 +1,22 @@ +{ + "defaultSamples": false, + "defaultRf": false, + "clientConfigs": [ + { + "ipAddress": "192.168.13.12", + "clientName": "TestClient1", + "enableSamples": true, + "enableRf": false, + "isEnabled": true, + "description": "测试客户端1 - 启用samples" + }, + { + "ipAddress": "192.168.13.13", + "clientName": "TestClient2", + "enableSamples": false, + "enableRf": true, + "isEnabled": true, + "description": "测试客户端2 - 启用rf" + } + ] +} \ No newline at end of file