Browse Source

feat: 重构IRanGainControlHandler接口并添加RAN API控制器

- 重构IRanGainControlHandler接口,移除RanIPEndPoint参数,统一从ICellularNetworkContext获取端点信息
- 修复SetTxGainCommand构造函数,添加参数验证
- 创建SetAllTxGainCommand和SetAllTxGainCommandHandler,支持批量设置发送增益
- 创建RanAPIController,提供统一的RAN API访问接口
- 优化依赖注入配置,统一使用工厂模式
feature/protocol-log-Perfect
root 4 months ago
parent
commit
3f98edfb81
  1. 89
      CoreAgent.API/Controllers/RanAPIController.cs
  2. 25
      CoreAgent.Application/Commands/RanAPI/SetAllTxGainCommand.cs
  3. 25
      CoreAgent.Application/Commands/RanAPI/SetTxGainCommand.cs
  4. 73
      CoreAgent.Application/Handlers/RanAPI/SetAllTxGainCommandHandler.cs
  5. 73
      CoreAgent.Application/Handlers/RanAPI/SetTxGainCommandHandler.cs
  6. 39
      CoreAgent.Domain/Interfaces/Common/IServiceScopeManager.cs
  7. 14
      CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandler.cs
  8. 22
      CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandlerFactory.cs
  9. 12
      CoreAgent.Domain/Interfaces/Network/IRanGainControlHandler.cs
  10. 42
      CoreAgent.Domain/Interfaces/Network/IRanPowerControlHandler.cs
  11. 8
      CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs
  12. 325
      CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandler.cs
  13. 49
      CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandlerFactory.cs
  14. 130
      CoreAgent.Infrastructure/Services/Common/ServiceScopeManager.cs
  15. 85
      CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
  16. 564
      CoreAgent.Infrastructure/Services/Network/RanAPICommandHandler.cs
  17. 675
      modify.md

89
CoreAgent.API/Controllers/RanAPIController.cs

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CoreAgent.Application.Commands.RanAPI;
using CoreAgent.Domain.Models.Common;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace CoreAgent.API.Controllers;
/// <summary>
/// RAN API 控制器
/// 负责处理RAN相关的API操作
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class RanAPIController : BaseApiController
{
private readonly IMediator _mediator;
private readonly ILogger<RanAPIController> _logger;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="mediator">MediatR中介者</param>
/// <param name="logger">日志记录器</param>
public RanAPIController(IMediator mediator, ILogger<RanAPIController> logger)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 设置发送增益
/// </summary>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>设置结果</returns>
[HttpPost("set-tx-gain")]
public async Task<ApiActionResult<bool>> SetTxGain([FromBody] Dictionary<int, double> gainSettings)
{
try
{
_logger.LogInformation("收到设置发送增益请求,端口数量: {PortCount}", gainSettings?.Count);
var command = new SetTxGainCommand(gainSettings);
var result = await _mediator.Send(command);
_logger.LogInformation("设置发送增益请求处理完成");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "处理设置发送增益请求时发生异常");
return ApiActionResult<bool>.Error(
$"处理请求失败: {ex.Message}",
"INTERNAL_ERROR",
System.Net.HttpStatusCode.InternalServerError);
}
}
/// <summary>
/// 设置所有端口发送增益
/// </summary>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>设置结果</returns>
[HttpPost("set-all-tx-gain")]
public async Task<ApiActionResult<bool>> SetAllTxGain([FromBody] double[] gainValues)
{
try
{
_logger.LogInformation("收到设置所有端口发送增益请求,端口数量: {PortCount}", gainValues?.Length);
var command = new SetAllTxGainCommand(gainValues);
var result = await _mediator.Send(command);
_logger.LogInformation("设置所有端口发送增益请求处理完成");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "处理设置所有端口发送增益请求时发生异常");
return ApiActionResult<bool>.Error(
$"处理请求失败: {ex.Message}",
"INTERNAL_ERROR",
System.Net.HttpStatusCode.InternalServerError);
}
}
}

25
CoreAgent.Application/Commands/RanAPI/SetAllTxGainCommand.cs

@ -0,0 +1,25 @@
using System;
using CoreAgent.Domain.Models.Common;
using MediatR;
namespace CoreAgent.Application.Commands.RanAPI;
/// <summary>
/// 设置所有端口发送增益命令
/// </summary>
public class SetAllTxGainCommand : IRequest<ApiActionResult<bool>>
{
/// <summary>
/// 所有端口的增益值数组,按端口顺序排列
/// </summary>
public double[] GainValues { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="gainValues">所有端口的增益值数组</param>
public SetAllTxGainCommand(double[] gainValues)
{
GainValues = gainValues ?? throw new ArgumentNullException(nameof(gainValues));
}
}

25
CoreAgent.Application/Commands/RanAPI/SetTxGainCommand.cs

@ -0,0 +1,25 @@
using System;
using CoreAgent.Domain.Models.Common;
using MediatR;
namespace CoreAgent.Application.Commands.RanAPI;
/// <summary>
/// 设置发送增益命令
/// </summary>
public class SetTxGainCommand : IRequest<ApiActionResult<bool>>
{
/// <summary>
/// 增益设置字典,key为端口号(int),value为增益值(double)
/// </summary>
public Dictionary<int, double> GainSettings { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="gainSettings">增益设置字典</param>
public SetTxGainCommand(Dictionary<int, double> gainSettings)
{
GainSettings = gainSettings ?? throw new ArgumentNullException(nameof(gainSettings));
}
}

73
CoreAgent.Application/Handlers/RanAPI/SetAllTxGainCommandHandler.cs

@ -0,0 +1,73 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using CoreAgent.Application.Commands.RanAPI;
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Models.Common;
using MediatR;
using Microsoft.Extensions.Logging;
namespace CoreAgent.Application.Handlers.RanAPI;
/// <summary>
/// 设置所有端口发送增益命令处理器
/// </summary>
public class SetAllTxGainCommandHandler : IRequestHandler<SetAllTxGainCommand, ApiActionResult<bool>>
{
private readonly IRanAPICommandHandlerFactory _ranAPICommandHandlerFactory;
private readonly ILogger<SetAllTxGainCommandHandler> _logger;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="ranAPICommandHandlerFactory">RAN API命令处理器工厂</param>
/// <param name="logger">日志记录器</param>
public SetAllTxGainCommandHandler(
IRanAPICommandHandlerFactory ranAPICommandHandlerFactory,
ILogger<SetAllTxGainCommandHandler> logger)
{
_ranAPICommandHandlerFactory = ranAPICommandHandlerFactory ?? throw new ArgumentNullException(nameof(ranAPICommandHandlerFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 处理设置所有端口发送增益命令
/// </summary>
/// <param name="request">设置所有端口发送增益命令</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>设置所有端口发送增益结果</returns>
public async Task<ApiActionResult<bool>> Handle(SetAllTxGainCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("正在设置所有端口发送增益,端口数量: {PortCount}", request.GainValues?.Length);
// 通过工厂获取RAN增益控制处理器并执行操作
var ranGainControlHandler = _ranAPICommandHandlerFactory.CreateGainControlHandler();
var result = await ranGainControlHandler.SetAllTxGainAsync(request.GainValues);
if (result)
{
_logger.LogInformation("所有端口发送增益设置成功");
return ApiActionResult<bool>.Ok(true, "所有端口发送增益设置成功");
}
else
{
_logger.LogWarning("所有端口发送增益设置失败");
return ApiActionResult<bool>.Error(
"所有端口发送增益设置失败",
"ALL_TX_GAIN_SET_FAILED",
HttpStatusCode.BadRequest);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口发送增益失败");
return ApiActionResult<bool>.Error(
$"设置所有端口发送增益失败: {ex.Message}",
"INTERNAL_ERROR",
HttpStatusCode.InternalServerError);
}
}
}

73
CoreAgent.Application/Handlers/RanAPI/SetTxGainCommandHandler.cs

@ -0,0 +1,73 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using CoreAgent.Application.Commands.RanAPI;
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Models.Common;
using MediatR;
using Microsoft.Extensions.Logging;
namespace CoreAgent.Application.Handlers.RanAPI;
/// <summary>
/// 设置发送增益命令处理器
/// </summary>
public class SetTxGainCommandHandler : IRequestHandler<SetTxGainCommand, ApiActionResult<bool>>
{
private readonly IRanAPICommandHandlerFactory _ranAPICommandHandlerFactory;
private readonly ILogger<SetTxGainCommandHandler> _logger;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="ranAPICommandHandlerFactory">RAN API命令处理器工厂</param>
/// <param name="logger">日志记录器</param>
public SetTxGainCommandHandler(
IRanAPICommandHandlerFactory ranAPICommandHandlerFactory,
ILogger<SetTxGainCommandHandler> logger)
{
_ranAPICommandHandlerFactory = ranAPICommandHandlerFactory ?? throw new ArgumentNullException(nameof(ranAPICommandHandlerFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 处理设置发送增益命令
/// </summary>
/// <param name="request">设置发送增益命令</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>设置发送增益结果</returns>
public async Task<ApiActionResult<bool>> Handle(SetTxGainCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("正在设置发送增益,端口数量: {PortCount}", request.GainSettings?.Count);
// 通过工厂获取RAN增益控制处理器并执行操作
var ranGainControlHandler = _ranAPICommandHandlerFactory.CreateGainControlHandler();
var result = await ranGainControlHandler.SetTxGainAsync(request.GainSettings);
if (result)
{
_logger.LogInformation("发送增益设置成功");
return ApiActionResult<bool>.Ok(true, "发送增益设置成功");
}
else
{
_logger.LogWarning("发送增益设置失败");
return ApiActionResult<bool>.Error(
"发送增益设置失败",
"TX_GAIN_SET_FAILED",
HttpStatusCode.BadRequest);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置发送增益失败");
return ApiActionResult<bool>.Error(
$"设置发送增益失败: {ex.Message}",
"INTERNAL_ERROR",
HttpStatusCode.InternalServerError);
}
}
}

39
CoreAgent.Domain/Interfaces/Common/IServiceScopeManager.cs

@ -0,0 +1,39 @@
using Microsoft.Extensions.DependencyInjection;
namespace CoreAgent.Domain.Interfaces.Common;
/// <summary>
/// 服务作用域管理器接口
/// 用于在单例服务中创建瞬时服务
/// </summary>
public interface IServiceScopeManager
{
/// <summary>
/// 在作用域中执行操作
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="operation">要执行的操作</param>
/// <returns>操作结果</returns>
Task<T> ExecuteInScopeAsync<T>(Func<IServiceProvider, Task<T>> operation);
/// <summary>
/// 在作用域中执行操作(无返回值)
/// </summary>
/// <param name="operation">要执行的操作</param>
/// <returns>任务</returns>
Task ExecuteInScopeAsync(Func<IServiceProvider, Task> operation);
/// <summary>
/// 在作用域中执行操作(同步)
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="operation">要执行的操作</param>
/// <returns>操作结果</returns>
T ExecuteInScope<T>(Func<IServiceProvider, T> operation);
/// <summary>
/// 在作用域中执行操作(同步,无返回值)
/// </summary>
/// <param name="operation">要执行的操作</param>
void ExecuteInScope(Action<IServiceProvider> operation);
}

14
CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandler.cs

@ -11,12 +11,11 @@ namespace CoreAgent.Domain.Interfaces.Network;
public interface IRanAPICommandHandler
{
/// <summary>
/// 设置 RAN 日志配置
/// 设置 BCCH 日志状态
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="enableBcch">是否启用BCCH日志</param>
/// <returns>是否成功设置配置</returns>
Task<bool> SetRanLogsConfigAsync(RanIPEndPoint ranEndPoint, bool enableBcch);
/// <returns>是否成功设置BCCH日志状态</returns>
Task<bool> SetBcchLogStatusAsync(bool enableBcch);
}
/// <summary>
@ -76,10 +75,9 @@ public abstract class RanAPICommandHandlerBase : IRanAPICommandHandler
}
/// <summary>
/// 设置 RAN 日志配置
/// 设置 BCCH 日志状态
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="enableBcch">是否启用BCCH日志</param>
/// <returns>是否成功设置配置</returns>
public abstract Task<bool> SetRanLogsConfigAsync(RanIPEndPoint ranEndPoint, bool enableBcch);
/// <returns>是否成功设置BCCH日志状态</returns>
public abstract Task<bool> SetBcchLogStatusAsync(bool enableBcch);
}

22
CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandlerFactory.cs

@ -0,0 +1,22 @@
using CoreAgent.Domain.Models.Network;
namespace CoreAgent.Domain.Interfaces.Network;
/// <summary>
/// RAN API 命令处理器工厂接口
/// 负责创建和管理RAN API命令处理器实例
/// </summary>
public interface IRanAPICommandHandlerFactory
{
/// <summary>
/// 创建RAN API命令处理器
/// </summary>
/// <returns>RAN API命令处理器实例</returns>
IRanAPICommandHandler CreateHandler();
/// <summary>
/// 创建RAN增益控制处理器
/// </summary>
/// <returns>RAN增益控制处理器实例</returns>
IRanGainControlHandler CreateGainControlHandler();
}

12
CoreAgent.Domain/Interfaces/Network/IRanGainControlHandler.cs

@ -11,32 +11,28 @@ public interface IRanGainControlHandler
/// <summary>
/// 设置发送增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
Task<bool> SetTxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings);
Task<bool> SetTxGainAsync(Dictionary<int, double> gainSettings);
/// <summary>
/// 设置接收增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
Task<bool> SetRxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings);
Task<bool> SetRxGainAsync(Dictionary<int, double> gainSettings);
/// <summary>
/// 设置所有端口的发送增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
Task<bool> SetAllTxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues);
Task<bool> SetAllTxGainAsync(double[] gainValues);
/// <summary>
/// 设置所有端口的接收增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
Task<bool> SetAllRxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues);
Task<bool> SetAllRxGainAsync(double[] gainValues);
}

42
CoreAgent.Domain/Interfaces/Network/IRanPowerControlHandler.cs

@ -1,42 +0,0 @@
using CoreAgent.Domain.Models.Network;
namespace CoreAgent.Domain.Interfaces.Network;
/// <summary>
/// RAN API 功率控制接口
/// 负责处理发送和接收功率相关的操作
/// </summary>
public interface IRanPowerControlHandler
{
/// <summary>
/// 设置发送功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerSettings">功率设置字典,key为端口号(int),value为功率值(double)</param>
/// <returns>是否成功设置功率</returns>
Task<bool> SetTxPowerAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> powerSettings);
/// <summary>
/// 设置接收功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerSettings">功率设置字典,key为端口号(int),value为功率值(double)</param>
/// <returns>是否成功设置功率</returns>
Task<bool> SetRxPowerAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> powerSettings);
/// <summary>
/// 设置所有端口的发送功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerValues">所有端口的功率值数组,按端口顺序排列</param>
/// <returns>是否成功设置功率</returns>
Task<bool> SetAllTxPowerAsync(RanIPEndPoint ranEndPoint, double[] powerValues);
/// <summary>
/// 设置所有端口的接收功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerValues">所有端口的功率值数组,按端口顺序排列</param>
/// <returns>是否成功设置功率</returns>
Task<bool> SetAllRxPowerAsync(RanIPEndPoint ranEndPoint, double[] powerValues);
}

8
CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs

@ -2,12 +2,15 @@ using CoreAgent.Domain.Interfaces;
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Interfaces.System;
using CoreAgent.Domain.Interfaces.System.Command;
using CoreAgent.Domain.Interfaces.Common;
using CoreAgent.Infrastructure.Command.Factories;
using CoreAgent.Infrastructure.Contexts;
using CoreAgent.Infrastructure.Handlers.API;
using CoreAgent.Infrastructure.Repositories;
using CoreAgent.Infrastructure.Services;
using CoreAgent.Infrastructure.Services.Network;
using CoreAgent.Infrastructure.Services.System;
using CoreAgent.Infrastructure.Services.Common;
using CoreAgent.ProtocolClient.Interfaces;
using CoreAgent.ProtocolClient.ProtocolEngineCore;
using Microsoft.Extensions.DependencyInjection;
@ -45,6 +48,9 @@ public static class CommandServiceExtensions
services.AddSingleton<ISystemCommandExecutorFactory, SystemCommandExecutorFactory>();
services.AddSingleton<IProtocolLogObserver, NetworkProtocolLogObserver>();
services.AddSingleton<IProtocolWsClientManager, ProtocolWsClientManager>();
// 注册服务作用域管理器(单例)
services.AddSingleton<IServiceScopeManager, ServiceScopeManager>();
// 注册命令执行器(瞬时)
services.AddTransient<ISystemCommandExecutor>(sp =>
{
@ -61,6 +67,8 @@ public static class CommandServiceExtensions
services.AddScoped<INetworkStatusMonitor, NetworkStatusMonitor>();
services.AddScoped<ICellularNetworkService, CellularNetworkService>();
// 注册API处理器工厂
services.AddScoped<IRanAPICommandHandlerFactory, RanAPICommandHandlerFactory>();
// 注册系统服务
services.AddScoped<IDeviceService, DeviceService>();

325
CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandler.cs

@ -0,0 +1,325 @@
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Interfaces.System.Command;
using CoreAgent.Domain.Models.Network;
using CoreAgent.Domain.Models.System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace CoreAgent.Infrastructure.Handlers.API;
/// <summary>
/// RAN API 命令处理器实现
/// 负责处理各种RAN相关的API操作命令
/// </summary>
public class RanAPICommandHandler : RanAPICommandHandlerBase, IRanGainControlHandler
{
private readonly ILogger<RanAPICommandHandler> _logger;
private readonly ICellularNetworkContext _context;
public RanAPICommandHandler(
ILogger<RanAPICommandHandler> logger,
ISystemCommandExecutor commandExecutor,
IOptions<AppSettings> appSettings,
ICellularNetworkContext context)
: base(commandExecutor, appSettings.Value)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_context = context ?? throw new ArgumentNullException(nameof(context));
}
/// <summary>
/// 设置 BCCH 日志状态
/// </summary>
/// <param name="enableBcch">是否启用BCCH日志</param>
/// <returns>是否成功设置BCCH日志状态</returns>
public override async Task<bool> SetBcchLogStatusAsync(bool enableBcch)
{
var ranEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint();
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
try
{
var configCommand = $@"{{""message"":""config_set"",""logs"":{{""bcch"":{enableBcch.ToString().ToLower()}}}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogInformation("开始设置BCCH日志状态,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
var result = await ExecuteCommandAsync(command, "BCCH日志状态设置");
if (result.IsSuccess)
{
_logger.LogInformation("BCCH日志状态设置成功,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
return true;
}
else
{
_logger.LogWarning("BCCH日志状态设置失败,地址: {ComAddr}, 启用BCCH: {EnableBcch}, 错误: {Error}",
ranEndPoint.ComAddr, enableBcch, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置BCCH日志状态时发生异常,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
return false;
}
}
#region 增益控制方法
/// <summary>
/// 设置发送增益
/// </summary>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetTxGainAsync(Dictionary<int, double> gainSettings)
{
var ranEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint();
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainSettings == null || gainSettings.Count == 0)
{
_logger.LogWarning("增益设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = gainSettings.Count;
_logger.LogInformation("开始批量设置发送增益,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in gainSettings)
{
var port = setting.Key;
var setGain = setting.Value;
var configCommand = $@"{{""message"":""rf"",""tx_gain"":{setGain},""tx_channel_index"":{port}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogDebug("设置端口 {Port} 的发送增益值为 {SetGain}", port, setGain);
var result = await ExecuteCommandAsync(command, "发送增益设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 发送增益设置成功,增益值: {SetGain}", port, setGain);
}
else
{
_logger.LogWarning("端口 {Port} 发送增益设置失败,增益值: {SetGain}, 错误: {Error}",
port, setGain, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口发送增益设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口发送增益设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置发送增益时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置接收增益
/// </summary>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetRxGainAsync(Dictionary<int, double> gainSettings)
{
var ranEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint();
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainSettings == null || gainSettings.Count == 0)
{
_logger.LogWarning("增益设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = gainSettings.Count;
_logger.LogInformation("开始批量设置接收增益,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in gainSettings)
{
var port = setting.Key;
var setGain = setting.Value;
var configCommand = $@"{{""message"":""rf"",""rx_gain"":{setGain},""rx_channel_index"":{port}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogDebug("设置端口 {Port} 的接收增益值为 {SetGain}", port, setGain);
var result = await ExecuteCommandAsync(command, "接收增益设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 接收增益设置成功,增益值: {SetGain}", port, setGain);
}
else
{
_logger.LogWarning("端口 {Port} 接收增益设置失败,增益值: {SetGain}, 错误: {Error}",
port, setGain, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口接收增益设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口接收增益设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置接收增益时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置所有端口的发送增益
/// </summary>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetAllTxGainAsync(double[] gainValues)
{
var ranEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint();
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainValues == null || gainValues.Length == 0)
{
_logger.LogWarning("增益值数组为空或无效");
return false;
}
try
{
var gainArrayJson = $"[{string.Join(",", gainValues)}]";
var configCommand = $@"{{""message"":""rf"",""tx_gain"":{gainArrayJson}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogInformation("开始设置所有端口发送增益,地址: {ComAddr}, 端口数量: {PortCount}, 增益值: {GainValues}",
ranEndPoint.ComAddr, gainValues.Length, string.Join(",", gainValues));
var result = await ExecuteCommandAsync(command, "所有端口发送增益设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口发送增益设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口发送增益设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, gainValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口发送增益时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues?.Length ?? 0);
return false;
}
}
/// <summary>
/// 设置所有端口的接收增益
/// </summary>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetAllRxGainAsync(double[] gainValues)
{
var ranEndPoint = _context.NetworkIPEndPointManager.GetRanEndPoint();
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainValues == null || gainValues.Length == 0)
{
_logger.LogWarning("增益值数组为空或无效");
return false;
}
try
{
var gainArrayJson = $"[{string.Join(",", gainValues)}]";
var configCommand = $@"{{""message"":""rf"",""rx_gain"":{gainArrayJson}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogInformation("开始设置所有端口接收增益,地址: {ComAddr}, 端口数量: {PortCount}, 增益值: {GainValues}",
ranEndPoint.ComAddr, gainValues.Length, string.Join(",", gainValues));
var result = await ExecuteCommandAsync(command, "所有端口接收增益设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口接收增益设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口接收增益设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, gainValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口接收增益时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues?.Length ?? 0);
return false;
}
}
#endregion
}

49
CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandlerFactory.cs

@ -0,0 +1,49 @@
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Interfaces.System.Command;
using CoreAgent.Domain.Models.System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace CoreAgent.Infrastructure.Handlers.API;
/// <summary>
/// RAN API 命令处理器工厂实现
/// 负责创建和管理RAN API命令处理器实例
/// </summary>
public class RanAPICommandHandlerFactory : IRanAPICommandHandlerFactory
{
private readonly ILogger<RanAPICommandHandler> _logger;
private readonly ISystemCommandExecutor _commandExecutor;
private readonly IOptions<AppSettings> _appSettings;
private readonly ICellularNetworkContext _context;
public RanAPICommandHandlerFactory(
ILogger<RanAPICommandHandler> logger,
ISystemCommandExecutor commandExecutor,
IOptions<AppSettings> appSettings,
ICellularNetworkContext context)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
_appSettings = appSettings ?? throw new ArgumentNullException(nameof(appSettings));
_context = context ?? throw new ArgumentNullException(nameof(context));
}
/// <summary>
/// 创建RAN API命令处理器
/// </summary>
/// <returns>RAN API命令处理器实例</returns>
public IRanAPICommandHandler CreateHandler()
{
return new RanAPICommandHandler(_logger, _commandExecutor, _appSettings, _context);
}
/// <summary>
/// 创建RAN增益控制处理器
/// </summary>
/// <returns>RAN增益控制处理器实例</returns>
public IRanGainControlHandler CreateGainControlHandler()
{
return new RanAPICommandHandler(_logger, _commandExecutor, _appSettings, _context);
}
}

130
CoreAgent.Infrastructure/Services/Common/ServiceScopeManager.cs

@ -0,0 +1,130 @@
using CoreAgent.Domain.Interfaces.Common;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace CoreAgent.Infrastructure.Services.Common;
/// <summary>
/// 服务作用域管理器实现
/// 用于在单例服务中创建瞬时服务
/// </summary>
public class ServiceScopeManager : IServiceScopeManager
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<ServiceScopeManager> _logger;
public ServiceScopeManager(
IServiceScopeFactory scopeFactory,
ILogger<ServiceScopeManager> logger)
{
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 在作用域中执行异步操作
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="operation">要执行的操作</param>
/// <returns>操作结果</returns>
public async Task<T> ExecuteInScopeAsync<T>(Func<IServiceProvider, Task<T>> operation)
{
if (operation == null)
throw new ArgumentNullException(nameof(operation));
using var scope = _scopeFactory.CreateScope();
var serviceProvider = scope.ServiceProvider;
try
{
_logger.LogDebug("开始在执行作用域中执行异步操作");
var result = await operation(serviceProvider);
_logger.LogDebug("在执行作用域中执行异步操作完成");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "在执行作用域中执行异步操作时发生异常");
throw;
}
}
/// <summary>
/// 在作用域中执行异步操作(无返回值)
/// </summary>
/// <param name="operation">要执行的操作</param>
/// <returns>任务</returns>
public async Task ExecuteInScopeAsync(Func<IServiceProvider, Task> operation)
{
if (operation == null)
throw new ArgumentNullException(nameof(operation));
using var scope = _scopeFactory.CreateScope();
var serviceProvider = scope.ServiceProvider;
try
{
_logger.LogDebug("开始在执行作用域中执行异步操作");
await operation(serviceProvider);
_logger.LogDebug("在执行作用域中执行异步操作完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "在执行作用域中执行异步操作时发生异常");
throw;
}
}
/// <summary>
/// 在作用域中执行同步操作
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="operation">要执行的操作</param>
/// <returns>操作结果</returns>
public T ExecuteInScope<T>(Func<IServiceProvider, T> operation)
{
if (operation == null)
throw new ArgumentNullException(nameof(operation));
using var scope = _scopeFactory.CreateScope();
var serviceProvider = scope.ServiceProvider;
try
{
_logger.LogDebug("开始在执行作用域中执行同步操作");
var result = operation(serviceProvider);
_logger.LogDebug("在执行作用域中执行同步操作完成");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "在执行作用域中执行同步操作时发生异常");
throw;
}
}
/// <summary>
/// 在作用域中执行同步操作(无返回值)
/// </summary>
/// <param name="operation">要执行的操作</param>
public void ExecuteInScope(Action<IServiceProvider> operation)
{
if (operation == null)
throw new ArgumentNullException(nameof(operation));
using var scope = _scopeFactory.CreateScope();
var serviceProvider = scope.ServiceProvider;
try
{
_logger.LogDebug("开始在执行作用域中执行同步操作");
operation(serviceProvider);
_logger.LogDebug("在执行作用域中执行同步操作完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "在执行作用域中执行同步操作时发生异常");
throw;
}
}
}

85
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs

@ -12,6 +12,8 @@ using CoreAgent.ProtocolClient.Interfaces;
using CoreAgent.ProtocolClient.ProtocolEngineCore;
using CoreAgent.WebSocketTransport.Interfaces;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using CoreAgent.Domain.Interfaces.Common;
namespace CoreAgent.Infrastructure.Services.Network
{
@ -22,15 +24,14 @@ namespace CoreAgent.Infrastructure.Services.Network
{
private readonly ILogger<CellularNetworkService> _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly ISystemCommandExecutor _commandExecutor;
private readonly INetworkConfigurationService _configService;
private readonly ICellularNetworkContext _context;
private readonly INetworkConfigCopier _configCopier;
private readonly INetworkInterfaceManager _interfaceManager;
private readonly INetworkStatusMonitor _statusMonitor;
private readonly IWebSocketTransport _webSocketTransport;
private readonly IProtocolLogObserver _protocolLogObserver;
private readonly IProtocolWsClientManager _protocolWsClientManager;
private readonly IServiceScopeManager _serviceScopeManager;
private readonly IRanAPICommandHandlerFactory _ranAPICommandHandlerFactory;
private static readonly SemaphoreSlim _startLock = new(1, 1);
private const int LockTimeoutSeconds = 60;
@ -46,19 +47,20 @@ namespace CoreAgent.Infrastructure.Services.Network
INetworkStatusMonitor statusMonitor,
IWebSocketTransport webSocketTransport,
IProtocolLogObserver protocolLogObserver,
IProtocolWsClientManager protocolWsClientManager)
IProtocolWsClientManager protocolWsClientManager,
IServiceScopeManager serviceScopeManager,
IRanAPICommandHandlerFactory ranAPICommandHandlerFactory)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
_configService = configService ?? throw new ArgumentNullException(nameof(configService));
_context = context ?? throw new ArgumentNullException(nameof(context));
_configCopier = configCopier ?? throw new ArgumentNullException(nameof(configCopier));
_interfaceManager = interfaceManager ?? throw new ArgumentNullException(nameof(interfaceManager));
_statusMonitor = statusMonitor;
_webSocketTransport = webSocketTransport ?? throw new ArgumentNullException(nameof(webSocketTransport));
_protocolLogObserver = protocolLogObserver ?? throw new ArgumentNullException(nameof(protocolLogObserver));
_protocolWsClientManager = protocolWsClientManager ?? throw new ArgumentNullException(nameof(protocolWsClientManager));
_serviceScopeManager = serviceScopeManager ?? throw new ArgumentNullException(nameof(serviceScopeManager));
_ranAPICommandHandlerFactory = ranAPICommandHandlerFactory ?? throw new ArgumentNullException(nameof(ranAPICommandHandlerFactory));
}
/// <summary>
@ -197,7 +199,7 @@ namespace CoreAgent.Infrastructure.Services.Network
// 只有步骤1成功才继续执行后续步骤
var result = await ExecuteRemainingStepsAsync(config, key, startTime);
// 删除临时配置文件 - 无论成功还是失败都需要执行
var deleteResult = _configCopier.DeleteCellularNetworkConfigurationFile(config);
if (!deleteResult.IsSuccess)
@ -209,7 +211,7 @@ namespace CoreAgent.Infrastructure.Services.Network
{
_logger.LogInformation("临时配置文件删除成功");
}
return result;
}
@ -386,11 +388,14 @@ namespace CoreAgent.Infrastructure.Services.Network
var step12Duration = (DateTime.UtcNow - step12Start).TotalMilliseconds;
_logger.LogDebug("步骤12完成:启动所有协议客户端,耗时: {Duration}ms", step12Duration.ToString("F2"));
await SetBcchLogStatusAsync();
_logger.LogInformation("BCCH日志状态设置完成");
var endTime = DateTime.UtcNow;
var duration = endTime - startTime;
_logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功,当前状态: {Status},总耗时: {Duration}ms",
key, state.CurrentStatus, duration.TotalMilliseconds.ToString("F2"));
return CellularNetworkOperationResult.Success(state.CurrentStatus);
}
@ -423,7 +428,7 @@ namespace CoreAgent.Infrastructure.Services.Network
try
{
_logger.LogInformation("开始恢复网络状态");
// 1. 关闭WebSocket传输连接
try
{
@ -472,7 +477,7 @@ namespace CoreAgent.Infrastructure.Services.Network
try
{
_logger.LogInformation("开始启动所有协议客户端");
// 获取协议客户端配置
var protocolConfigs = protocolConfigFactory.GetAllConfigs();
if (protocolConfigs == null || protocolConfigs.Length == 0)
@ -481,9 +486,9 @@ namespace CoreAgent.Infrastructure.Services.Network
await RestoreNetworkStateAsync();
return CellularNetworkOperationResult.Failure("没有可用的协议客户端配置");
}
_logger.LogInformation("获取到 {ConfigCount} 个协议客户端配置", protocolConfigs.Length);
// 启动所有协议客户端
var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs);
if (!startResult)
@ -492,9 +497,9 @@ namespace CoreAgent.Infrastructure.Services.Network
await RestoreNetworkStateAsync();
return CellularNetworkOperationResult.Failure("部分协议客户端启动失败");
}
_logger.LogInformation("所有协议客户端启动完成,开始检查连接状态");
// 检查连接状态(使用默认10秒超时)
var connectionResult = _protocolWsClientManager.CheckAllClientsConnection();
if (!connectionResult)
@ -503,7 +508,7 @@ namespace CoreAgent.Infrastructure.Services.Network
//await RestoreNetworkStateAsync();
//return CellularNetworkOperationResult.Failure("协议客户端连接状态检查失败,部分客户端可能未连接");
}
_logger.LogInformation("所有协议客户端启动并连接成功");
return CellularNetworkOperationResult.Success(NetworkStatus.Connected);
}
@ -515,5 +520,51 @@ namespace CoreAgent.Infrastructure.Services.Network
}
}
/// <summary>
/// 设置BCCH日志状态
/// </summary>
/// <returns>任务</returns>
private async Task SetBcchLogStatusAsync()
{
try
{
// 使用工厂创建处理器实例
var ranApiCommandHandler = _ranAPICommandHandlerFactory.CreateHandler();
// 设置BCCH日志状态为true
_logger.LogInformation("开始设置BCCH日志状态为true");
var setTrueResult = await ranApiCommandHandler.SetBcchLogStatusAsync(true);
if (setTrueResult)
{
_logger.LogInformation("BCCH日志状态设置为true成功");
// 等待200秒
_logger.LogInformation("等待200秒后设置BCCH日志状态为false");
await Task.Delay(TimeSpan.FromSeconds(200));
// 设置BCCH日志状态为false
_logger.LogInformation("200秒后开始设置BCCH日志状态为false");
var setFalseResult = await ranApiCommandHandler.SetBcchLogStatusAsync(false);
if (setFalseResult)
{
_logger.LogInformation("BCCH日志状态设置为false成功");
}
else
{
_logger.LogWarning("BCCH日志状态设置为false失败");
}
}
else
{
_logger.LogWarning("BCCH日志状态设置为true失败");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置BCCH日志状态时发生异常");
}
}
}
}

564
CoreAgent.Infrastructure/Services/Network/RanAPICommandHandler.cs

@ -1,564 +0,0 @@
using CoreAgent.Domain.Interfaces.Network;
using CoreAgent.Domain.Interfaces.System.Command;
using CoreAgent.Domain.Models.Network;
using CoreAgent.Domain.Models.System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace CoreAgent.Infrastructure.Services.Network;
/// <summary>
/// RAN API 命令处理器实现
/// 负责处理各种RAN相关的API操作命令
/// </summary>
public class RanAPICommandHandler : RanAPICommandHandlerBase, IRanPowerControlHandler, IRanGainControlHandler
{
private readonly ILogger<RanAPICommandHandler> _logger;
public RanAPICommandHandler(
ILogger<RanAPICommandHandler> logger,
ISystemCommandExecutor commandExecutor,
IOptions<AppSettings> appSettings)
: base(commandExecutor, appSettings.Value)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// 设置 RAN 日志配置
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="enableBcch">是否启用BCCH日志</param>
/// <returns>是否成功设置配置</returns>
public override async Task<bool> SetRanLogsConfigAsync(RanIPEndPoint ranEndPoint, bool enableBcch)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
try
{
var configCommand = $@"{{""message"":""config_set"",""logs"":{{""bcch"":{enableBcch.ToString().ToLower()}}}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
_logger.LogInformation("开始设置RAN日志配置,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
var result = await ExecuteCommandAsync(command, "RAN日志配置设置");
if (result.IsSuccess)
{
_logger.LogInformation("RAN日志配置设置成功,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
return true;
}
else
{
_logger.LogWarning("RAN日志配置设置失败,地址: {ComAddr}, 启用BCCH: {EnableBcch}, 错误: {Error}",
ranEndPoint.ComAddr, enableBcch, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置RAN日志配置时发生异常,地址: {ComAddr}, 启用BCCH: {EnableBcch}", ranEndPoint.ComAddr, enableBcch);
return false;
}
}
#region 功率控制方法
/// <summary>
/// 设置发送功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerSettings">功率设置字典,key为端口号(int),value为功率值(double)</param>
/// <returns>是否成功设置功率</returns>
public async Task<bool> SetTxPowerAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> powerSettings)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (powerSettings == null || powerSettings.Count == 0)
{
_logger.LogWarning("功率设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = powerSettings.Count;
_logger.LogInformation("开始批量设置发送功率,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in powerSettings)
{
var port = setting.Key;
var setPower = setting.Value;
var cmd_setPower = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""tx_power"":{setPower},""tx_channel_index"":{port}}}'";
_logger.LogDebug("设置端口 {Port} 的发送功率值为 {SetPower}", port, setPower);
var result = await ExecuteCommandAsync(cmd_setPower, "发送功率设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 发送功率设置成功,功率值: {SetPower}", port, setPower);
}
else
{
_logger.LogWarning("端口 {Port} 发送功率设置失败,功率值: {SetPower}, 错误: {Error}",
port, setPower, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口发送功率设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口发送功率设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置发送功率时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置接收功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerSettings">功率设置字典,key为端口号(int),value为功率值(double)</param>
/// <returns>是否成功设置功率</returns>
public async Task<bool> SetRxPowerAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> powerSettings)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (powerSettings == null || powerSettings.Count == 0)
{
_logger.LogWarning("功率设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = powerSettings.Count;
_logger.LogInformation("开始批量设置接收功率,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in powerSettings)
{
var port = setting.Key;
var setPower = setting.Value;
var cmd_setPower = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""rx_power"":{setPower},""rx_channel_index"":{port}}}'";
_logger.LogDebug("设置端口 {Port} 的接收功率值为 {SetPower}", port, setPower);
var result = await ExecuteCommandAsync(cmd_setPower, "接收功率设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 接收功率设置成功,功率值: {SetPower}", port, setPower);
}
else
{
_logger.LogWarning("端口 {Port} 接收功率设置失败,功率值: {SetPower}, 错误: {Error}",
port, setPower, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口接收功率设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口接收功率设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置接收功率时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置所有端口的发送功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerValues">所有端口的功率值数组,按端口顺序排列</param>
/// <returns>是否成功设置功率</returns>
public async Task<bool> SetAllTxPowerAsync(RanIPEndPoint ranEndPoint, double[] powerValues)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (powerValues == null || powerValues.Length == 0)
{
_logger.LogWarning("功率值数组为空或无效");
return false;
}
try
{
var powerArrayJson = $"[{string.Join(",", powerValues)}]";
var cmd_setAllPower = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""tx_power"":{powerArrayJson}}}'";
_logger.LogInformation("开始设置所有端口发送功率,地址: {ComAddr}, 端口数量: {PortCount}, 功率值: {PowerValues}",
ranEndPoint.ComAddr, powerValues.Length, string.Join(",", powerValues));
var result = await ExecuteCommandAsync(cmd_setAllPower, "所有端口发送功率设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口发送功率设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, powerValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口发送功率设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, powerValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口发送功率时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, powerValues?.Length ?? 0);
return false;
}
}
/// <summary>
/// 设置所有端口的接收功率
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="powerValues">所有端口的功率值数组,按端口顺序排列</param>
/// <returns>是否成功设置功率</returns>
public async Task<bool> SetAllRxPowerAsync(RanIPEndPoint ranEndPoint, double[] powerValues)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (powerValues == null || powerValues.Length == 0)
{
_logger.LogWarning("功率值数组为空或无效");
return false;
}
try
{
var powerArrayJson = $"[{string.Join(",", powerValues)}]";
var cmd_setAllPower = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""rx_power"":{powerArrayJson}}}'";
_logger.LogInformation("开始设置所有端口接收功率,地址: {ComAddr}, 端口数量: {PortCount}, 功率值: {PowerValues}",
ranEndPoint.ComAddr, powerValues.Length, string.Join(",", powerValues));
var result = await ExecuteCommandAsync(cmd_setAllPower, "所有端口接收功率设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口接收功率设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, powerValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口接收功率设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, powerValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口接收功率时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, powerValues?.Length ?? 0);
return false;
}
}
#endregion
#region 增益控制方法
/// <summary>
/// 设置发送增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetTxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainSettings == null || gainSettings.Count == 0)
{
_logger.LogWarning("增益设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = gainSettings.Count;
_logger.LogInformation("开始批量设置发送增益,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in gainSettings)
{
var port = setting.Key;
var setGain = setting.Value;
var cmd_setGain = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""tx_gain"":{setGain},""tx_channel_index"":{port}}}'";
_logger.LogDebug("设置端口 {Port} 的发送增益值为 {SetGain}", port, setGain);
var result = await ExecuteCommandAsync(cmd_setGain, "发送增益设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 发送增益设置成功,增益值: {SetGain}", port, setGain);
}
else
{
_logger.LogWarning("端口 {Port} 发送增益设置失败,增益值: {SetGain}, 错误: {Error}",
port, setGain, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口发送增益设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口发送增益设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置发送增益时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置接收增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainSettings">增益设置字典,key为端口号(int),value为增益值(double)</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetRxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainSettings == null || gainSettings.Count == 0)
{
_logger.LogWarning("增益设置字典为空或无效");
return false;
}
try
{
var successCount = 0;
var totalCount = gainSettings.Count;
_logger.LogInformation("开始批量设置接收增益,地址: {ComAddr}, 端口数量: {PortCount}", ranEndPoint.ComAddr, totalCount);
foreach (var setting in gainSettings)
{
var port = setting.Key;
var setGain = setting.Value;
var cmd_setGain = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""rx_gain"":{setGain},""rx_channel_index"":{port}}}'";
_logger.LogDebug("设置端口 {Port} 的接收增益值为 {SetGain}", port, setGain);
var result = await ExecuteCommandAsync(cmd_setGain, "接收增益设置");
if (result.IsSuccess)
{
successCount++;
_logger.LogDebug("端口 {Port} 接收增益设置成功,增益值: {SetGain}", port, setGain);
}
else
{
_logger.LogWarning("端口 {Port} 接收增益设置失败,增益值: {SetGain}, 错误: {Error}",
port, setGain, result.Error);
}
}
var allSuccess = successCount == totalCount;
if (allSuccess)
{
_logger.LogInformation("所有端口接收增益设置成功,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
else
{
_logger.LogWarning("部分端口接收增益设置失败,地址: {ComAddr}, 成功数量: {SuccessCount}/{TotalCount}",
ranEndPoint.ComAddr, successCount, totalCount);
}
return allSuccess;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量设置接收增益时发生异常,地址: {ComAddr}", ranEndPoint.ComAddr);
return false;
}
}
/// <summary>
/// 设置所有端口的发送增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetAllTxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainValues == null || gainValues.Length == 0)
{
_logger.LogWarning("增益值数组为空或无效");
return false;
}
try
{
var gainArrayJson = $"[{string.Join(",", gainValues)}]";
var cmd_setAllGain = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""tx_gain"":{gainArrayJson}}}'";
_logger.LogInformation("开始设置所有端口发送增益,地址: {ComAddr}, 端口数量: {PortCount}, 增益值: {GainValues}",
ranEndPoint.ComAddr, gainValues.Length, string.Join(",", gainValues));
var result = await ExecuteCommandAsync(cmd_setAllGain, "所有端口发送增益设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口发送增益设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口发送增益设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, gainValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口发送增益时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues?.Length ?? 0);
return false;
}
}
/// <summary>
/// 设置所有端口的接收增益
/// </summary>
/// <param name="ranEndPoint">RAN 端点信息</param>
/// <param name="gainValues">所有端口的增益值数组,按端口顺序排列</param>
/// <returns>是否成功设置增益</returns>
public async Task<bool> SetAllRxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues)
{
if (!ValidateRanEndPoint(ranEndPoint))
{
_logger.LogWarning("RAN 端点未配置");
return false;
}
if (gainValues == null || gainValues.Length == 0)
{
_logger.LogWarning("增益值数组为空或无效");
return false;
}
try
{
var gainArrayJson = $"[{string.Join(",", gainValues)}]";
var cmd_setAllGain = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""rx_gain"":{gainArrayJson}}}'";
_logger.LogInformation("开始设置所有端口接收增益,地址: {ComAddr}, 端口数量: {PortCount}, 增益值: {GainValues}",
ranEndPoint.ComAddr, gainValues.Length, string.Join(",", gainValues));
var result = await ExecuteCommandAsync(cmd_setAllGain, "所有端口接收增益设置");
if (result.IsSuccess)
{
_logger.LogInformation("所有端口接收增益设置成功,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues.Length);
return true;
}
else
{
_logger.LogWarning("所有端口接收增益设置失败,地址: {ComAddr}, 端口数量: {PortCount}, 错误: {Error}",
ranEndPoint.ComAddr, gainValues.Length, result.Error);
return false;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "设置所有端口接收增益时发生异常,地址: {ComAddr}, 端口数量: {PortCount}",
ranEndPoint.ComAddr, gainValues?.Length ?? 0);
return false;
}
}
#endregion
}

675
modify.md

@ -2,6 +2,423 @@
## 2025-01-02
### 创建RanAPIController - 统一处理RAN API请求
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.API/Controllers/RanAPIController.cs` (新建)
**修改内容**:
1. **创建RanAPIController控制器**:
- 继承 `BaseApiController`,提供统一的API响应格式
- 使用 `IMediator` 处理命令,遵循CQRS模式
- 提供两个API端点:
- `POST /api/ranapi/set-tx-gain`: 设置指定端口的发送增益
- `POST /api/ranapi/set-all-tx-gain`: 设置所有端口的发送增益
2. **API端点设计**:
- **SetTxGain**: 接收 `Dictionary<int, double>` 格式的增益设置
- **SetAllTxGain**: 接收 `double[]` 格式的增益值数组
- 统一的错误处理和日志记录
- 完整的XML文档注释
3. **设计特点**:
- **统一控制器**: 两个命令处理器共用一个控制器
- **RESTful设计**: 使用POST方法,语义化的路由
- **异常处理**: 完整的异常捕获和错误响应
- **日志记录**: 详细的请求处理日志
**API使用示例**:
```http
# 设置指定端口的发送增益
POST /api/ranapi/set-tx-gain
Content-Type: application/json
{
"1": 1.5,
"2": 2.0,
"3": 1.8
}
# 设置所有端口的发送增益
POST /api/ranapi/set-all-tx-gain
Content-Type: application/json
[1.5, 2.0, 1.8, 2.2, 1.6, 1.9]
```
**影响范围**:
- 提供统一的RAN API访问接口
- 简化客户端调用方式
- 保持API设计的一致性
### 添加SetAllTxGainCommand - 实现批量发送增益设置
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Application/Commands/RanAPI/SetAllTxGainCommand.cs` (新建)
- `CoreAgent.Application/Handlers/RanAPI/SetAllTxGainCommandHandler.cs` (新建)
**修改内容**:
1. **创建SetAllTxGainCommand命令类**:
- 包含 `double[]` 类型的 `GainValues` 属性,用于设置所有端口的增益值
- 添加构造函数参数验证,确保参数不为空
- 使用强类型属性,提供完整的XML文档注释
2. **创建SetAllTxGainCommandHandler处理器类**:
- 实现 `IRequestHandler<SetAllTxGainCommand, ApiActionResult<bool>>` 接口
- 使用工厂模式获取 `IRanGainControlHandler` 实例
- 调用 `SetAllTxGainAsync` 方法执行批量增益设置
- 添加完整的异常处理和日志记录
3. **设计特点**:
- **批量操作**: 一次命令设置所有端口的增益值,提高效率
- **工厂模式**: 使用 `IRanAPICommandHandlerFactory` 获取处理器实例
- **统一设计**: 与 `SetTxGainCommandHandler` 保持相同的设计模式
- **错误处理**: 完整的异常处理和错误码定义
**使用示例**:
```csharp
// 设置6个端口的发送增益
var gainValues = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
var command = new SetAllTxGainCommand(gainValues);
var result = await mediator.Send(command);
```
**影响范围**:
- 新增批量发送增益设置功能
- 提供高效的端口配置方式
- 保持与现有命令处理器的一致性
### 重构IRanGainControlHandler接口设计 - 统一端点获取模式
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Domain/Interfaces/Network/IRanGainControlHandler.cs`
- `CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandler.cs`
- `CoreAgent.Application/Commands/RanAPI/SetTxGainCommand.cs`
- `CoreAgent.Application/Handlers/RanAPI/SetTxGainCommandHandler.cs`
- `CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs`
**重构原因**:
- `IRanGainControlHandler` 接口设计不合理,每次调用都需要传递 `RanIPEndPoint` 参数
- `SetBcchLogStatusAsync` 方法已经采用从 `ICellularNetworkContext` 获取端点信息的模式
- 需要统一接口设计,简化调用方式,提高一致性
**修改内容**:
1. **重构IRanGainControlHandler接口**:
- 移除所有方法的 `RanIPEndPoint` 参数
- 统一采用从 `ICellularNetworkContext` 获取端点信息的模式
- 简化方法签名,提高接口一致性
2. **更新实现类**:
- 所有增益控制方法内部从 `_context.NetworkIPEndPointManager.GetRanEndPoint()` 获取端点信息
- 保持与 `SetBcchLogStatusAsync` 方法相同的设计模式
- 统一错误处理和日志记录方式
3. **简化命令类**:
- 移除 `SetTxGainCommand` 中的 `RanEndPoint` 属性
- 简化构造函数,只需要 `gainSettings` 参数
- 减少不必要的参数传递
4. **优化命令处理器**:
- 移除对 `RanEndPoint` 的日志记录
- 简化方法调用,直接传递 `gainSettings` 参数
- 保持错误处理和返回结果的一致性
5. **依赖注入优化**:
- 移除直接注册的 `IRanGainControlHandler`
- 统一使用工厂模式获取处理器实例
- 确保设计一致性和生命周期管理
**设计优势**:
- **接口一致性**: 所有RAN API方法都采用相同的端点获取模式
- **简化调用**: 客户端代码不需要关心端点获取细节
- **统一设计**: 与 `SetBcchLogStatusAsync` 保持相同的设计模式
- **减少参数**: 简化方法签名,减少参数传递
- **生命周期匹配**: 使用瞬时生命周期,与依赖的服务保持一致
**影响范围**:
- 统一了RAN API接口的设计模式
- 简化了客户端代码的调用方式
- 提高了接口的一致性和可维护性
- 统一使用工厂模式,确保设计一致性
### 修复GeneralCellularNetworkService.cs缺少Microsoft.Extensions.DependencyInjection引用
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs`
**修改内容**:
1. **添加缺失的using指令**:
- 添加 `using Microsoft.Extensions.DependencyInjection;` 引用
- 解决 `IServiceProvider` 没有 `GetRequiredService` 方法定义的问题
2. **修复编译错误**:
- 错误信息:`"IServiceProvider"未包含"GetRequiredService"的定义,并且找不到可接受第一个"IServiceProvider"类型参数的可访问扩展方法`
- 在第544行使用 `serviceProvider.GetRequiredService<IRanAPICommandHandler>()` 时需要该引用
3. **具体修复**:
```csharp
// 添加的using指令
using Microsoft.Extensions.DependencyInjection;
```
4. **设计优势**:
- **编译错误修复**:解决缺少扩展方法引用的编译错误
- **依赖注入支持**:正确支持服务提供者的扩展方法
- **代码完整性**:确保所有必要的引用都已包含
**影响范围**:
- 编译错误的修复
- 依赖注入功能的正常使用
- 代码的编译和运行
### 修改CellularNetworkService - 添加RAN日志配置自动设置功能
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs`
**修改内容**:
1. **添加服务作用域管理器依赖**:
- 在构造函数中添加 `IServiceScopeManager` 参数
- 添加私有字段 `_serviceScopeManager` 用于在单例服务中创建瞬时服务
2. **扩展协议客户端启动流程**:
- 在步骤12(启动所有协议客户端)后添加步骤13(设置RAN日志配置)
- 新增 `SetRanLogsConfigAsync` 方法实现RAN日志配置的自动设置
3. **实现RAN日志配置自动设置逻辑**:
- 使用 `IServiceScopeManager` 获取 `IRanAPICommandHandler` 实例
- 在协议客户端启动后立即调用 `SetRanLogsConfigAsync(ranEndPoint, true)` 启用BCCH日志
- 直接等待200秒后调用 `SetRanLogsConfigAsync(ranEndPoint, false)` 禁用BCCH日志
- 使用同步等待方式,确保操作按顺序执行
4. **错误处理和日志记录**:
- 添加完整的异常处理,确保RAN日志配置设置失败不会影响网络启动流程
- 详细记录每个步骤的执行状态和结果
- 记录RAN端点地址信息便于调试
5. **设计优势**:
- **自动化**: 无需手动干预,系统自动管理RAN日志配置
- **顺序执行**: 使用同步等待确保操作按预期顺序执行
- **容错性**: RAN日志配置设置失败不会导致网络启动失败
- **可观测性**: 完整的日志记录便于监控和调试
- **生命周期管理**: 正确使用服务作用域管理器管理瞬时服务
6. **使用示例**:
```csharp
// 网络启动时会自动执行以下流程:
// 1. 启动所有协议客户端
// 2. 设置RAN日志配置为true
// 3. 等待200秒
// 4. 设置RAN日志配置为false
```
**影响范围**:
- 蜂窝网络启动流程的完整性
- RAN日志配置的自动化管理
- 服务依赖注入的生命周期管理
### 添加服务作用域管理器
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Domain/Interfaces/Common/IServiceScopeManager.cs` (新增)
- `CoreAgent.Infrastructure/Services/Common/ServiceScopeManager.cs` (新增)
- `CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs`
- `CoreAgent.Application/Handlers/CellularNetwork/GetCellularNetworkStatusCommandHandler.cs`
- `CoreAgent.Application/Handlers/RanAPI/SetTxGainCommandHandler.cs`
- `CoreAgent.Domain/Interfaces/Network/ICellularNetworkService.cs`
- `CoreAgent.Domain/Interfaces/Network/INetworkStatusMonitor.cs`
- `CoreAgent.Domain/Models/Network/NetworkInterfaceStatus.cs` (新增)
- `CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs`
- `CoreAgent.Infrastructure/Services/Network/NetworkStatusMonitor.cs`
**修复问题**:
- 添加了缺失的 `IRanGainControlHandler``IRanAPICommandHandler` 服务注册
- 添加了 `CoreAgent.Infrastructure.Handlers.API` 命名空间的引用
- 修复了 `SetTxGainCommandHandler` 中缺少 `Microsoft.Extensions.DependencyInjection` using 指令的问题
- 移除了不必要的 `RanAPICommandHandlerBase` 抽象基类注册
- 添加了缺失的 `IServiceScopeManager` 服务注册
- 添加了 `CoreAgent.Domain.Interfaces.Common``CoreAgent.Infrastructure.Services.Common` 命名空间的引用
- 简化了 `SetTxGainCommandHandler`,直接注入 `IRanGainControlHandler` 而不是使用 `IServiceScopeManager`
**修改内容**:
1. **创建服务作用域管理器**
- 在 `CoreAgent.Domain/Interfaces/Common/` 下创建 `IServiceScopeManager` 接口定义作用域管理方法
- 在 `CoreAgent.Infrastructure/Services/Common/` 下创建 `ServiceScopeManager` 实现类
- 支持同步和异步操作,有返回值和无返回值的方法
- **遵循依赖倒置原则**:接口定义在Domain层,实现放在Infrastructure层
2. **注册服务作用域管理器**
- 在 `CommandServiceExtensions` 中注册为单例服务
- 确保可以在单例服务中安全使用
- 添加了缺失的 `IRanGainControlHandler``IRanAPICommandHandler` 服务注册
3. **扩展接口和模型**
- 为 `ICellularNetworkService` 添加 `GetStatusAsync` 方法
- 为 `INetworkStatusMonitor` 添加 `CheckInterfaceStatusAsync` 方法
- 创建 `NetworkInterfaceStatus` 模型用于返回接口状态信息
4. **实现具体功能**
- 在 `CellularNetworkService` 中实现 `GetStatusAsync` 方法
- 在 `NetworkStatusMonitor` 中实现 `CheckInterfaceStatusAsync` 方法
- 提供完整的网络状态查询功能
5. **修改命令处理器**
- 修改 `GetCellularNetworkStatusCommandHandler` 使用服务作用域管理器
- 修改 `SetTxGainCommandHandler` 使用服务作用域管理器
- 展示如何在单例服务中创建瞬时服务
6. **设计优势**:
- **类型安全**:编译时检查,避免运行时错误
- **资源管理**:自动使用 `using` 语句管理作用域生命周期
- **异常处理**:统一的异常处理和日志记录
- **易于使用**:简洁的API,支持同步和异步操作
- **可重用**:可以在任何需要的地方使用
- **线程安全**:每次调用都创建新的作用域
7. **使用示例**:
```csharp
// 异步操作,有返回值
var result = await _scopeManager.ExecuteInScopeAsync(async (sp) =>
{
var service1 = sp.GetRequiredService<IScopedService1>();
var service2 = sp.GetRequiredService<IScopedService2>();
return await service1.DoSomethingAsync(service2);
});
// 同步操作,无返回值
_scopeManager.ExecuteInScope((sp) =>
{
var service = sp.GetRequiredService<IScopedService>();
service.DoSomething();
});
```
**影响范围**:
- 单例服务中创建瞬时服务的能力
- 依赖注入的生命周期管理
- 命令处理器的服务访问方式
- 网络状态查询功能的完整性
- 代码的可维护性和可读性
- 服务作用域的统一管理
- **架构设计原则的遵循**:依赖倒置原则,Domain层定义接口,Infrastructure层实现
### CoreAgent.Application.Handlers 实现 RanAPICommandHandler 的 SetTxGainAsync 方法
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Application/Commands/RanAPI/SetTxGainCommand.cs` (新建)
- `CoreAgent.Application/Handlers/RanAPI/SetTxGainCommandHandler.cs` (新建)
**修改内容**:
1. **创建 SetTxGainCommand 命令类**:
- 在 `CoreAgent.Application/Commands/RanAPI/` 目录下创建 `SetTxGainCommand.cs`
- 包含 `RanIPEndPoint` 类型的 `RanEndPoint` 属性
- 包含 `Dictionary<int, double>` 类型的 `GainSettings` 属性,key为端口号,value为增益值
- 添加构造函数参数验证,确保参数不为空
- 使用强类型属性,提供完整的XML文档注释
2. **创建 SetTxGainCommandHandler 处理器类**:
- 在 `CoreAgent.Application/Handlers/RanAPI/` 目录下创建 `SetTxGainCommandHandler.cs`
- 实现 `IRequestHandler<SetTxGainCommand, bool>` 接口,使用 MediatR 模式
- 注入 `IRanGainControlHandler` 依赖,用于实际执行增益设置操作
- 注入 `ILogger<SetTxGainCommandHandler>` 依赖,用于日志记录
- 在 `Handle` 方法中调用 `_ranGainControlHandler.SetTxGainAsync` 执行具体操作
- 添加完整的异常处理和日志记录
3. **具体实现**:
```csharp
// SetTxGainCommand.cs
public class SetTxGainCommand
{
public RanIPEndPoint RanEndPoint { get; }
public Dictionary<int, double> GainSettings { get; }
public SetTxGainCommand(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings)
{
RanEndPoint = ranEndPoint ?? throw new ArgumentNullException(nameof(ranEndPoint));
GainSettings = gainSettings ?? throw new ArgumentNullException(nameof(gainSettings));
}
}
// SetTxGainCommandHandler.cs
public class SetTxGainCommandHandler : IRequestHandler<SetTxGainCommand, bool>
{
private readonly IRanGainControlHandler _ranGainControlHandler;
private readonly ILogger<SetTxGainCommandHandler> _logger;
public SetTxGainCommandHandler(
IRanGainControlHandler ranGainControlHandler,
ILogger<SetTxGainCommandHandler> logger)
{
_ranGainControlHandler = ranGainControlHandler ?? throw new ArgumentNullException(nameof(ranGainControlHandler));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<bool> Handle(SetTxGainCommand request, CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("开始处理设置发送增益命令,RAN地址: {ComAddr}, 端口数量: {PortCount}",
request.RanEndPoint.ComAddr, request.GainSettings.Count);
var result = await _ranGainControlHandler.SetTxGainAsync(request.RanEndPoint, request.GainSettings);
if (result)
{
_logger.LogInformation("设置发送增益命令处理成功,RAN地址: {ComAddr}", request.RanEndPoint.ComAddr);
}
else
{
_logger.LogWarning("设置发送增益命令处理失败,RAN地址: {ComAddr}", request.RanEndPoint.ComAddr);
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "处理设置发送增益命令时发生异常,RAN地址: {ComAddr}", request.RanEndPoint.ComAddr);
return false;
}
}
}
```
4. **设计优势**:
- **职责分离**: 命令类负责数据封装,处理器类负责业务逻辑
- **依赖注入**: 使用依赖注入模式,便于测试和扩展
- **异常处理**: 完整的异常捕获和日志记录
- **参数验证**: 构造函数中进行参数验证,确保数据有效性
- **日志详细**: 提供详细的处理过程日志,便于调试和监控
- **类型安全**: 使用强类型属性,避免类型错误
- **MediatR模式**: 使用标准的CQRS模式,便于扩展和维护
5. **使用方式**:
```csharp
// 在控制器或服务中使用
var command = new SetTxGainCommand(ranEndPoint, gainSettings);
var result = await _mediator.Send(command);
```
**影响范围**:
- RAN API命令处理的应用层架构
- CQRS模式的实现
- 依赖注入配置(需要注册新的Handler)
- 代码组织结构的规范化
- 单元测试的便利性
### 优化RanAPICommandHandler SetTxGainAsync方法 - 使用字典结构
**修改时间**: 2025年1月2日
@ -18277,6 +18694,103 @@ feat: 优化NetworkProtocolLogObserver并发处理和ProtocolWsClientManager资
## 2025-01-02
### 使用工厂模式解决 IRanAPICommandHandler 依赖注入问题
**修改时间**: 2025年1月2日
**修改文件**:
- `CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandlerFactory.cs` (新建)
- `CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandlerFactory.cs` (新建)
- `CoreAgent.Domain/Interfaces/Network/IRanAPICommandHandler.cs`
- `CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandler.cs`
- `CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs`
- `CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs`
**解决的问题**:
1. **生命周期不匹配问题**:
- 原问题:`ISystemCommandExecutor` 注册为 `AddTransient`,`IRanAPICommandHandler` 注册为 `AddScoped`
- 解决方案:保持原有生命周期设计,通过工厂模式管理实例创建
2. **依赖注入设计问题**:
- 原问题:`IRanAPICommandHandler` 所有方法都需要传递 `RanIPEndPoint` 参数,但可以从 `ICellularNetworkContext` 获取
- 解决方案:使用工厂模式,让工厂可以访问 `ICellularNetworkContext`,简化接口设计
**修改内容**:
1. **新建工厂接口**:
- 创建 `IRanAPICommandHandlerFactory` 接口
- 提供 `CreateHandler()``CreateGainControlHandler()` 方法
2. **新建工厂实现**:
- 创建 `RanAPICommandHandlerFactory` 实现类
- 工厂依赖 `ICellularNetworkContext`,可以访问单例服务
- 负责创建和配置 `RanAPICommandHandler` 实例
3. **接口设计简化**:
- 移除 `SetBcchLogStatusAsync` 方法的 `RanIPEndPoint` 参数
- 方法签名简化为:`Task<bool> SetBcchLogStatusAsync(bool enableBcch)`
4. **实现类增强**:
- 构造函数添加 `ICellularNetworkContext` 参数
- `SetBcchLogStatusAsync` 方法内部从上下文获取端点信息
- 简化方法调用,无需传递端点参数
5. **调用方简化**:
- `GeneralCellularNetworkService` 依赖工厂而非直接依赖处理器
- 使用工厂创建处理器实例
- 简化方法调用,无需获取和传递端点信息
6. **依赖注入优化**:
- 注册工厂而非直接注册处理器
- 工厂管理处理器的创建和依赖注入
**设计优势**:
1. **工厂模式优势**: 工厂负责创建复杂对象,封装创建逻辑
2. **简化接口**: 方法签名更简洁,不需要传递端点参数
3. **正确的生命周期管理**: 工厂可以安全地依赖单例服务
4. **减少重复代码**: 端点获取逻辑封装在处理器内部
5. **更好的封装**: 客户端代码不需要关心端点获取细节
6. **易于扩展**: 可以轻松添加新的处理器类型
**工厂模式实现**:
```csharp
// 工厂接口
public interface IRanAPICommandHandlerFactory
{
IRanAPICommandHandler CreateHandler();
IRanGainControlHandler CreateGainControlHandler();
}
// 工厂实现
public class RanAPICommandHandlerFactory : IRanAPICommandHandlerFactory
{
private readonly ICellularNetworkContext _context;
// ... 其他依赖
public IRanAPICommandHandler CreateHandler()
{
return new RanAPICommandHandler(_logger, _commandExecutor, _appSettings, _context);
}
}
// 使用方式
var handler = _factory.CreateHandler();
await handler.SetBcchLogStatusAsync(true); // 不需要传递端点参数
```
**影响范围**:
- RAN API命令处理器的创建和管理
- 依赖注入配置的架构设计
- 通用蜂窝网络服务中的BCCH日志状态管理
- 接口设计的简化和优化
**向后兼容性**:
- 接口签名简化,调用方需要更新
- 功能逻辑完全保持不变,只是简化了使用方式
- 依赖注入配置变更,使用工厂模式
### 添加SetTxGainAsync方法 - 实现发送增益设置接口
**修改时间**: 2025年1月2日
@ -18346,3 +18860,164 @@ feat: 优化NetworkProtocolLogObserver并发处理和ProtocolWsClientManager资
- 发送增益设置功能
- 接口定义的完整性
## 2024-12-19 - RanAPICommandHandler 命令构建方式统一
**修改文件**:
- `CoreAgent.Infrastructure/Services/Network/RanAPICommandHandler.cs`
**修改内容**:
1. **命令构建方式统一**:
- 将所有方法的命令构建方式统一为与 `SetRanLogsConfigAsync` 一致的模式
- 使用 `configCommand` 变量存储JSON配置,然后通过 `command` 变量构建完整命令
2. **修改的方法**:
- `SetTxPowerAsync`: 发送功率设置
- `SetRxPowerAsync`: 接收功率设置
- `SetAllTxPowerAsync`: 所有端口发送功率设置
- `SetAllRxPowerAsync`: 所有端口接收功率设置
- `SetTxGainAsync`: 发送增益设置
- `SetRxGainAsync`: 接收增益设置
- `SetAllTxGainAsync`: 所有端口发送增益设置
- `SetAllRxGainAsync`: 所有端口接收增益设置
3. **修改模式**:
```csharp
// 修改前
var cmd_setPower = $"{BuildCommandPrefix(ranEndPoint)} '{{""message"":""rf"",""rx_power"":{setPower},""rx_channel_index"":{port}}}'";
var result = await ExecuteCommandAsync(cmd_setPower, "接收功率设置");
// 修改后
var configCommand = $@"{{""message"":""rf"",""rx_power"":{setPower},""rx_channel_index"":{port}}}";
var command = $"{BuildCommandPrefix(ranEndPoint)} '{configCommand}'";
var result = await ExecuteCommandAsync(command, "接收功率设置");
```
4. **优势**:
- **代码一致性**: 所有方法使用相同的命令构建模式
- **可读性提升**: JSON配置单独构建,更清晰易读
- **维护性**: 统一的模式便于后续维护和修改
- **错误减少**: 避免因命令构建方式不一致导致的错误
5. **影响范围**:
- RAN API命令处理器的所有功率和增益控制方法
- 命令构建逻辑的统一化
- 代码风格的一致性改进
**技术细节**:
- 使用 `@` 字符串字面量避免转义字符问题
- 保持原有的参数验证和错误处理逻辑
- 保持原有的日志记录格式和内容
## 2024-12-19 - 移除功率控制功能,只保留增益控制
**修改文件**:
- `CoreAgent.Domain/Interfaces/Network/IRanPowerControlHandler.cs` (删除)
- `CoreAgent.Domain/Interfaces/Network/IRanGainControlHandler.cs`
- `CoreAgent.Infrastructure/Services/Network/RanAPICommandHandler.cs`
**修改内容**:
1. **删除功率控制接口**:
- 删除 `IRanPowerControlHandler.cs` 文件
- 移除所有功率控制相关的方法定义
2. **完善增益控制接口**:
- 在 `IRanGainControlHandler` 接口中添加所有增益控制方法定义:
- `SetTxGainAsync`: 设置发送增益
- `SetRxGainAsync`: 设置接收增益
- `SetAllTxGainAsync`: 设置所有端口发送增益
- `SetAllRxGainAsync`: 设置所有端口接收增益
3. **修改实现类**:
- 移除 `RanAPICommandHandler``IRanPowerControlHandler` 的继承
- 删除所有功率控制方法:
- `SetTxPowerAsync`
- `SetRxPowerAsync`
- `SetAllTxPowerAsync`
- `SetAllRxPowerAsync`
- 保留所有增益控制方法
4. **接口定义**:
```csharp
public interface IRanGainControlHandler
{
Task<bool> SetTxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings);
Task<bool> SetRxGainAsync(RanIPEndPoint ranEndPoint, Dictionary<int, double> gainSettings);
Task<bool> SetAllTxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues);
Task<bool> SetAllRxGainAsync(RanIPEndPoint ranEndPoint, double[] gainValues);
}
```
5. **实现类继承**:
```csharp
public class RanAPICommandHandler : RanAPICommandHandlerBase, IRanGainControlHandler
```
6. **功能范围**:
- **保留功能**: 增益控制(tx_gain, rx_gain)
- **移除功能**: 功率控制(tx_power, rx_power)
- **保留功能**: RAN日志配置
**影响范围**:
- 简化了RAN API命令处理器的功能范围
- 移除了不存在的功率控制功能
- 专注于增益控制功能
- 减少了代码复杂度和维护成本
## 2024-12-19 - 重构RanAPICommandHandler目录结构
**修改文件**:
- `CoreAgent.Infrastructure/Services/Network/RanAPICommandHandler.cs` (移动)
- `CoreAgent.Infrastructure/Handlers/API/RanAPICommandHandler.cs` (新位置)
- `CoreAgent.Infrastructure/Extensions/ServiceCollection/CommandServiceExtensions.cs`
**修改内容**:
1. **目录结构重构**:
- 创建新的目录结构:`CoreAgent.Infrastructure/Handlers/API/`
- 将 `RanAPICommandHandler``Services.Network` 移动到 `Handlers.API`
- 更合理的文件组织,避免在Network目录下放置API处理器
2. **命名空间更新**:
```csharp
// 修改前
namespace CoreAgent.Infrastructure.Services.Network;
// 修改后
namespace CoreAgent.Infrastructure.Handlers.API;
```
3. **依赖注入配置**:
- 在 `CommandServiceExtensions.cs` 中添加新的using语句
- 注册 `RanAPICommandHandler` 服务:
```csharp
services.AddScoped<IRanAPICommandHandler, RanAPICommandHandler>();
services.AddScoped<IRanGainControlHandler, RanAPICommandHandler>();
```
4. **目录结构优势**:
- **职责分离**: Handlers目录专门用于存放各种处理器
- **结构清晰**: API处理器与Network服务分离
- **易于扩展**: 未来可以添加其他类型的API处理器
- **命名规范**: 避免在Network目录下放置非Network相关的处理器
5. **新的目录结构**:
```
CoreAgent.Infrastructure/
├── Handlers/
│ └── API/
│ └── RanAPICommandHandler.cs
├── Services/
│ └── Network/
│ └── (其他Network相关服务)
└── Extensions/
└── ServiceCollection/
└── CommandServiceExtensions.cs
```
**影响范围**:
- 改进了项目的目录组织结构
- 提高了代码的可维护性和可读性
- 为未来的API处理器扩展提供了良好的基础
- 符合单一职责原则的目录设计
Loading…
Cancel
Save