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.
329 lines
13 KiB
329 lines
13 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 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) |
|
{ |
|
_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; |
|
} |
|
|
|
/// <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/1000014"; |
|
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(); |
|
} |
|
} |
|
} |