113 lines
4.9 KiB
C#
113 lines
4.9 KiB
C#
|
|
using Microsoft.Extensions.Hosting;
|
|||
|
|
using SHH.CameraSdk;
|
|||
|
|
|
|||
|
|
namespace SHH.CameraService;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 相机服务核心引擎工作者(后台长驻服务)
|
|||
|
|
/// <para>核心职责:</para>
|
|||
|
|
/// <para>1. 管理 CameraManager 全生命周期(启动、配置、释放)</para>
|
|||
|
|
/// <para>2. 初始化网络哨兵(ConnectivitySentinel),监控设备网络连通性</para>
|
|||
|
|
/// <para>3. 无配置时自动添加默认测试设备,降低调试门槛</para>
|
|||
|
|
/// <para>设计说明:</para>
|
|||
|
|
/// <para>- 基于 BackgroundService,运行在独立后台线程,不阻塞 Web 主线程</para>
|
|||
|
|
/// <para>- 与 CameraManager 强绑定,是所有相机设备的统一入口</para>
|
|||
|
|
/// <para>- 包含容错机制,添加设备失败不影响整体服务启动</para>
|
|||
|
|
public class CameraEngineWorker : BackgroundService
|
|||
|
|
{
|
|||
|
|
#region --- 依赖注入字段 ---
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 相机管理器实例(核心业务对象)
|
|||
|
|
/// 功能:管理所有相机设备的生命周期、状态监控、配置更新
|
|||
|
|
/// </summary>
|
|||
|
|
private readonly CameraManager _manager;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 网络连通性哨兵实例
|
|||
|
|
/// 功能:周期性 Ping 设备、检测网络状态、触发断线重连
|
|||
|
|
/// </summary>
|
|||
|
|
private readonly ConnectivitySentinel _sentinel;
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region --- 构造函数 ---
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化相机引擎工作者实例
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="manager">相机管理器(通过 DI 注入,已关联存储服务)</param>
|
|||
|
|
/// <param name="sentinel">网络哨兵(通过 DI 注入,已预设监控周期)</param>
|
|||
|
|
public CameraEngineWorker(CameraManager manager, ConnectivitySentinel sentinel)
|
|||
|
|
{
|
|||
|
|
_manager = manager ?? throw new ArgumentNullException(
|
|||
|
|
nameof(manager), "相机管理器实例不能为空,核心引擎启动失败");
|
|||
|
|
_sentinel = sentinel ?? throw new ArgumentNullException(
|
|||
|
|
nameof(sentinel), "网络哨兵实例不能为空,设备监控功能失效");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region --- BackgroundService 核心实现 ---
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 启动引擎:初始化相机管理器并加载业务配置
|
|||
|
|
/// <para>执行流程:</para>
|
|||
|
|
/// <para>1. 启动 CameraManager(加载本地配置文件中的设备信息)</para>
|
|||
|
|
/// <para>2. 加载默认业务逻辑(无设备时添加测试设备)</para>
|
|||
|
|
/// <para>注意:网络哨兵的启动逻辑已内置在其构造函数中,此处无需额外调用</para>
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="stoppingToken">服务停止令牌(响应应用关闭/重启信号)</param>
|
|||
|
|
/// <returns>异步任务(引擎启动完成后结束)</returns>
|
|||
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine("[Engine] 核心引擎启动中...");
|
|||
|
|
Console.WriteLine("[Engine] 启动相机管理器(加载设备配置)");
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 启动相机管理器:加载 App_Data/Process_X 目录下的设备配置文件
|
|||
|
|
await _manager.StartAsync();
|
|||
|
|
Console.WriteLine("[Engine] 相机管理器启动成功,已加载配置文件中的设备");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine($"[Engine] 相机管理器启动失败:{ex.Message}");
|
|||
|
|
Console.WriteLine("[Engine] 警告:核心引擎将继续运行,但无法管理任何相机设备");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Console.WriteLine("[Engine] 核心引擎启动完成,进入运行状态");
|
|||
|
|
Console.WriteLine("[Engine] 提示:可通过 API 接口添加/编辑/删除设备,实时生效");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 停止引擎:优雅释放资源
|
|||
|
|
/// <para>执行流程:</para>
|
|||
|
|
/// <para>1. 调用 CameraManager.DisposeAsync(),释放所有设备连接、句柄、线程资源</para>
|
|||
|
|
/// <para>2. 调用基类 StopAsync(),标记服务停止状态</para>
|
|||
|
|
/// <para>注意:必须先释放 CameraManager,避免设备连接泄露</para>
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="cancellationToken">取消令牌(用于强制终止释放流程)</param>
|
|||
|
|
/// <returns>异步任务(资源释放完成后结束)</returns>
|
|||
|
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine("[Engine] 核心引擎正在停止...");
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 释放相机管理器:停止所有设备取流、注销登录、释放非托管资源
|
|||
|
|
await _manager.DisposeAsync();
|
|||
|
|
Console.WriteLine("[Engine] 相机管理器资源已释放");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Console.WriteLine($"[Engine] 资源释放异常:{ex.Message}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用基类方法,完成服务停止
|
|||
|
|
await base.StopAsync(cancellationToken);
|
|||
|
|
Console.WriteLine("[Engine] 核心引擎已停止");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
}
|