Files
Ayay/SHH.CameraService/Core/CommandDispatcher.cs

66 lines
2.5 KiB
C#

using Newtonsoft.Json.Linq;
using SHH.Contracts.Grpc;
namespace SHH.CameraService;
/// <summary>
/// gRPC 指令分发器
/// 职责:接收从 GrpcCommandReceiverWorker 传入的 Proto 消息,解析参数并路由至具体的 Handler。
/// </summary>
public class CommandDispatcher
{
private readonly Dictionary<string, ICommandHandler> _handlers;
/// <summary>
/// 构造函数:通过 DI 注入所有已注册的处理器 (SyncCameraHandler, RemoveCameraHandler 等)
/// </summary>
public CommandDispatcher(IEnumerable<ICommandHandler> handlers)
{
// 将处理器列表转换为字典,方便 O(1) 查询
_handlers = handlers.ToDictionary(
h => h.ActionName,
h => h,
StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// 执行指令分发
/// </summary>
/// <param name="protoMsg">从 gRPC Server Streaming 接收到的原始 Proto 指令对象</param>
public async Task DispatchAsync(CommandPayloadProto protoMsg)
{
if (protoMsg == null) return;
string cmdCode = protoMsg.CmdCode; // 例如 "Sync_Camera"
Console.WriteLine($"[Dispatcher] 收到远程指令: {cmdCode}, 请求ID: {protoMsg.RequestId}");
try
{
// 1. 查找对应的处理器
if (_handlers.TryGetValue(cmdCode, out var handler))
{
// 2. 参数转换:将 Proto 里的 JSON 字符串转换为原有 Handler 需要的 JToken
// 这样你之前的 SyncCameraHandler 代码不需要做任何逻辑改动即可直接复用
var jsonStr = string.IsNullOrWhiteSpace(protoMsg.JsonParams) ? "{}" : protoMsg.JsonParams;
var token = JToken.Parse(jsonStr);
// 3. 调用具体业务执行
await handler.ExecuteAsync(token);
Console.WriteLine($"[Dispatcher] 指令 {cmdCode} 执行成功。");
}
else
{
Console.WriteLine($"[Dispatcher Warning] 未找到指令处理器: {cmdCode}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[Dispatcher Error] 执行指令 {cmdCode} 异常: {ex.Message}");
}
// 注意:关于 ACK (require_ack)
// 在 NetMQ 时代需要手动回发结果,在 gRPC Server Streaming 模式下,
// 建议通过 Unary RPC (例如另设一个 ReportCommandResult 方法) 异步上报执行结果。
}
}