2026-01-15 18:56:39 +08:00
|
|
|
|
using Ayay.SerilogLogs;
|
2026-01-15 09:31:57 +08:00
|
|
|
|
using Microsoft.AspNetCore.Builder;
|
2025-12-29 08:09:14 +08:00
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2026-01-15 18:56:39 +08:00
|
|
|
|
using Serilog;
|
2026-01-07 10:59:03 +08:00
|
|
|
|
using SHH.CameraSdk;
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SHH.CameraService;
|
|
|
|
|
|
|
|
|
|
|
|
public class Program
|
|
|
|
|
|
{
|
2026-01-15 18:56:39 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 主程序
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="args"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-12-29 08:09:14 +08:00
|
|
|
|
public static async Task Main(string[] args)
|
|
|
|
|
|
{
|
2026-01-15 09:31:57 +08:00
|
|
|
|
// 1. [核心环境] 必须在所有网络操作前开启
|
|
|
|
|
|
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
|
|
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 2. 解析配置与初始化日志
|
|
|
|
|
|
var (config, opts, isDebugArgs) = Bootstrapper.ParseConfigAndInitLogger(args);
|
|
|
|
|
|
var sysLog = Log.ForContext("SourceContext", LogModules.Core);
|
2026-01-05 14:54:06 +08:00
|
|
|
|
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 1. 启动日志
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
sysLog.Warning($"🚀 视频取流进程启动, 日志组件初始化完毕 => 进程: {opts.AppId}");
|
|
|
|
|
|
|
|
|
|
|
|
string argString = string.Join(" ", args);
|
|
|
|
|
|
sysLog.Debug($"🚀 启动参数({(isDebugArgs ? "调试环境" : "生产环境")}): {argString}");
|
2026-01-05 14:54:06 +08:00
|
|
|
|
|
2026-01-15 09:31:57 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 2. 硬件预热、端口扫描、gRPC链接
|
2026-01-15 09:31:57 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
Bootstrapper.WarmUpHardware(sysLog);
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 端口自动扫描 (必须做,否则端口冲突)
|
|
|
|
|
|
int activePort = Bootstrapper.ScanForAvailablePort(config, sysLog);
|
|
|
|
|
|
if (activePort == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
sysLog.Fatal("💀 无法启动:配置范围内无可用端口");
|
|
|
|
|
|
Bootstrapper.Shutdown("无法启动:配置范围内无可用端口", exitCode: 1);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
config.UpdateActualPort(activePort); // 回填端口
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 具体的 gRPC 链接逻辑封装在 Bootstrapper 中,保持 Main 清爽但逻辑可见
|
2026-01-16 07:23:56 +08:00
|
|
|
|
await Bootstrapper.RegisterToGatewayAsync(config);
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 3. 构建 Web 主机环境
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 18:56:39 +08:00
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// ★ 核心改动:一行代码注册所有业务 (SDK, Workers, gRPC, 视频流)
|
|
|
|
|
|
builder.Services.AddCameraBusinessServices(config, sysLog);
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// ★ 核心改动:注册 Web 基础 (Controller, Swagger, Cors)
|
|
|
|
|
|
builder.Services.AddWebSupport(config);
|
2026-01-15 09:31:57 +08:00
|
|
|
|
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
2026-01-15 09:31:57 +08:00
|
|
|
|
// 6. 启动服务
|
2026-01-07 10:59:03 +08:00
|
|
|
|
// =============================================================
|
|
|
|
|
|
var app = builder.Build();
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-15 09:31:57 +08:00
|
|
|
|
// 激活 SDK 管理器并启动业务点火
|
2026-01-15 18:56:39 +08:00
|
|
|
|
await StartBusinessLogic(app, sysLog);
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// ★ 核心改动:配置 HTTP 管道 (Swagger, MapControllers 等)
|
|
|
|
|
|
app.ConfigurePipeline(config);
|
2026-01-05 14:54:06 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
// 启动监听
|
|
|
|
|
|
string url = $"http://0.0.0.0:{config.BasePort}";
|
|
|
|
|
|
sysLog.Information($"🚀 [WebApi] 服务启动,监听: {url}");
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
2026-01-15 18:56:39 +08:00
|
|
|
|
await app.RunAsync(url);
|
2025-12-29 08:09:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-07 10:59:03 +08:00
|
|
|
|
/// <summary>
|
2026-01-15 09:31:57 +08:00
|
|
|
|
/// 激活单例并启动相机管理器
|
2026-01-07 10:59:03 +08:00
|
|
|
|
/// </summary>
|
2026-01-15 18:56:39 +08:00
|
|
|
|
/// <param name="app"></param>
|
|
|
|
|
|
/// <param name="logger"></param>
|
|
|
|
|
|
static async Task StartBusinessLogic(WebApplication app, Serilog.ILogger logger)
|
2026-01-05 14:54:06 +08:00
|
|
|
|
{
|
2026-01-07 10:59:03 +08:00
|
|
|
|
var manager = app.Services.GetRequiredService<CameraManager>();
|
2026-01-15 18:56:39 +08:00
|
|
|
|
|
|
|
|
|
|
// 激活哨兵
|
2026-01-07 10:59:03 +08:00
|
|
|
|
_ = app.Services.GetRequiredService<ConnectivitySentinel>();
|
2026-01-15 18:56:39 +08:00
|
|
|
|
|
2026-01-07 10:59:03 +08:00
|
|
|
|
await manager.StartAsync();
|
2026-01-15 18:56:39 +08:00
|
|
|
|
Console.WriteLine("✅[System] 核心业务逻辑已激活。");
|
2025-12-29 08:09:14 +08:00
|
|
|
|
}
|
2026-01-15 18:56:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
🚀 启动/发布 程序启动、服务预热、开始监听
|
|
|
|
|
|
🏁 结束/终点 批量任务全部完成、程序正常退出
|
|
|
|
|
|
🔄 重试/循环 正在重试连接、定时任务触发、同步数据中
|
|
|
|
|
|
⏳ 等待/耗时 长耗时操作开始、排队中
|
|
|
|
|
|
💤 休眠/闲置 线程挂起、服务进入待机模式
|
|
|
|
|
|
🌐 网络/HTTP HTTP 请求、API 调用、Web 服务
|
|
|
|
|
|
🔌 连接 数据库连接建立、Socket 连接
|
|
|
|
|
|
📡 信号/广播 发送 MQ 消息、广播通知、取流
|
|
|
|
|
|
💾 存储/磁盘 写入文件、数据库落盘、缓存读写
|
|
|
|
|
|
🔒 安全/锁 加密、解密、登录成功、获取分布式锁
|
|
|
|
|
|
⚙️ 配置/系统 加载配置、系统底层操作
|
|
|
|
|
|
🐞 Bug/调试 捕捉到的异常、临时调试信息
|
|
|
|
|
|
🧪 测试/实验 单元测试环境、灰度测试代码
|
|
|
|
|
|
🔍 搜索/检查 查询数据库、检查文件是否存在
|
|
|
|
|
|
💡 提示/发现 逻辑分支提示、参数值打印
|
|
|
|
|
|
🔴 红:致命/严重 (Fatal/Error)
|
|
|
|
|
|
🟡 黄:警告 (Warning)
|
|
|
|
|
|
🟢 绿:正常/成功 (Info/Success)
|
|
|
|
|
|
🔵 蓝:数据/网络 (Data/Network)
|
|
|
|
|
|
⚪ 灰:细节/忽略 (Debug/Verbose)
|
|
|
|
|
|
✅ Check Mark Button \u{2705} ✅
|
|
|
|
|
|
🆗 OK Button \u{1F197} 🆗
|
|
|
|
|
|
🔚 END Arrow (逻辑结束) \u{1F51A} 🔚
|
|
|
|
|
|
💯 Hundred Points (完美结束) \u{1F4AF} 💯
|
|
|
|
|
|
🛑 Stop Sign (最强提示) \u{1F6D1} 🛑
|
|
|
|
|
|
⛔ No Entry (禁止/中断) \u{26D4} ⛔
|
|
|
|
|
|
🚫 Prohibited (非法操作终止) \u{1F6AB} 🚫
|
|
|
|
|
|
⏹️ Stop Button (播放器风格) \u{23F9} ⏹
|
|
|
|
|
|
❌ Cross Mark (任务失败结束) \u{274C} ❌
|
|
|
|
|
|
💀 Skull (进程被 Kill) \u{1F480} 💀
|
|
|
|
|
|
⚰️ Coffin (彻底销毁) \u{26B0} ⚰
|
|
|
|
|
|
👻 Ghost (变成孤儿进程) \u{1F47B} 👻
|
|
|
|
|
|
*/
|