Files
Ayay/SHH.CameraService/Core/CmdClients/CommandClientWorker.cs
wilson 3351ae739e 在 AiVideo 中能看到图像
增加了在线状态同步逻辑
2026-01-09 12:30:36 +08:00

154 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using MessagePack;
using Microsoft.Extensions.Hosting;
using NetMQ;
using NetMQ.Sockets;
using SHH.CameraSdk;
using SHH.Contracts;
using System.Text;
namespace SHH.CameraService;
public class CommandClientWorker : BackgroundService
{
private readonly ServiceConfig _config;
private readonly CommandDispatcher _dispatcher;
// ★ 1. 注入拦截器管道管理器
private readonly InterceptorPipeline _pipeline;
public CommandClientWorker(
ServiceConfig config,
CommandDispatcher dispatcher,
InterceptorPipeline pipeline) // <--- 注入
{
_config = config;
_dispatcher = dispatcher;
_pipeline = pipeline;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield();
if (!_config.ShouldConnect) return;
if (_config.CommandEndpoints.Count == 0) return;
using var dealer = new DealerSocket();
string myIdentity = _config.AppId;
dealer.Options.Identity = Encoding.UTF8.GetBytes(myIdentity);
foreach (var ep in _config.CommandEndpoints)
{
try { dealer.Connect(ep.Uri); }
catch (Exception ex) { Console.WriteLine($"[指令] 连接失败 {ep.Uri}: {ex.Message}"); }
}
string localIp = "127.0.0.1";
// ... (获取 IP 代码省略,保持不变) ...
// =================================================================
// 构建注册包
// =================================================================
var registerPayload = new RegisterPayload
{
Protocol = ProtocolHeaders.ServerRegister,
InstanceId = _config.AppId,
ProcessId = Environment.ProcessId,
Version = "1.0.0",
ServerIp = localIp,
WebApiPort = _config.BasePort,
StartTime = DateTime.Now
};
try
{
byte[] regData = MessagePackSerializer.Serialize(registerPayload);
// =============================================================
// ★ 2. 拦截点 A: 发送注册包 (Outbound)
// =============================================================
var ctx = await _pipeline.ExecuteSendAsync(ProtocolHeaders.ServerRegister, regData);
if (ctx != null) // 如果未被拦截
{
// 注意:这里使用 ctx.Protocol 和 ctx.Data允许拦截器修改内容
dealer.SendMoreFrame(ctx.Protocol)
.SendFrame(ctx.Data);
Console.WriteLine($"[指令] 注册包已发送 ({ctx.Data.Length} bytes)");
}
}
catch (Exception ex)
{
Console.WriteLine($"[致命错误] 注册流程异常: {ex.Message}");
return;
}
// =================================================================
// 定义 ACK 发送逻辑 (包含拦截器)
// =================================================================
// 注意:这里需要 async因为拦截器是异步的
Action<CommandResult> sendAckHandler = async (result) =>
{
try
{
byte[] resultBytes = MessagePackSerializer.Serialize(result);
// =========================================================
// ★ 3. 拦截点 B: 发送 ACK 回执 (Outbound)
// =========================================================
// 协议头是 COMMAND_RESULT
var ctx = await _pipeline.ExecuteSendAsync(ProtocolHeaders.CommandResult, resultBytes);
if (ctx != null)
{
dealer.SendMoreFrame(ctx.Protocol)
.SendFrame(ctx.Data);
Console.WriteLine($"[指令] 已回复 ACK -> Req: {result.RequestId}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[ACK Error] 回执发送失败: {ex.Message}");
}
};
// 订阅事件 (需要适配 async void注意异常捕获)
_dispatcher.OnResponseReady += async (res) => await Task.Run(() => sendAckHandler(res));
// =================================================================
// 接收循环
// =================================================================
try
{
while (!stoppingToken.IsCancellationRequested)
{
NetMQMessage incomingMsg = new NetMQMessage();
if (dealer.TryReceiveMultipartMessage(TimeSpan.FromMilliseconds(500), ref incomingMsg))
{
if (incomingMsg.FrameCount >= 2)
{
string rawProtocol = incomingMsg[0].ConvertToString();
byte[] rawData = incomingMsg[1].ToByteArray();
// =================================================
// ★ 4. 拦截点 C: 接收指令 (Inbound)
// =================================================
var ctx = await _pipeline.ExecuteReceiveAsync(rawProtocol, rawData);
if (ctx != null) // 如果未被拦截
{
// 将处理后的数据交给 Dispatcher
await _dispatcher.DispatchAsync(ctx.Protocol, ctx.Data);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"[指令] 接收循环异常: {ex.Message}");
}
}
}