智慧建筑第三方功能集成微服务,目的是聚集所有涉及到第三方厂商调用的功能,按照业务功能划分不同微服务
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

333 lines
14 KiB

using Common.Shared.Application.DaHua;
using Common.Shared.DomainService;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Alarm.DomainService.DahAlarm
{
public class DahuaGeneralCtlService : IDahuaGeneralCtlService
{
private readonly ILogger<DahuaGeneralCtlService> _logger;
private readonly IConfiguration _configuration;
private readonly MQTTClient _mqttClient;
private readonly IMqttClientService _mqttClientService;
private readonly ITokenProviderService _tokenProviderService;
private readonly HttpClient _http;
private string mqttHostIp;
private int mqttHostPort;
private int mqttTimeout;
private string mqttUsername;
private string mqttPassword;
private string mqttClientId;
private string topicName;
/// <summary>
///
/// </summary>
/// <param name="logger"></param>
/// <param name="configuration"></param>
/// <param name="http"></param>
/// <param name="mQTTClient"></param>
public DahuaGeneralCtlService(ILogger<DahuaGeneralCtlService> logger, IConfiguration configuration, MQTTClient mQTTClient, IMqttClientService mqttClientService, ITokenProviderService tokenProviderService, HttpClient http)
{
_logger = logger;
_configuration = configuration;
_mqttClient = mQTTClient;
mqttHostIp = _configuration["SubscribeMQTT:HostIP"]!;//IP地址
mqttHostPort = _configuration["SubscribeMQTT:HostPort"].ToInt();//端口号
mqttTimeout = _configuration["SubscribeMQTT:Timeout"].ToInt();//超时时间
mqttUsername = _configuration["SubscribeMQTT:UserName"]!;//用户名
mqttPassword = _configuration["SubscribeMQTT:Password"]!;//密码
mqttClientId = _configuration["SubscribeMQTT:ClientId"]!;
topicName = _configuration["SubscribeMQTT:TopicName"]!;
_mqttClientService = mqttClientService;
_tokenProviderService = tokenProviderService;
_http = http;
}
///// <summary>
///// 开发测试的时候,忽略证书
///// </summary>
//private static readonly HttpClient _http = new(new HttpClientHandler
//{
// ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
//});
/// <summary>
/// 新增报警事件订阅
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DaHApiResult<object>> AddSubscribeEvent()
{
var result = new DaHApiResult<object> { Success = true, Code = "0", Data = new object() };
try
{
var baseHost = _configuration["DahuaAuth:Host"];
if (string.IsNullOrWhiteSpace(baseHost))
{
return new DaHApiResult<object>
{
Success = false,
Code = "2001",
Msg = "配置 DahuaEvent:Host 为空"
};
}
var url = $"https://{baseHost}/evo-apigw/evo-event/1.0.0/subscribe/mqinfo";
var req = new SubscribeReqDto
{
Param = new SubscribeParam
{
Monitors = new List<MonitorConfig>
{
new MonitorConfig
{
MonitorUrl = _configuration["DahuaAuth:Callback"],
MonitorType = "url",
Events = new List<EventConfig>
{
new EventConfig
{
Category = "alarm",
SubscribeAll = 1,
DomainSubscribe = 2,
Authorities = new List<Authority>
{
new Authority
{
Types = new List<string> { "4321" }
}
}
}
}
}
},
Subsystem = new SubsystemConfig
{
SubsystemType = 0,
Name = _configuration["DahuaAuth:SubsystemName"],
Magic = _configuration["DahuaAuth:SubsystemMagic"]
}
}
};
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (!_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("新增报警事件订阅:token无效");
return new DaHApiResult<object> { Success = false, Code = "1009", Msg = "token无效" };
}
// —— 发起请求 ——
using var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = JsonContent.Create(req, options: new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = new AllLowerCaseNamingPolicy()
})
};
// 大华网关要求:Authorization 放完整值(Bearer xxx)
request.Headers.TryAddWithoutValidation("Authorization", token);
request.Headers.Accept.ParseAdd("application/json");
using var resp = await _http.SendAsync(request);
var body = await resp.Content.ReadFromJsonAsync<DaHApiResult<object>>();
if (!resp.IsSuccessStatusCode || body is null)
{
return new DaHApiResult<object>
{
Success = false,
Code = "2002",
Msg = $"HTTP {resp.StatusCode} 或响应为空"
};
}
if (!(body.Success && string.Equals((string?)body.Code, "0", StringComparison.OrdinalIgnoreCase)))
{
return new DaHApiResult<object>
{
Success = false,
Code = body.Code ?? "2003",
Msg = body.Msg ?? "订阅失败"
};
}
result.Data = body;
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "大华事件订阅异常");
return new DaHApiResult<object>
{
Success = false,
Code = "2005",
Msg = "事件订阅异常"
};
}
}
/// <summary>
/// 报警事件订阅回调处理
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DaHApiResult<bool>> HandleAsync(EventEnvelopeDto dto)
{
DaHApiResult<bool> result = new() { Code = "200", Msg = "接口调用成功", Data = true };
try
{
if (dto is null)
{
result.Code = "500";
result.Msg = "请求参数不能为空";
result.Data = false;
_logger.LogWarning("大华报警事件订阅回调处理失败,参数不能为空");
return result;
}
if (dto.Info is not null)
{
//这是大华的残卫报警类型
if (dto.Info.AlarmType == 4321)
{
//拼接物联平台标准的mqtt消息格式
// var payload = "[{\"taglabel\":\"" + dto.Info.DeviceCode + ".alart." + dto.Info.DeviceName + "\",\"value\":\"" + dto.Info.AlarmStat + "\",\"time\":\"" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\"}]";
var payload = "[{\"taglabel\":\"残卫测试报警按钮.alarmStat\",\"value\":\"" + dto.Info.AlarmStat + "\",\"time\":\"" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\"}]";
await _mqttClient.EnsureConnectedAsync(mqttHostIp, mqttHostPort, mqttUsername, mqttPassword, topicName, mqttClientId);
await _mqttClientService.PublishAsync(topicName, payload);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "大华报警事件订阅回调处理异常");
result.Code = "500";
result.Msg = "大华报警事件订阅回调处理异常";
result.Data = false;
}
return result;
}
/// <summary>
/// 取消订阅某个报警事件
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<bool> DeleteEvent(string name)
{
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (!_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("取消订阅某个报警事件:token无效");
return false;
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-event/1.0.0/subscribe/mqinfo?name={name}";
try
{
var request = new HttpRequestMessage(HttpMethod.Delete, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Authorization", token);
using var resp = await _http.SendAsync(request);
var body = await resp.Content.ReadAsStringAsync();
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning("实时流请求 HTTP 失败: {Status}, Body: {Body}", (int)resp.StatusCode, body);
return false;
}
var result = JsonSerializer.Deserialize<DaHApiResult<object>>(body);
if (result == null || !result.Success)
{
_logger.LogWarning("实时流请求业务失败: {Body}", body);
return false;
}
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "大华实时流请求出错");
return false;
}
}
/// <summary>
/// 获取事件列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DaHApiResult<SubscriptionMapDto>> GetEventList(string name = "alarm")
{
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (!_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("获取事件列表:token无效");
return new DaHApiResult<SubscriptionMapDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-brm/1.0.0/device/1000021";
//var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-event/1.0.0/subscribe/subscribe-list?monitorType=url&category={name}";
try
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("Authorization", token);
using var resp = await _http.SendAsync(request);
var body = await resp.Content.ReadAsStringAsync();
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning("实时流请求 HTTP 失败: {Status}, Body: {Body}", (int)resp.StatusCode, body);
return new DaHApiResult<SubscriptionMapDto> { Success = false, Code = "1010", Msg = $"HTTP错误 {(int)resp.StatusCode}" };
}
var result = JsonSerializer.Deserialize<DaHApiResult<SubscriptionMapDto>>(body);
if (result == null || !result.Success)
{
_logger.LogWarning("实时流请求业务失败: {Body}", body);
return new DaHApiResult<SubscriptionMapDto> { Success = false, Code = "1010", Msg = "实时流请求失败" };
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "大华实时流请求出错");
return new DaHApiResult<SubscriptionMapDto> { Success = false, Code = "1010", Msg = "实时流请求失败" };
}
}
/// <summary>
/// 转换小写
/// </summary>
private class AllLowerCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) => name.ToLowerInvariant();
}
}
}