Files
SecMPS/api_sqlsugar/VolPro.WebApi/Controllers/Warehouse/Partial/gateway_nodesController.cs

229 lines
9.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
*网关节点管理 — A1注册/A2心跳/A3设备同步/A4告警同步
*A组接口使用 [AllowAnonymous] + NodeToken 二次认证
*所有改动在 Partial 目录,不破坏框架可升级性
*/
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using VolPro.Entity.DomainModels;
using Warehouse.IServices;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace Warehouse.Controllers
{
public partial class gateway_nodesController
{
/// <summary>A1: 网关注册Upsert。认证方式: NodeToken</summary>
[HttpPost]
[Route("/api/gateway/register")]
[AllowAnonymous]
public async Task<IActionResult> RegisterGateway([FromBody] GatewayRegisterRequest req)
{
if (string.IsNullOrEmpty(req.NodeCode) || string.IsNullOrEmpty(req.Token))
return BadRequest(new { message = "NodeCode 和 Token 为必填项" });
try
{
var node = await _service.RegisterNodeAsync(req.NodeCode, req.Token, req.AdapterTypes, req.BaseUrl);
// 返回当前网关的顶层设备列表
var deviceSvc = _service.GetType().Assembly.GetType("Warehouse.Services.base_deviceService")
?.GetProperty("Instance")?.GetValue(null) as Ibase_deviceService;
var devices = deviceSvc != null
? await deviceSvc.GetDevicesByGatewayNodeAsync(node.NodeId)
: new List<base_device>();
return Ok(new { nodeId = node.NodeId, devices = devices.Select(d => new {
d.DeviceId, d.DeviceName, d.AdapterCode, d.SourceId,
d.DeviceCategory, d.DeviceGroup, d.IsParent, d.IsOnline, d.ExtraData
}) });
}
catch (UnauthorizedAccessException)
{
return StatusCode(401, new { message = "认证失败Token 无效" });
}
}
/// <summary>A2: 心跳。认证方式: NodeToken。每15秒调用一次。</summary>
[HttpPost]
[Route("/api/gateway/heartbeat")]
[AllowAnonymous]
public async Task<IActionResult> GatewayHeartbeat([FromBody] GatewayHeartbeatRequest req)
{
if (string.IsNullOrEmpty(req.NodeCode) || string.IsNullOrEmpty(req.Token))
return BadRequest(new { message = "NodeCode 和 Token 为必填项" });
try
{
await _service.UpdateHeartbeatAsync(req.NodeCode, req.Token);
return Ok(new { status = "ok", serverTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
}
catch (UnauthorizedAccessException)
{
return StatusCode(401, new { message = "认证失败" });
}
}
/// <summary>A3: 设备数据同步(字段分治 + parentSourceId 映射)。认证方式: NodeToken</summary>
[HttpPost]
[Route("/api/gateway/sync/devices")]
[AllowAnonymous]
public async Task<IActionResult> SyncDevices([FromBody] SyncDevicesRequest req)
{
if (string.IsNullOrEmpty(req.NodeCode) || string.IsNullOrEmpty(req.Token))
return BadRequest(new { message = "NodeCode 和 Token 为必填项" });
try
{
// 认证
var node = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode && x.NodeToken == req.Token)
.FirstOrDefaultAsync();
if (node == null) return StatusCode(401, new { message = "认证失败" });
var items = req.Devices.Select(d => new SyncDeviceItem
{
AdapterCode = d.AdapterCode,
SourceId = d.SourceId,
Name = d.Name,
Category = d.Category,
Group = d.Group,
IsParent = d.IsParent,
ParentSourceId = d.ParentSourceId,
IsOnline = d.IsOnline,
IpAddress = d.IpAddress,
Port = d.Port,
ExtraDataJson = d.ExtraDataJson
}).ToList();
var (added, updated) = await _service.SyncDevicesAsync(node.NodeId, items);
return Ok(new { added, updated, removed = 0 });
}
catch (UnauthorizedAccessException)
{
return StatusCode(401, new { message = "认证失败" });
}
}
/// <summary>A4: 告警同步DeviceSourceId→DeviceId 映射 + SourceAlarmId 去重)。认证方式: NodeToken</summary>
[HttpPost]
[Route("/api/gateway/sync/alarms")]
[AllowAnonymous]
public async Task<IActionResult> SyncAlarms([FromBody] SyncAlarmsRequest req)
{
if (string.IsNullOrEmpty(req.NodeCode) || string.IsNullOrEmpty(req.Token))
return BadRequest(new { message = "NodeCode 和 Token 为必填项" });
try
{
var node = await _service.FindAsIQueryable(x => x.NodeCode == req.NodeCode && x.NodeToken == req.Token)
.FirstOrDefaultAsync();
if (node == null) return StatusCode(401, new { message = "认证失败" });
// 获取告警服务
var alarmSvcType = _service.GetType().Assembly.GetType("Warehouse.Services.iot_alarmService");
var alarmSvc = alarmSvcType?.GetProperty("Instance")?.GetValue(null) as Iiot_alarmService;
// 批量查询 DeviceSourceId → DeviceId 映射
var deviceSvcType = _service.GetType().Assembly.GetType("Warehouse.Services.base_deviceService");
var deviceSvc = deviceSvcType?.GetProperty("Instance")?.GetValue(null) as Ibase_deviceService;
int added = 0;
foreach (var a in req.Alarms)
{
int? deviceId = null;
if (deviceSvc != null)
{
var dev = await deviceSvc.FindAsIQueryable(
x => x.AdapterCode == a.AdapterCode && x.SourceId == a.DeviceSourceId)
.Select(x => new { x.DeviceId })
.FirstOrDefaultAsync();
deviceId = dev?.DeviceId;
}
if (alarmSvc != null)
{
var alarmItem = new SyncAlarmItem
{
SourceAlarmId = a.SourceAlarmId,
DeviceSourceId = a.DeviceSourceId,
AdapterCode = a.AdapterCode,
Level = a.Level,
Desc = a.Desc,
Value = a.Value,
StartTime = a.StartTime
};
await alarmSvc.UpsertAlarmAsync(alarmItem, deviceId);
added++;
}
}
return Ok(new { added });
}
catch (UnauthorizedAccessException)
{
return StatusCode(401, new { message = "认证失败" });
}
}
}
// ── A 组请求 DTO ──
public class GatewayRegisterRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public string AdapterTypes { get; set; } = "";
public string BaseUrl { get; set; } = "";
}
public class GatewayHeartbeatRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
}
public class SyncDevicesRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public List<SyncDeviceItemDto> Devices { get; set; } = new();
}
public class SyncDeviceItemDto
{
public string AdapterCode { get; set; } = "";
public string SourceId { get; set; } = "";
public string? Name { get; set; }
public string? Category { get; set; }
public string? Group { get; set; }
public bool IsParent { get; set; }
public string? ParentSourceId { get; set; }
public bool IsOnline { get; set; }
public string? IpAddress { get; set; }
public int? Port { get; set; }
public string? ExtraDataJson { get; set; }
}
public class SyncAlarmsRequest
{
public string NodeCode { get; set; } = "";
public string Token { get; set; } = "";
public List<SyncAlarmItemDto> Alarms { get; set; } = new();
}
public class SyncAlarmItemDto
{
public string SourceAlarmId { get; set; } = "";
public string DeviceSourceId { get; set; } = "";
public string AdapterCode { get; set; } = "";
public string Level { get; set; } = "";
public string Desc { get; set; } = "";
public double? Value { get; set; }
public string StartTime { get; set; } = "";
}
}