全部网关代码添加详细中文注释

This commit is contained in:
2026-05-17 04:53:03 +08:00
parent df0c4cc4b2
commit 73d47cb470
26 changed files with 597 additions and 79 deletions

View File

@@ -2,9 +2,21 @@ using IntegrationGateway.Core.Abstractions;
using IntegrationGateway.Core.Infrastructure;
using IntegrationGateway.Core.Models;
// ═══════════════════════════════════════════════════════════════
// IntegrationGateway 宿主启动程序
//
// 职责:
// 1. 注册 IHttpClientFactory连接池复用
// 2. 创建并注册 OwlAdapter + MC4Adapter
// 3. 并行初始化所有适配器
// 4. 注册 14 个 B 组 REST 端点
// ═══════════════════════════════════════════════════════════════
var builder = WebApplication.CreateBuilder(args);
// 注册 IHttpClientFactory
// ── 注册 HttpClient 工厂 ──
// 命名客户端 "VolPro":用于调用 Vol.Pro A 组接口和适配器内部 HTTP 请求
// 连接池:最多 10 个并发连接5 分钟生命周期
builder.Services.AddHttpClient("VolPro", c =>
{
c.Timeout = TimeSpan.FromSeconds(30);
@@ -17,20 +29,20 @@ builder.Services.AddHttpClient("VolPro", c =>
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 客户端工厂
// ── 创建 Vol.Pro 客户端工厂(用于 A1-A4 回调) ──
var volProUrl = gwCfg["VolProBaseUrl"] ?? "http://localhost:9100";
var httpFactory = app.Services.GetRequiredService<IHttpClientFactory>();
var clientFactory = new GatewayClientFactory(httpFactory, volProUrl);
// 注册 OwlAdapter
// ── 注册 OwlAdapter ──
var owlHttp = app.Services.GetRequiredService<IHttpClientFactory>().CreateClient("VolPro");
var owlAdapter = new IntegrationGateway.Adapters.Owl.OwlAdapter(
"Owl:main", owlHttp,
@@ -40,7 +52,7 @@ var owlAdapter = new IntegrationGateway.Adapters.Owl.OwlAdapter(
);
registry.Register(owlAdapter);
// 注册 MC4Adapter
// ── 注册 MC4Adapter ──
var mc4Http = app.Services.GetRequiredService<IHttpClientFactory>().CreateClient("VolPro");
var mc4Adapter = new IntegrationGateway.Adapters.MC4.Mc4Adapter(
"MC4:31ku", mc4Http,
@@ -48,13 +60,16 @@ var mc4Adapter = new IntegrationGateway.Adapters.MC4.Mc4Adapter(
);
registry.Register(mc4Adapter);
// 并行初始化适配器
// ── 并行初始化所有适配器 ──
await registry.InitializeAllAsync();
Console.WriteLine($"[Gateway] {registry.All.Count} adapter(s) registered");
Console.WriteLine($"[Gateway] {registry.All.Count} 个适配器已注册");
// ═══ B 组路由 ═══
// ═══════════════════════════════════════════════════════════════
// B 组路由(管理端 / Vol.Pro → 网关)
// 所有路由通过适配器编码查找对应适配器,按能力接口分发请求
// ═══════════════════════════════════════════════════════════════
// B1: 健康检查
// B1: 健康检查 — 返回所有适配器的健康状态和能力声明
app.MapGet("/api/gateway/health", async () =>
{
var results = new List<object>();
@@ -67,34 +82,34 @@ app.MapGet("/api/gateway/health", async () =>
return Results.Ok(results);
});
// B2: 设备列表
// B2: 设备列表 — 分页获取扁平设备列表Owl/门禁/道闸)
app.MapGet("/api/gateway/devices", async (string adapter, int page, int size, string? keyword) =>
{
var a = registry.FindByCode<IHasFlatDevices>(adapter);
if (a == null) return Results.NotFound(new { error = "ADAPTER_NOT_FOUND", message = $"Adapter '{adapter}' not found or does not support flat devices" });
if (a == null) return Results.NotFound(new { error = "ADAPTER_NOT_FOUND", message = $"适配器 '{adapter}' 不存在或不支持扁平设备列表" });
return Results.Ok(await a.GetDevicesAsync(page, size, keyword));
});
// B3: 对象树
// B3: 对象树 — 获取层级对象树MC4.0
app.MapGet("/api/gateway/tree", async (string adapter) =>
{
var a = registry.FindByCode<IHasOwnDeviceTree>(adapter);
if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"Tree not supported by '{adapter}'" });
if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"适配器 '{adapter}' 不支持对象树" });
return Results.Ok(await a.GetObjectTreeAsync());
});
// B6a: 实时
// B6a: 实时取流 — 获取视频通道的实时流地址
app.MapGet("/api/gateway/streams/{adapter}/{deviceId}/live", async (string adapter, string deviceId) =>
{
var a = registry.FindByCode<IHasStreams>(adapter);
if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"Streams not supported by '{adapter}'" });
if (a == null) return Results.NotFound(new { error = "CAPABILITY_NOT_SUPPORTED", message = $"适配器 '{adapter}' 不支持视频取流" });
var result = await a.GetLiveUrlAsync(deviceId);
return result.WsFlv == null && result.Hls == null
? Results.Problem("No stream URL returned", statusCode: 502)
? Results.Problem("未获取到流地址", statusCode: 502)
: Results.Ok(result);
});
// B6b: 回放
// B6b: 录像回放 — 获取历史录像 HLS 地址
app.MapGet("/api/gateway/streams/{adapter}/{deviceId}/playback", async (string adapter, string deviceId, DateTime start, DateTime end) =>
{
var a = registry.FindByCode<IHasStreams>(adapter);
@@ -102,7 +117,7 @@ app.MapGet("/api/gateway/streams/{adapter}/{deviceId}/playback", async (string a
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<IHasStreams>(adapter);
@@ -110,7 +125,7 @@ app.MapPost("/api/gateway/streams/{adapter}/{deviceId}/snapshot", async (string
return Results.Ok(await a.GetSnapshotAsync(deviceId));
});
// B7: PTZ
// B7: 云台控制 — continuous 方向移动 + stop
app.MapPost("/api/gateway/streams/{adapter}/{deviceId}/ptz", async (string adapter, string deviceId, PtzRequest req) =>
{
var a = registry.FindByCode<IHasStreams>(adapter);
@@ -120,7 +135,7 @@ app.MapPost("/api/gateway/streams/{adapter}/{deviceId}/ptz", async (string adapt
return Results.Ok();
});
// B4: 实时点
// B4: 实时点位值 — 获取 IoT 设备测点当前读数
app.MapGet("/api/gateway/realtime/{adapter}/{deviceId}", async (string adapter, string deviceId) =>
{
var a = registry.FindByCode<IHasPoints>(adapter);
@@ -128,7 +143,7 @@ app.MapGet("/api/gateway/realtime/{adapter}/{deviceId}", async (string adapter,
return Results.Ok(await a.GetRealtimeValuesAsync(deviceId));
});
// B5: 控制
// B5: 设备控制 — 向 IoT 设备下发控制指令
app.MapPost("/api/gateway/realtime/{adapter}/control", async (string adapter, ControlRequest req) =>
{
var a = registry.FindByCode<IHasPoints>(adapter);
@@ -137,7 +152,7 @@ app.MapPost("/api/gateway/realtime/{adapter}/control", async (string adapter, Co
return Results.Ok();
});
// B8: 告警查询
// 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<IHasAlarms>(adapter);
@@ -145,7 +160,7 @@ app.MapGet("/api/gateway/alarms/{adapter}", async (string adapter, int page, int
return Results.Ok(await a.GetAlarmsAsync(page, size, from, to, level, state));
});
// B9: 告警确认
// B9: 告警确认 — 确认告警并写回子系统
app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/confirm", async (string adapter, string alarmId) =>
{
var a = registry.FindByCode<IHasAlarms>(adapter);
@@ -154,7 +169,7 @@ app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/confirm", async (string ada
return Results.Ok();
});
// 告警结束
// 告警结束 — 结束告警并写回子系统
app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/end", async (string adapter, string alarmId) =>
{
var a = registry.FindByCode<IHasAlarms>(adapter);
@@ -163,7 +178,7 @@ app.MapPost("/api/gateway/alarms/{adapter}/{alarmId}/end", async (string adapter
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<IHasRecordings>(adapter);
@@ -171,27 +186,39 @@ app.MapGet("/api/gateway/recordings/{adapter}/{deviceId}", async (string adapter
return Results.Ok(await a.GetRecordingsAsync(deviceId, start, end, page, size));
});
// B3: 手动同步
// B3: 手动同步 — 触发适配器全量设备同步
app.MapPost("/api/gateway/devices/sync", async (string adapter) =>
{
var a = registry.FindByCode<IGatewayAdapter>(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" });
return Results.Ok(new { nodeCount = obj.Count, message = "对象树同步完成" });
}
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 { deviceCount = dev.Total, message = "设备列表同步完成" });
}
return Results.Ok(new { message = "no sync needed" });
return Results.Ok(new { message = "无需同步" });
});
app.Run();
// 请求 DTO
// ═══════════════════════════════════════════════
// B 组请求 DTO
// ═══════════════════════════════════════════════
/// <summary>云台控制请求</summary>
/// <param name="Direction">方向up/down/left/right/zoom_in/zoom_out/stop</param>
/// <param name="Action">动作类型continuous 或 stop</param>
/// <param name="Speed">速度 0.0-1.0</param>
record PtzRequest(string? Direction, string Action, float Speed);
/// <summary>设备控制请求</summary>
/// <param name="DeviceId">目标设备 SourceId</param>
/// <param name="PointIndex">点位索引</param>
/// <param name="Value">目标值</param>
record ControlRequest(string? DeviceId, int PointIndex, double Value);