97 lines
3.4 KiB
C#
97 lines
3.4 KiB
C#
|
|
using Microsoft.Extensions.Hosting;
|
|||
|
|
using NetMQ;
|
|||
|
|
using NetMQ.Sockets;
|
|||
|
|
using Newtonsoft.Json;
|
|||
|
|
using SHH.CameraSdk;
|
|||
|
|
using System.Text;
|
|||
|
|
|
|||
|
|
namespace SHH.CameraService;
|
|||
|
|
|
|||
|
|
public class CommandClientWorker : BackgroundService
|
|||
|
|
{
|
|||
|
|
private readonly ServiceConfig _config;
|
|||
|
|
|
|||
|
|
public CommandClientWorker(ServiceConfig config)
|
|||
|
|
{
|
|||
|
|
_config = config;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|||
|
|
{
|
|||
|
|
// 1. 如果不是主动/混合模式,不需要连接
|
|||
|
|
if (!_config.ShouldConnect) return;
|
|||
|
|
|
|||
|
|
// ★★★ 核心修正:直接读取解析好的指令地址列表 ★★★
|
|||
|
|
// 这些地址来自参数 --uris "IP,VideoPort&CommandPort" 中的 CommandPort 部分
|
|||
|
|
var cmdUris = _config.CommandEndpoints;
|
|||
|
|
|
|||
|
|
if (cmdUris.Count == 0)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine("[指令] 未在参数中找到指令通道地址(位于&符号右侧),跳过连接。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 初始化 Dealer Socket
|
|||
|
|
using var dealer = new DealerSocket();
|
|||
|
|
|
|||
|
|
// 设置身份 (Identity),让 Dashboard 知道我是 "CameraApp_01"
|
|||
|
|
string myIdentity = _config.AppId;
|
|||
|
|
dealer.Options.Identity = Encoding.UTF8.GetBytes(myIdentity);
|
|||
|
|
|
|||
|
|
// 3. 连接所有目标 (支持多点控制)
|
|||
|
|
foreach (var uri in cmdUris)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine($"[指令] 连接控制端: {uri}");
|
|||
|
|
dealer.Connect(uri);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 4. 发送登录包 (握手)
|
|||
|
|
// 构造心跳包
|
|||
|
|
var heartbeat = new
|
|||
|
|
{
|
|||
|
|
Type = "Login",
|
|||
|
|
Id = myIdentity,
|
|||
|
|
Time = DateTime.Now
|
|||
|
|
};
|
|||
|
|
string loginJson = JsonConvert.SerializeObject(heartbeat);
|
|||
|
|
|
|||
|
|
// 注意:Dealer Socket 发送是负载均衡的 (Round-Robin)。
|
|||
|
|
// 如果连接了多个 Dashboard,SendFrame 一次只会发给其中一个。
|
|||
|
|
// 为了确保所有 Dashboard 都能收到上线通知,我们根据连接数循环发送几次。
|
|||
|
|
// (注:这只是初始化时的权宜之计,心跳包后续可以定时发送)
|
|||
|
|
for (int i = 0; i < cmdUris.Count; i++)
|
|||
|
|
{
|
|||
|
|
dealer.SendFrame(loginJson);
|
|||
|
|
await Task.Delay(10); // 稍微间隔,给 ZMQ 内部调度一点时间
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Console.WriteLine($"[指令] 已发送登录包 (ID: {myIdentity}),进入监听循环...");
|
|||
|
|
|
|||
|
|
// 5. 监听循环
|
|||
|
|
while (!stoppingToken.IsCancellationRequested)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 非阻塞接收 (500ms 超时),避免卡死线程
|
|||
|
|
if (dealer.TryReceiveFrameString(TimeSpan.FromMilliseconds(500), out string msg))
|
|||
|
|
{
|
|||
|
|
Console.WriteLine($"[指令] 收到: {msg}");
|
|||
|
|
|
|||
|
|
// TODO: 在这里解析 JSON 并调用 CameraSDK 执行业务
|
|||
|
|
// var cmd = JsonConvert.DeserializeObject<CommandModel>(msg);
|
|||
|
|
// if (cmd.Action == "Reboot") ...
|
|||
|
|
|
|||
|
|
// 回复 ACK (确认收到)
|
|||
|
|
// Dealer 会自动根据 Router 发来的 RoutingID 路由回去
|
|||
|
|
dealer.SendFrame($"ACK: {msg} (From {myIdentity})");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine($"[指令] 通信异常: {ex.Message}");
|
|||
|
|
// 防止异常死循环刷屏
|
|||
|
|
await Task.Delay(1000, stoppingToken);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|