66 lines
2.5 KiB
C#
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 方法) 异步上报执行结果。
|
|
}
|
|
} |