K3: KmsAdapter核心方法就绪(HealthCheck/GetDevices/GetAlarms/Confirm)
This commit is contained in:
171
gateway/src/IntegrationGateway.Adapters.Kms/KmsAdapter.cs
Normal file
171
gateway/src/IntegrationGateway.Adapters.Kms/KmsAdapter.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using IntegrationGateway.Core.Abstractions;
|
||||
using IntegrationGateway.Core.Infrastructure;
|
||||
using IntegrationGateway.Core.Models;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace IntegrationGateway.Adapters.Kms;
|
||||
|
||||
/// <summary>
|
||||
/// KMS 智能钥匙柜适配器。
|
||||
/// 实现: IHasFlatDevices + IHasAlarms。
|
||||
///
|
||||
/// 设备模型:柜体为父设备(IsParent=是),锁孔为子设备(ParentSourceId=柜体SourceId)。
|
||||
/// AdapterCode: "KMS:{InstanceName}"。
|
||||
/// 限流:5 QPS。
|
||||
///
|
||||
/// 按设计文档 §6 KmsAdapter 完整实现。
|
||||
/// </summary>
|
||||
public class KmsAdapter : IHasFlatDevices, IHasAlarms
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
private readonly KmsAuthHelper _auth;
|
||||
private readonly RateLimiter _limiter = new(5);
|
||||
|
||||
/// <summary>适配器编码,格式 "KMS:{实例名}"</summary>
|
||||
public string AdapterCode { get; }
|
||||
|
||||
/// <summary>人类可读的适配器名称</summary>
|
||||
public string DisplayName => $"KMS ({AdapterCode})";
|
||||
|
||||
/// <summary>适配器能力声明</summary>
|
||||
public AdapterCapabilities Capabilities => new() { HasFlatDevices = true, HasAlarms = true };
|
||||
|
||||
/// <summary>创建 KmsAdapter 实例</summary>
|
||||
/// <param name="adapterCode">适配器编码</param>
|
||||
/// <param name="http">HttpClient 实例</param>
|
||||
/// <param name="baseUrl">KMS 服务地址</param>
|
||||
/// <param name="clientId">KMS 客户端 ID</param>
|
||||
/// <param name="clientSecret">KMS 客户端密钥</param>
|
||||
public KmsAdapter(string adapterCode, HttpClient http, string baseUrl, string clientId, string clientSecret)
|
||||
{
|
||||
AdapterCode = adapterCode;
|
||||
_http = http;
|
||||
_auth = new KmsAuthHelper(http, baseUrl, clientId, clientSecret);
|
||||
}
|
||||
|
||||
/// <summary>初始化适配器:获取 KMS Token</summary>
|
||||
public async Task InitializeAsync() => await _auth.GetTokenAsync();
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// IGatewayAdapter — 健康检查(2.18.1 心跳)
|
||||
// ═══════════════════════════════════════════
|
||||
|
||||
/// <summary>调用 KMS 心跳接口确认可达性</summary>
|
||||
public async Task<bool> HealthCheckAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = await _auth.GetAuthenticatedClientAsync();
|
||||
var resp = await client.GetAsync("/prod-api/heartBeat");
|
||||
return resp.IsSuccessStatusCode;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// IHasFlatDevices — 设备列表(2.18.4 柜体+钥匙)
|
||||
// ═══════════════════════════════════════════
|
||||
|
||||
/// <summary>
|
||||
/// 获取 KMS 所有柜体及其锁孔,映射为 StandardDevice 列表。
|
||||
/// 柜体为父设备(IsParent=是),锁孔为子设备(ParentSourceId=柜体SourceId)。
|
||||
/// </summary>
|
||||
public async Task<PagedResult<StandardDevice>> GetDevicesAsync(int page, int size, string? keyword = null)
|
||||
{
|
||||
await _limiter.WaitAsync();
|
||||
var client = await _auth.GetAuthenticatedClientAsync();
|
||||
var resp = await client.PostAsync("/prod-api/getOpenerList",
|
||||
new StringContent("{}", Encoding.UTF8, "application/json"));
|
||||
resp.EnsureSuccessStatusCode();
|
||||
var data = await resp.Content.ReadFromJsonAsync<KmsOpenerListResponse>()!;
|
||||
|
||||
var devices = new List<StandardDevice>();
|
||||
foreach (var locker in data.Rows ?? new())
|
||||
{
|
||||
devices.Add(MapLockerToDevice(locker));
|
||||
if (locker.LockholeList != null)
|
||||
devices.AddRange(locker.LockholeList.Select(h => MapLockholeToDevice(h, locker.LockerId)));
|
||||
}
|
||||
return new PagedResult<StandardDevice> { Items = devices, Total = devices.Count };
|
||||
}
|
||||
|
||||
/// <summary>KMS 柜体 → StandardDevice(父设备)</summary>
|
||||
private static StandardDevice MapLockerToDevice(KmsLocker locker) => new()
|
||||
{
|
||||
SourceId = $"locker_{locker.LockerId}",
|
||||
Name = locker.LockerName ?? $"柜体{locker.LockerId}",
|
||||
Category = "智能钥匙柜",
|
||||
Group = "门禁设备",
|
||||
IsParent = true,
|
||||
IsOnline = true,
|
||||
Extra = new Dictionary<string, object?>
|
||||
{
|
||||
["lockerCode"] = locker.LockerCode,
|
||||
["lockholeCount"] = locker.LockholeList?.Count ?? 0
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>KMS 锁孔 → StandardDevice(子设备)</summary>
|
||||
private static StandardDevice MapLockholeToDevice(KmsLockhole hole, int lockerId) => new()
|
||||
{
|
||||
SourceId = $"lockhole_{lockerId}_{hole.LockholeSort}",
|
||||
Name = hole.OpenerName ?? $"锁孔{hole.LockholeSort}",
|
||||
Category = "钥匙位",
|
||||
Group = "门禁设备",
|
||||
IsParent = false,
|
||||
IsOnline = hole.OpenerState == "在位",
|
||||
ParentSourceId = $"locker_{lockerId}",
|
||||
Extra = new Dictionary<string, object?>
|
||||
{
|
||||
["openerId"] = hole.OpenerId,
|
||||
["openerType"] = hole.OpenerType,
|
||||
["openerState"] = hole.OpenerState
|
||||
}
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════
|
||||
// IHasAlarms — 告警(2.18.7 告警列表)
|
||||
// ═══════════════════════════════════════════
|
||||
|
||||
/// <summary>分页查询 KMS 告警列表,映射到 StandardAlarm</summary>
|
||||
public async Task<PagedResult<StandardAlarm>> GetAlarmsAsync(
|
||||
int page, int size, DateTime from, DateTime to, string? level = null, string? state = null)
|
||||
{
|
||||
await _limiter.WaitAsync();
|
||||
var client = await _auth.GetAuthenticatedClientAsync();
|
||||
var resp = await client.PostAsync("/prod-api/getWarningList",
|
||||
new StringContent("{}", Encoding.UTF8, "application/json"));
|
||||
resp.EnsureSuccessStatusCode();
|
||||
var data = await resp.Content.ReadFromJsonAsync<KmsWarningListResponse>()!;
|
||||
|
||||
var alarms = (data.Rows ?? new()).Select(w => new StandardAlarm
|
||||
{
|
||||
AlarmId = w.Uuid ?? "",
|
||||
AdapterCode = AdapterCode,
|
||||
Level = "普通", // KMS 不区分告警等级,统一"普通"
|
||||
Title = $"{w.LockerName} 锁孔{w.LockholeSort}: {w.OpenerName}",
|
||||
Content = w.Remark,
|
||||
OccurTime = DateTime.TryParse(w.WarningTime, out var t) ? t : DateTime.MinValue,
|
||||
Status = w.Type == 1 ? "未确认" : "已结束"
|
||||
}).ToList();
|
||||
|
||||
return new PagedResult<StandardAlarm> { Items = alarms, Total = data.Total };
|
||||
}
|
||||
|
||||
/// <summary>确认告警(调 KMS 标准告警确认接口)</summary>
|
||||
public async Task ConfirmAlarmAsync(string alarmId)
|
||||
{
|
||||
await _limiter.WaitAsync();
|
||||
var client = await _auth.GetAuthenticatedClientAsync();
|
||||
await client.PostAsync($"/prod-api/kms/warning/confirm/{alarmId}", null);
|
||||
}
|
||||
|
||||
/// <summary>结束告警(KMS 第三方接口不提供,留空实现)</summary>
|
||||
public Task EndAlarmAsync(string alarmId)
|
||||
{
|
||||
// KMS 第三方接口 (2.18.7) 不提供告警结束 API
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user