diff --git a/api_sqlsugar/Warehouse/Services/device_manager/Partial/base_deviceService.cs b/api_sqlsugar/Warehouse/Services/device_manager/Partial/base_deviceService.cs
index fc7a46b..290a12a 100644
--- a/api_sqlsugar/Warehouse/Services/device_manager/Partial/base_deviceService.cs
+++ b/api_sqlsugar/Warehouse/Services/device_manager/Partial/base_deviceService.cs
@@ -59,7 +59,8 @@ namespace Warehouse.Services
/// 同步设备条目
/// 网关节点ID
/// 已有设备映射表 (AdapterCode, SourceId) → DeviceId
- public async Task UpsertDeviceAsync(SyncDeviceItem d, int gatewayNodeId, Dictionary<(string, string), int> existingIds)
+ [Obsolete("已迁移至 gateway_nodesService.SyncDevicesAsync")]
+ public async Task UpsertDeviceAsync(SyncDeviceItem d, int gatewayNodeId, Dictionary<(string, string), int> existingIds)
{
var db = _repository.DbContext;
var key = (d.AdapterCode, d.SourceId);
diff --git a/api_sqlsugar/Warehouse/Services/device_manager/Partial/gateway_nodesService.cs b/api_sqlsugar/Warehouse/Services/device_manager/Partial/gateway_nodesService.cs
index 4147785..b601647 100644
--- a/api_sqlsugar/Warehouse/Services/device_manager/Partial/gateway_nodesService.cs
+++ b/api_sqlsugar/Warehouse/Services/device_manager/Partial/gateway_nodesService.cs
@@ -49,8 +49,8 @@ namespace Warehouse.Services
///
public async Task RegisterNodeAsync(string nodeCode, string token, string adapterTypes, string baseUrl)
{
- var existing = _repository.DbContext.Queryable()
- .First(x => x.NodeCode == nodeCode);
+ var existing = await _repository.FindAsIQueryable()
+ .FirstOrDefaultAsync(x => x.NodeCode == nodeCode);
gateway_nodes entity;
if (existing != null)
@@ -91,8 +91,8 @@ namespace Warehouse.Services
///
public async Task UpdateHeartbeatAsync(string nodeCode, string token)
{
- var entity = _repository.DbContext.Queryable()
- .First(x => x.NodeCode == nodeCode && x.NodeToken == token);
+ var entity = _repository.FindAsIQueryable()
+ .FirstOrDefaultAsync(x => x.NodeCode == nodeCode && x.NodeToken == token);
if (entity == null)
throw new UnauthorizedAccessException("认证失败:NodeCode 或 Token 无效");
diff --git a/gateway/src/IntegrationGateway.Host/Program.cs b/gateway/src/IntegrationGateway.Host/Program.cs
index b4141e7..72a55f1 100644
--- a/gateway/src/IntegrationGateway.Host/Program.cs
+++ b/gateway/src/IntegrationGateway.Host/Program.cs
@@ -92,22 +92,99 @@ Console.WriteLine($"[Gateway] {registry.All.Count} 个适配器已注册: {adapt
// ── A1: 向 Vol.Pro 注册当前网关节点 ──
var nodeCode = gwCfg["NodeCode"] ?? "gw-default";
var nodeToken = Environment.GetEnvironmentVariable("SECMPS_GATEWAY_TOKEN") ?? gwCfg["NodeToken"] ?? "";
+var port = app.Urls.FirstOrDefault()?.Split(':').LastOrDefault() ?? "5100";
+var selfUrl = gwCfg["SelfUrl"] ?? $"http://localhost:{port}";
try
{
var registerReq = new GatewayRegisterRequest
{
NodeCode = nodeCode, Token = nodeToken,
AdapterTypes = adapterTypes,
- BaseUrl = $"http://localhost:{app.Urls.FirstOrDefault()?.Split(':').LastOrDefault() ?? "5100"}"
+ BaseUrl = selfUrl
};
var registerResult = await clientFactory.RegisterAsync(registerReq);
Console.WriteLine($"[Gateway] A1 注册完成: nodeCode={nodeCode}, adapters={adapterTypes}");
}
catch (Exception ex) { Console.Error.WriteLine($"[Gateway] A1 注册失败: {ex.Message}"); }
+// ── A3: 同步所有适配器设备到 Vol.Pro ──
+await SyncAllDevicesAsync(nodeCode, nodeToken, selfUrl);
+Console.WriteLine("[Gateway] A3 设备同步完成");
+
+// ── A2: 心跳 + 自动重注册 ──
+var heartbeatInterval = int.TryParse(gwCfg["HeartbeatIntervalSec"], out var hs) ? hs : 15;
+var failCount = 0; var maxFails = 3;
+_ = Task.Run(async () =>
+{
+ using var timer = new PeriodicTimer(TimeSpan.FromSeconds(heartbeatInterval));
+ while (await timer.WaitForNextTickAsync())
+ {
+ try
+ {
+ await clientFactory.HeartbeatAsync(new GatewayHeartbeatRequest { NodeCode = nodeCode, Token = nodeToken });
+ failCount = 0;
+ }
+ catch
+ {
+ failCount++;
+ Console.Error.WriteLine($"[Gateway] A2 心跳失败 ({failCount}/{maxFails})");
+ if (failCount >= maxFails)
+ {
+ Console.WriteLine("[Gateway] 心跳连续失败, 尝试重新注册...");
+ try
+ {
+ await clientFactory.RegisterAsync(new GatewayRegisterRequest { NodeCode = nodeCode, Token = nodeToken, AdapterTypes = adapterTypes, BaseUrl = selfUrl });
+ await SyncAllDevicesAsync(nodeCode, nodeToken, selfUrl);
+ failCount = 0;
+ Console.WriteLine("[Gateway] 重新注册成功");
+ }
+ catch (Exception re) { Console.Error.WriteLine($"[Gateway] 重新注册失败: {re.Message}"); }
+ }
+ }
+ }
+});
+Console.WriteLine($"[Gateway] A2 心跳已启动 ({heartbeatInterval}s)");
+
// ═══════════════════════════════════════════════════════════════
-// B 组路由(管理端 / Vol.Pro → 网关)
-// 所有路由通过适配器编码查找对应适配器,按能力接口分发请求
+// A 组辅助函数
+// ═══════════════════════════════════════════════════════════════
+
+async Task SyncAllDevicesAsync(string nc, string nt, string baseUrl)
+{
+ var allDevices = new List