完善契约与客户端、服务端的收发代码
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using SHH.CameraSdk; // 引用你的业务核心
|
||||
using SHH.NetMQ;
|
||||
@@ -11,94 +10,126 @@ public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
// =============================================================
|
||||
// 1. 端口与身份计算
|
||||
// =============================================================
|
||||
#region --- 1. 端口与身份计算 ---
|
||||
|
||||
int processId = 1;
|
||||
if (args.Length > 0 && int.TryParse(args[0], out int pid)) processId = pid;
|
||||
// 从命令行参数解析进程ID(默认1)
|
||||
if (args.Length > 0 && int.TryParse(args[0], out int pid))
|
||||
processId = pid;
|
||||
|
||||
// 计算 Web 服务端口(基础5000 + 进程ID偏移)
|
||||
int port = 5000 + (processId - 1);
|
||||
|
||||
Console.Title = $"SHH Gateway - Instance #{processId} (Port: {port})";
|
||||
|
||||
// =============================================================
|
||||
// 2. 硬件环境预热 (【重要】必须在一切开始前调用)
|
||||
// =============================================================
|
||||
#endregion
|
||||
|
||||
#region --- 2. 硬件环境预热 (【重要】必须在一切开始前调用) ---
|
||||
|
||||
InitHardwareEnv();
|
||||
|
||||
// =============================================================
|
||||
// 3. 构建 WebHost
|
||||
// =============================================================
|
||||
#endregion
|
||||
|
||||
#region --- 3. 构建 WebHost ---
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// --- A. 注册 ZeroMQ 组件 (传输层) ---
|
||||
#region --- A. 注册 ZeroMQ 组件 (传输层) ---
|
||||
|
||||
// 注册转发客户端(定向推送)
|
||||
string zmqBind = $"tcp://*:{5555 + (processId - 1)}";
|
||||
|
||||
// ★★★ 新增:注册指令总线服务 ★★★
|
||||
string zmqTarget = "tcp://127.0.0.1:6000";
|
||||
|
||||
builder.Services.AddSingleton(new DistributorServer(zmqBind));
|
||||
// 注册转发客户端(定向推送)
|
||||
builder.Services.AddSingleton(new ForwarderClient(zmqTarget));
|
||||
|
||||
// --- B. 注册核心业务服务 ---
|
||||
// ★★★ 新增:注册指令总线服务 ★★★
|
||||
builder.Services.AddHostedService<CommandBusService>();
|
||||
|
||||
// 注册分发服务器(广播)
|
||||
builder.Services.AddSingleton(new DistributorServer(zmqBind));
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- B. 注册核心业务服务 ---
|
||||
|
||||
// 注册文件存储服务(进程隔离)
|
||||
builder.Services.AddSingleton<IStorageService>(new FileStorageService(processId));
|
||||
|
||||
// CameraManager 注册为单例,生命周期由 CameraEngineWorker 管理
|
||||
builder.Services.AddSingleton<CameraManager>();
|
||||
|
||||
// 图像处理配置管理器(单例)
|
||||
builder.Services.AddSingleton<ProcessingConfigManager>();
|
||||
|
||||
// 显示窗口管理器(单例)
|
||||
builder.Services.AddSingleton<DisplayWindowManager>();
|
||||
|
||||
// --- C. 注册图像处理集群 (修复版) ---
|
||||
// 我们需要确保 ImageScaleCluster 和 ImageEnhanceCluster 都能被独立注入,
|
||||
// 同时它们之间又要建立链式关系。我们使用一个专门的 HostedService 来做连接。
|
||||
#endregion
|
||||
|
||||
// 1. 注册 Scale 实例
|
||||
#region --- C. 注册图像处理集群 (修复版) ---
|
||||
|
||||
// 说明:通过责任链模式组装 Scale → Enhance 处理流程,确保顺序执行
|
||||
// 1. 注册图像缩容集群(并行度4)
|
||||
builder.Services.AddSingleton<ImageScaleCluster>(sp =>
|
||||
{
|
||||
var config = sp.GetRequiredService<ProcessingConfigManager>();
|
||||
return new ImageScaleCluster(4, config);
|
||||
var configManager = sp.GetRequiredService<ProcessingConfigManager>();
|
||||
return new ImageScaleCluster(4, configManager);
|
||||
});
|
||||
|
||||
// 2. 注册 Enhance 实例
|
||||
// 2. 注册图像增强集群(并行度4)
|
||||
builder.Services.AddSingleton<ImageEnhanceCluster>(sp =>
|
||||
{
|
||||
var config = sp.GetRequiredService<ProcessingConfigManager>();
|
||||
return new ImageEnhanceCluster(4, config);
|
||||
var configManager = sp.GetRequiredService<ProcessingConfigManager>();
|
||||
return new ImageEnhanceCluster(4, configManager);
|
||||
});
|
||||
|
||||
// 3. 注册一个启动服务来连接这两个集群 (Chain of Responsibility)
|
||||
// 3. 注册管道配置服务(组装责任链)
|
||||
builder.Services.AddHostedService<PipelineConfigurator>();
|
||||
|
||||
#endregion
|
||||
|
||||
// --- D. 注册 Web 基础服务 ---
|
||||
#region --- D. 注册 Web 基础服务 ---
|
||||
|
||||
// 注册控制器(加载 SDK 中的 CamerasController、MonitorController)
|
||||
builder.Services.AddControllers()
|
||||
.AddApplicationPart(typeof(CamerasController).Assembly) // 加载 SDK 中的控制器
|
||||
.AddApplicationPart(typeof(MonitorController).Assembly)
|
||||
.AddControllersAsServices();
|
||||
|
||||
// 注册全局操作日志过滤器 (防止 500 错误)
|
||||
// 注册全局操作日志过滤器(捕获 API 操作日志)
|
||||
builder.Services.AddScoped<UserActionFilter>();
|
||||
|
||||
// 注册 Swagger 文档(区分实例ID)
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"Gateway #{processId}", Version = "v1" });
|
||||
c.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Title = $"Gateway #{processId}",
|
||||
Version = "v1"
|
||||
});
|
||||
});
|
||||
|
||||
// --- E. 注册后台服务 (Worker) ---
|
||||
#endregion
|
||||
|
||||
#region --- E. 注册后台服务 (Worker) ---
|
||||
|
||||
// 1. 核心引擎工作者 (负责 StartAsync 和 ConfigureBusinessLogic)
|
||||
builder.Services.AddHostedService<CameraEngineWorker>();
|
||||
|
||||
// 2. 网络哨兵 (负责断线重连)
|
||||
// 假设 ConnectivitySentinel 实现了 IHostedService 或者它是一个简单的类
|
||||
// 如果它实现了 IHostedService:
|
||||
// builder.Services.AddHostedService<ConnectivitySentinel>();
|
||||
// 如果它只是一个普通类,需要在 CameraEngineWorker 里启动它,或者注册为单例并手动启动
|
||||
// 这里假设我们需要显式注册它以便让它工作:
|
||||
builder.Services.AddSingleton<ConnectivitySentinel>(); // 注册单例
|
||||
// 注意:ConnectivitySentinel 的启动逻辑我们放到 CameraEngineWorker 里去调用
|
||||
// 2.网络哨兵(负责断线重连)(监控设备断线重连,注册为单例)
|
||||
builder.Services.AddSingleton<ConnectivitySentinel>();
|
||||
|
||||
// 3. ZeroMQ 桥梁
|
||||
// 3. ZeroMQ 桥梁服务(转发帧数据到外部系统)
|
||||
builder.Services.AddHostedService<ZeroMqBridgeService>();
|
||||
|
||||
// 4. 配置 CORS
|
||||
#endregion
|
||||
|
||||
#region --- F. 配置 CORS(允许所有跨域请求) ---
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowAll", policy =>
|
||||
@@ -107,144 +138,57 @@ public class Program
|
||||
});
|
||||
});
|
||||
|
||||
// =============================================================
|
||||
// 4. 启动应用
|
||||
// =============================================================
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 4. 启动应用 ---
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// 启用 Swagger 文档
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseCors("AllowAll"); // 启用 CORS
|
||||
|
||||
// 启用 CORS 策略
|
||||
app.UseCors("AllowAll");
|
||||
|
||||
// 映射控制器路由
|
||||
app.MapControllers();
|
||||
|
||||
// 输出启动信息
|
||||
Console.WriteLine($"[System] 绑定 Web 端口: {port}");
|
||||
Console.WriteLine($"[System] 绑定 ZMQ 端口: {zmqBind}");
|
||||
|
||||
// 启动 Web 应用
|
||||
await app.RunAsync($"http://0.0.0.0:{port}");
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region --- 辅助方法:硬件环境预热 ---
|
||||
|
||||
/// <summary>
|
||||
/// 初始化硬件环境(海康 SDK 预热)
|
||||
/// </summary>
|
||||
static void InitHardwareEnv()
|
||||
{
|
||||
Console.WriteLine("=== 工业级视频 SDK 架构测试 (V3.5 框架版) ===");
|
||||
Console.WriteLine("[硬件] 海康驱动预热中...");
|
||||
try
|
||||
{
|
||||
// 初始化海康 SDK
|
||||
HikNativeMethods.NET_DVR_Init();
|
||||
// 强制预热播放库(避免首次取流延迟)
|
||||
HikSdkManager.ForceWarmUp();
|
||||
Console.WriteLine("[硬件] 预热完成。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[硬件] 预热失败: {ex.Message}");
|
||||
// 不抛出异常,允许程序继续尝试启动(可能是在无 DLL 环境调试)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 负责图像处理管道的组装 (Scale -> Enhance -> Global)
|
||||
/// </summary>
|
||||
public class PipelineConfigurator : IHostedService
|
||||
{
|
||||
private readonly ImageScaleCluster _scale;
|
||||
private readonly ImageEnhanceCluster _enhance;
|
||||
|
||||
public PipelineConfigurator(ImageScaleCluster scale, ImageEnhanceCluster enhance)
|
||||
{
|
||||
_scale = scale;
|
||||
_enhance = enhance;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// 建立责任链: Scale -> Enhance
|
||||
_scale.SetNext(_enhance);
|
||||
|
||||
// 挂载到全局路由 (驱动层回调会把流推给 Scale)
|
||||
GlobalPipelineRouter.SetProcessor(_scale);
|
||||
|
||||
Console.WriteLine("[Pipeline] 图像处理链组装完成: Scale -> Enhance");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 负责 CameraManager 的生命周期管理和业务初始化
|
||||
/// </summary>
|
||||
public class CameraEngineWorker : BackgroundService
|
||||
{
|
||||
private readonly CameraManager _manager;
|
||||
private readonly ConnectivitySentinel _sentinel; // 注入哨兵
|
||||
|
||||
public CameraEngineWorker(CameraManager manager, ConnectivitySentinel sentinel)
|
||||
{
|
||||
_manager = manager;
|
||||
_sentinel = sentinel;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
Console.WriteLine("[Engine] 正在启动摄像头管理器...");
|
||||
|
||||
// 1. 启动管理器 (加载文件配置)
|
||||
await _manager.StartAsync();
|
||||
|
||||
// 2. 启动哨兵 (开始监控断线)
|
||||
// 假设 ConnectivitySentinel 有一个 Start 或类似的方法,如果没有,说明它在构造函数里就启动了 timers
|
||||
// _sentinel.Start();
|
||||
|
||||
// 3. 加载默认业务逻辑 (添加测试设备)
|
||||
await ConfigureBusinessLogic(_manager);
|
||||
|
||||
Console.WriteLine("[Engine] 业务逻辑加载完成。");
|
||||
}
|
||||
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Console.WriteLine("[Engine] 正在停止...");
|
||||
await _manager.DisposeAsync();
|
||||
await base.StopAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// 以前 Program 类里的静态方法,现在移到这里
|
||||
private async Task ConfigureBusinessLogic(CameraManager manager)
|
||||
{
|
||||
try
|
||||
{
|
||||
//// 检查是否已经有设备了,如果没有才添加默认的
|
||||
//if (manager.GetAllCameras().Any()) return;
|
||||
|
||||
Console.WriteLine("[Engine] 检测到空配置,正在添加默认测试设备...");
|
||||
|
||||
var config = new VideoSourceConfig
|
||||
{
|
||||
Id = 101,
|
||||
Brand = DeviceBrand.HikVision,
|
||||
IpAddress = "192.168.5.9",
|
||||
Port = 8000,
|
||||
Username = "admin",
|
||||
Password = "RRYFOA",
|
||||
StreamType = 0
|
||||
};
|
||||
manager.AddDevice(config);
|
||||
|
||||
var config2 = new VideoSourceConfig
|
||||
{
|
||||
Id = 102,
|
||||
Brand = DeviceBrand.HikVision,
|
||||
IpAddress = "172.16.41.20",
|
||||
Port = 8000,
|
||||
Username = "admin",
|
||||
Password = "abcd1234",
|
||||
StreamType = 0
|
||||
};
|
||||
manager.AddDevice(config2);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[Engine] 添加默认设备失败: {ex.Message}");
|
||||
// 不抛出异常,允许程序在无 DLL 环境下调试
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user