using Newtonsoft.Json.Linq; using SHH.Contracts.Grpc; namespace SHH.CameraService; /// /// gRPC 指令分发器 /// 职责:接收从 GrpcCommandReceiverWorker 传入的 Proto 消息,解析参数并路由至具体的 Handler。 /// public class CommandDispatcher { private readonly Dictionary _handlers; /// /// 构造函数:通过 DI 注入所有已注册的处理器 (SyncCameraHandler, RemoveCameraHandler 等) /// public CommandDispatcher(IEnumerable handlers) { // 将处理器列表转换为字典,方便 O(1) 查询 _handlers = handlers.ToDictionary( h => h.ActionName, h => h, StringComparer.OrdinalIgnoreCase); } /// /// 执行指令分发 /// /// 从 gRPC Server Streaming 接收到的原始 Proto 指令对象 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 方法) 异步上报执行结果。 } }