Files
Ayay/SHH.CameraService/Program.cs

148 lines
6.2 KiB
C#
Raw Normal View History

2026-01-15 18:56:39 +08:00
using Ayay.SerilogLogs;
2026-01-15 09:31:57 +08:00
using Microsoft.AspNetCore.Builder;
2026-01-16 17:45:27 +08:00
using Microsoft.AspNetCore.Hosting;
2025-12-29 08:09:14 +08:00
using Microsoft.Extensions.DependencyInjection;
2026-01-16 17:45:27 +08:00
using Microsoft.Extensions.Logging;
2026-01-15 18:56:39 +08:00
using Serilog;
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-15 18:56:39 +08:00
// 1. 启动日志
// =============================================================
2026-01-16 14:30:42 +08:00
sysLog.Warning($"[Core] 🚀 视频取流进程启动, 日志组件初始化完毕 => 进程: {opts.AppId}");
2026-01-15 18:56:39 +08:00
string argString = string.Join(" ", args);
2026-01-16 14:30:42 +08:00
sysLog.Debug($"[Core] 🚀 启动参数({(isDebugArgs ? "" : "")}: {argString}");
2026-01-05 14:54:06 +08:00
2026-01-15 09:31:57 +08:00
// =============================================================
2026-01-16 14:30:42 +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-15 18:56:39 +08:00
// 端口自动扫描 (必须做,否则端口冲突)
int activePort = Bootstrapper.ScanForAvailablePort(config, sysLog);
if (activePort == -1)
{
2026-01-16 14:30:42 +08:00
sysLog.Fatal("[Core] 💀 无法启动:配置范围内无可用端口");
2026-01-15 18:56:39 +08:00
Bootstrapper.Shutdown("无法启动:配置范围内无可用端口", exitCode: 1);
return;
}
config.UpdateActualPort(activePort); // 回填端口
2026-01-16 14:30:42 +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-15 18:56:39 +08:00
// 3. 构建 Web 主机环境
// =============================================================
2026-01-15 18:56:39 +08:00
var builder = WebApplication.CreateBuilder(args);
2026-01-16 17:45:27 +08:00
// 👇👇👇 核心修复开始 👇👇👇
// ★ 1. 接管日志系统:告诉 Host 使用我们刚才配置好的 Serilog
// dispose: true 表示程序结束时自动刷新日志
builder.Host.UseSerilog(dispose: true);
// ★ 2. 斩草除根:清除 .NET 默认注入的 Console/Debug 日志提供程序
// 这一步是解决 "info: Microsoft.Hosting.Lifetime..." 重复输出的关键
builder.Logging.ClearProviders();
// ★ 3. (可选) 彻底静音:禁止 Kestrel 打印 "Now listening on..." 这种启动横幅
// 如果你只想看你自己的 "[WebApi] 🚀 服务启动...",就把这行加上
builder.WebHost.SuppressStatusMessages(true);
2026-01-16 14:30:42 +08:00
// ★ 核心改动:一行代码注册所有业务 (SDK, Workers, gRpc, 视频流)
2026-01-15 18:56:39 +08:00
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-15 09:31:57 +08:00
// 6. 启动服务
// =============================================================
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-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}";
2026-01-16 14:30:42 +08:00
sysLog.Information($"[WebApi] 🚀 服务启动,监听: {url}");
2026-01-15 18:56:39 +08:00
await app.RunAsync(url);
2025-12-29 08:09:14 +08:00
}
/// <summary>
2026-01-15 09:31:57 +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
{
var manager = app.Services.GetRequiredService<CameraManager>();
2026-01-15 18:56:39 +08:00
// 激活哨兵
_ = app.Services.GetRequiredService<ConnectivitySentinel>();
2026-01-15 18:56:39 +08:00
await manager.StartAsync();
2026-01-16 14:30:42 +08:00
var sysLog = Log.ForContext("SourceContext", LogModules.Core);
sysLog.Information($"[Core] 🚀 核心业务逻辑已激活, 设备管理器已就绪.");
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} &#x2705;
🆗 OK Button \u{1F197} &#x1F197;
🔚 END Arrow () \u{1F51A} &#x1F51A;
💯 Hundred Points () \u{1F4AF} &#x1F4AF;
🛑 Stop Sign () \u{1F6D1} &#x1F6D1;
No Entry (/) \u{26D4} &#x26D4;
🚫 Prohibited () \u{1F6AB} &#x1F6AB;
Stop Button () \u{23F9} &#x23F9;
Cross Mark () \u{274C} &#x274C;
💀 Skull ( Kill) \u{1F480} &#x1F480;
Coffin () \u{26B0} &#x26B0;
👻 Ghost () \u{1F47B} &#x1F47B;
*/