using IntegrationGateway.Core.Abstractions; using IntegrationGateway.Core.Infrastructure; using IntegrationGateway.Core.Models; var builder = WebApplication.CreateBuilder(args); // 注册 IHttpClientFactory builder.Services.AddHttpClient("VolPro", c => { c.Timeout = TimeSpan.FromSeconds(30); c.DefaultRequestHeaders.Add("Accept", "application/json"); }).ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(5), MaxConnectionsPerServer = 10 }); var app = builder.Build(); // 读取配置 var gwCfg = app.Configuration.GetSection("Gateway"); var owlCfg = app.Configuration.GetSection("Owl"); var mc4Cfg = app.Configuration.GetSection("MC4"); // 创建适配器注册中心 var registry = new AdapterRegistry(); // 创建 VolPro 客户端工厂 var volProUrl = gwCfg["VolProBaseUrl"] ?? "http://localhost:9100"; var httpFactory = app.Services.GetRequiredService(); var clientFactory = new GatewayClientFactory(httpFactory, volProUrl); // 注册 OwlAdapter var owlHttp = app.Services.GetRequiredService().CreateClient("VolPro"); var owlAdapter = new IntegrationGateway.Adapters.Owl.OwlAdapter( "Owl:main", owlHttp, owlCfg["BaseUrl"] ?? "http://localhost:15123", owlCfg["Username"] ?? "admin", owlCfg["Password"] ?? "admin" ); registry.Register(owlAdapter); // 注册 MC4Adapter var mc4Http = app.Services.GetRequiredService().CreateClient("VolPro"); var mc4Adapter = new IntegrationGateway.Adapters.MC4.Mc4Adapter( "MC4:31ku", mc4Http, mc4Cfg["BaseUrl"] ?? "http://localhost:3000" ); registry.Register(mc4Adapter); // 并行初始化适配器 await registry.InitializeAllAsync(); Console.WriteLine($"[Gateway] {registry.All.Count} adapter(s) registered"); // ═══ B 组路由 ═══ // B1: 健康检查 app.MapGet("/api/gateway/health", async () => { var results = new List(); foreach (var a in registry.All) { bool healthy = false; try { healthy = await a.HealthCheckAsync(); } catch { } results.Add(new { a.AdapterCode, a.DisplayName, Healthy = healthy, a.Capabilities }); } return Results.Ok(results); }); // B2: 设备列表 app.MapGet("/api/gateway/devices", async (string adapter, int page, int size, string? keyword) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "ADAPTER_NOT_FOUND", message = $"Adapter '{adapter}' not found or does not support flat devices" }); return Results.Ok(await a.GetDevicesAsync(page, size, keyword)); }); // B3: 对象树 app.MapGet("/api/gateway/tree", async (string adapter) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"Tree not supported by '{adapter}'" }); return Results.Ok(await a.GetObjectTreeAsync()); }); // B6a: 实时流 app.MapGet("/api/gateway/streams/{adapter}/{deviceId}/live", async (string adapter, string deviceId) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"Streams not supported by '{adapter}'" }); var result = await a.GetLiveUrlAsync(deviceId); return result.WsFlv == null && result.Hls == null ? Results.Problem("No stream URL returned", statusCode: 502) : Results.Ok(result); }); // B6b: 回放 app.MapGet("/api/gateway/streams/{adapter}/{deviceId}/playback", async (string adapter, string deviceId, DateTime start, DateTime end) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); return Results.Ok(await a.GetPlaybackUrlAsync(deviceId, start, end)); }); // 截图 app.MapPost("/api/gateway/streams/{adapter}/{deviceId}/snapshot", async (string adapter, string deviceId) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); return Results.Ok(await a.GetSnapshotAsync(deviceId)); }); // B7: PTZ app.MapPost("/api/gateway/streams/{adapter}/{deviceId}/ptz", async (string adapter, string deviceId, PtzRequest req) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); if (req.Action == "stop") await a.PtzStopAsync(deviceId); else await a.PtzControlAsync(deviceId, req.Direction ?? "stop", req.Speed); return Results.Ok(); }); // B4: 实时点值 app.MapGet("/api/gateway/realtime/{adapter}/{deviceId}", async (string adapter, string deviceId) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); return Results.Ok(await a.GetRealtimeValuesAsync(deviceId)); }); // B5: 控制 app.MapPost("/api/gateway/realtime/{adapter}/control", async (string adapter, ControlRequest req) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); await a.SetPointValueAsync(req.DeviceId ?? "", req.PointIndex, req.Value); return Results.Ok(); }); // B8: 告警查询 app.MapGet("/api/gateway/alarms/{adapter}", async (string adapter, int page, int size, DateTime from, DateTime to, string? level, string? state) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); return Results.Ok(await a.GetAlarmsAsync(page, size, from, to, level, state)); }); // B9: 告警确认 app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/confirm", async (string adapter, string alarmId) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); await a.ConfirmAlarmAsync(alarmId); return Results.Ok(); }); // 告警结束 app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/end", async (string adapter, string alarmId) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); await a.EndAlarmAsync(alarmId); return Results.Ok(); }); // 录像 app.MapGet("/api/gateway/recordings/{adapter}/{deviceId}", async (string adapter, string deviceId, DateTime start, DateTime end, int page, int size) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED" }); return Results.Ok(await a.GetRecordingsAsync(deviceId, start, end, page, size)); }); // B3: 手动同步 app.MapPost("/api/gateway/devices/sync", async (string adapter) => { var a = registry.FindByCode(adapter); if (a == null) return Results.NotFound(new { error = "ADAPTER_NOT_FOUND" }); // 根据适配器能力触发对应同步 if (a is IHasOwnDeviceTree tree) { var obj = await tree.GetObjectTreeAsync(); return Results.Ok(new { nodeCount = obj.Count, message = "tree synced" }); } if (a is IHasFlatDevices flat) { var dev = await flat.GetDevicesAsync(1, 1000); return Results.Ok(new { deviceCount = dev.Total, message = "devices synced" }); } return Results.Ok(new { message = "no sync needed" }); }); app.Run(); // 请求 DTO record PtzRequest(string? Direction, string Action, float Speed); record ControlRequest(string? DeviceId, int PointIndex, double Value);