dev_lx #6

Merged
LiuXin merged 2 commits from dev_lx into main 4 months ago
  1. 65
      WeiCloud.Fusion/AlarmService/Alarm.Application/RequestDto/SubscribeEventReqDto.cs
  2. 217
      WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs
  3. 15
      WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/IDahuaGeneralCtlService.cs
  4. 18
      WeiCloud.Fusion/AlarmService/AlarmService.API/Controllers/AlarmController.cs
  5. 6
      WeiCloud.Fusion/AlarmService/AlarmService.API/Properties/launchSettings.json
  6. 5
      WeiCloud.Fusion/AlarmService/AlarmService.API/appsettings.json
  7. 4
      WeiCloud.Fusion/AspireApp/Manage.AppHost.AppHost/AppHost.cs
  8. 11
      WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs
  9. 47
      WeiCloud.Fusion/VideoService/Video.Application/RequestDto/DahuaVideoQueryDto.cs
  10. 13
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs
  11. 7
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IDahuaGeneralCtlService.cs
  12. 7
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IRootVideoPlaybackService.cs
  13. 10
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs

@ -5,85 +5,66 @@ namespace Alarm.Application.RequestDto
public sealed class SubscribeReqDto public sealed class SubscribeReqDto
{ {
[JsonPropertyName("param")] [JsonPropertyName("param")]
public required SubscribeParam Param { get; init; } public SubscribeParam Param { get; set; } = new();
} }
public sealed class SubscribeParam public sealed class SubscribeParam
{ {
[JsonPropertyName("monitors")] [JsonPropertyName("monitors")]
public required List<MonitorEntry> Monitors { get; init; } public List<MonitorConfig> Monitors { get; set; } = new();
[JsonPropertyName("subsystem")] [JsonPropertyName("subsystem")]
public required SubsystemInfo Subsystem { get; init; } public SubsystemConfig Subsystem { get; set; } = new();
} }
public sealed class MonitorEntry public sealed class MonitorConfig
{ {
/// <summary>回调地址(ICC 能访问到)</summary> // 为避免歧义,内部命名用 MonitorUrl,映射到 JSON 的 "monitor"
[JsonPropertyName("monitor")] [JsonPropertyName("monitor")]
public required string Monitor { get; init; } public string? MonitorUrl { get; set; }
/// <summary>固定 url</summary>
[JsonPropertyName("monitorType")] [JsonPropertyName("monitorType")]
public string MonitorType { get; init; } = "url"; public string? MonitorType { get; set; }
/// <summary>事件大类订阅配置</summary>
[JsonPropertyName("events")] [JsonPropertyName("events")]
public required List<EventSubscribe> Events { get; init; } public List<EventConfig> Events { get; set; } = new();
} }
/// <summary>事件大类订阅(alarm / business / state / perception ...)</summary> public sealed class EventConfig
public sealed class EventSubscribe
{ {
[JsonPropertyName("category")] [JsonPropertyName("category")]
public required string Category { get; init; } // 用 string 保持向后兼容 public string? Category { get; set; }
/// <summary>1=订阅该大类全部(仍受 authorities 过滤),0=按维度筛选</summary> // 你的示例是 0/1 数字,这里保持 int;若你更想用 bool,可改成 bool 并写自定义转换
[JsonPropertyName("subscribeAll")] [JsonPropertyName("subscribeAll")]
public int SubscribeAll { get; init; } = 1; public int? SubscribeAll { get; set; }
/// <summary>级联:0=本级,1=下级,2=本级+下级</summary>
[JsonPropertyName("domainSubscribe")] [JsonPropertyName("domainSubscribe")]
public int DomainSubscribe { get; init; } = 0; public int? DomainSubscribe { get; set; }
/// <summary>权限过滤(可多组)</summary>
[JsonPropertyName("authorities")] [JsonPropertyName("authorities")]
public List<AuthorityFilter>? Authorities { get; init; } public List<Authority> Authorities { get; set; } = new();
/// <summary>仅 alarm 使用:0=事件,1=报警。未提供时默认 0</summary>
[JsonPropertyName("eventType")]
public int? EventType { get; init; }
/// <summary>报警级别过滤(仅 alarm 有意义),如 1/2/3 ...</summary>
[JsonPropertyName("grades")]
public List<int>? Grades { get; init; }
} }
/// <summary>权限过滤:缺省=订阅全部;空数组=不订阅。</summary> public sealed class Authority
public sealed class AuthorityFilter
{ {
/// <summary>事件/业务/感知子类型(如 "57", "car.capture")</summary> // 二选一的字段:有的事件给 types,有的给 nodeCodes
[JsonPropertyName("types")] [JsonPropertyName("types")]
public List<string>? Types { get; init; } public List<string>? Types { get; set; }
/// <summary>设备/通道编码</summary>
[JsonPropertyName("nodeCodes")] [JsonPropertyName("nodeCodes")]
public List<string>? NodeCodes { get; init; } public List<string>? NodeCodes { get; set; }
/// <summary>组织编码</summary>
[JsonPropertyName("orgs")]
public List<string>? Orgs { get; init; }
} }
public sealed class SubsystemInfo public sealed class SubsystemConfig
{ {
/// <summary>固定 0</summary>
[JsonPropertyName("subsystemType")] [JsonPropertyName("subsystemType")]
public int SubsystemType { get; init; } = 0; public int SubsystemType { get; set; }
[JsonPropertyName("name")] [JsonPropertyName("name")]
public required string Name { get; init; } public string? Name { get; set; }
[JsonPropertyName("magic")] [JsonPropertyName("magic")]
public required string Magic { get; init; } public string? Magic { get; set; }
} }
} }

@ -4,6 +4,7 @@ using Common.Shared.Application.DaHua;
using Common.Shared.DomainService; using Common.Shared.DomainService;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security; using Org.BouncyCastle.Security;
using System; using System;
@ -18,9 +19,10 @@ namespace Alarm.DomainService.DahAlarm
{ {
private readonly ILogger<DahuaGeneralCtlService> _logger; private readonly ILogger<DahuaGeneralCtlService> _logger;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private readonly HttpClient _http;
private readonly MQTTClient _mqttClient; private readonly MQTTClient _mqttClient;
private readonly IMqttClientService _mqttClientService; private readonly IMqttClientService _mqttClientService;
private readonly ITokenProviderService _tokenProviderService;
private string mqttHostIp; private string mqttHostIp;
private int mqttHostPort; private int mqttHostPort;
private int mqttTimeout; private int mqttTimeout;
@ -36,11 +38,11 @@ namespace Alarm.DomainService.DahAlarm
/// <param name="configuration"></param> /// <param name="configuration"></param>
/// <param name="http"></param> /// <param name="http"></param>
/// <param name="mQTTClient"></param> /// <param name="mQTTClient"></param>
public DahuaGeneralCtlService(ILogger<DahuaGeneralCtlService> logger, IConfiguration configuration, HttpClient http, MQTTClient mQTTClient, IMqttClientService mqttClientService) public DahuaGeneralCtlService(ILogger<DahuaGeneralCtlService> logger, IConfiguration configuration, MQTTClient mQTTClient, IMqttClientService mqttClientService, ITokenProviderService tokenProviderService)
{ {
_logger = logger; _logger = logger;
_configuration = configuration; _configuration = configuration;
_http = http;
_mqttClient = mQTTClient; _mqttClient = mQTTClient;
mqttHostIp = _configuration["SubscribeMQTT:HostIP"]!;//IP地址 mqttHostIp = _configuration["SubscribeMQTT:HostIP"]!;//IP地址
mqttHostPort = _configuration["SubscribeMQTT:HostPort"].ToInt();//端口号 mqttHostPort = _configuration["SubscribeMQTT:HostPort"].ToInt();//端口号
@ -50,112 +52,16 @@ namespace Alarm.DomainService.DahAlarm
mqttClientId = _configuration["SubscribeMQTT:ClientId"]!; mqttClientId = _configuration["SubscribeMQTT:ClientId"]!;
topicName = _configuration["SubscribeMQTT:TopicName"]!; topicName = _configuration["SubscribeMQTT:TopicName"]!;
_mqttClientService = mqttClientService; _mqttClientService = mqttClientService;
_tokenProviderService = tokenProviderService;
} }
/// <summary> /// <summary>
/// 获取公钥 /// 开发测试的时候,忽略证书
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<DaHApiResult<PublicKeyDto>> GetPublicKey()
{
DaHApiResult<PublicKeyDto> result = new() { Success = true, Code = "0", Data = new PublicKeyDto() { PublicKey = "" } };
try
{
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-oauth/1.0.0/oauth/public-key";
using var resp = await _http.GetAsync(url);
resp.EnsureSuccessStatusCode();
var json = await resp.Content.ReadAsStringAsync();
var envelope = JsonSerializer.Deserialize<DaHApiResult<PublicKeyDto>>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
if (envelope?.Data?.PublicKey is null or { Length: 0 })
{
_logger.LogWarning("获取大华公钥失败,返回结果:{Result}", json);
result.Success = false;
result.Code = "1001";
result.Msg = "获取大华公钥失败";
return result;
}
result.Data.PublicKey = envelope.Data.PublicKey;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "大华平台获取公钥出错");
}
return result;
}
/// <summary>
/// 获取token
/// </summary> /// </summary>
/// <param name="dto"></param> private static readonly HttpClient _http = new HttpClient(new HttpClientHandler
/// <returns></returns>
public async Task<DaHApiResult<LoginResDto>> GetToken(LoginRequestDto dto)
{ {
DaHApiResult<LoginResDto> result = new DaHApiResult<LoginResDto>() { Success = true, Code = "0" }; ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
if (dto is null) });
{
result.Success = false;
result.Code = "1002";
result.Msg = "请求参数不能为空";
_logger.LogWarning("获取大华登录令牌失败,参数不能为空");
return result;
}
if (string.IsNullOrWhiteSpace(dto.Password))
{
result.Success = false;
result.Code = "1003";
result.Msg = "密码不能为空";
_logger.LogWarning("获取大华登录令牌失败,密码不能为空");
return result;
}
try
{
//1. 获取公钥
DaHApiResult<PublicKeyDto> publicKeyResult = await GetPublicKey();
if (!publicKeyResult.Success)
{
result.Code = "500";
result.Msg = publicKeyResult.Msg;
_logger.LogWarning("获取大华公钥失败:{Msg}", publicKeyResult.Msg);
}
//2. 鉴权
dto.PublicKey = publicKeyResult.Data.PublicKey;
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-oauth/1.0.0/oauth/extend/token";
//必须加密
dto.Password = EncryptByPublicKey(dto.Password, dto.PublicKey!);
using var resp = await _http.PostAsJsonAsync(url, dto);
resp.EnsureSuccessStatusCode();
var tokenInfo = await resp.Content.ReadFromJsonAsync<DaHApiResult<LoginResDto>>();
if (tokenInfo == null || !result.Success || result.Code != "0")
{
result.Success = false;
result.Code = "1004";
result.Msg = "获取大华登录令牌失败";
_logger.LogWarning("获取大华登录令牌失败,返回结果:{Result}", result);
}
//固定的拼接方式
result.Data.AccessToken = string.Concat(tokenInfo!.Data.TokenType, " ", tokenInfo.Data.AccessToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取大华登录令牌出错");
result.Success = false;
result.Code = "1004";
result.Msg = "获取大华登录令牌失败";
}
return result;
}
/// <summary> /// <summary>
/// 新增报警事件订阅 /// 新增报警事件订阅
@ -163,13 +69,13 @@ namespace Alarm.DomainService.DahAlarm
/// <param name="dto"></param> /// <param name="dto"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
public async Task<DaHApiResult<object>> AddSubscribeEvent(string accessToken) public async Task<DaHApiResult<object>> AddSubscribeEvent()
{ {
var result = new DaHApiResult<object> { Success = true, Code = "0", Data = new object() }; var result = new DaHApiResult<object> { Success = true, Code = "0", Data = new object() };
try try
{ {
var baseHost = _configuration["DahuaEvent:Host"]; var baseHost = _configuration["DahuaAuth:Host"];
if (string.IsNullOrWhiteSpace(baseHost)) if (string.IsNullOrWhiteSpace(baseHost))
{ {
return new DaHApiResult<object> return new DaHApiResult<object>
@ -186,28 +92,41 @@ namespace Alarm.DomainService.DahAlarm
{ {
Param = new SubscribeParam Param = new SubscribeParam
{ {
Monitors = new List<MonitorEntry> Monitors = new List<MonitorConfig>
{
new MonitorConfig
{
MonitorUrl = _configuration["DahuaAuth:Callback"],
MonitorType = "url",
Events = new List<EventConfig>
{ {
new() new EventConfig
{ {
Monitor = _configuration["DahuaEvent:Callback"]!, Category = "alarm",
Events = SubscribeAll = 1,
[ DomainSubscribe = 2,
new() Authorities = new List<Authority>
{
new Authority
{ {
Category = "alarm", Types = new List<string> { "4321" }
SubscribeAll = 1,
DomainSubscribe = 2,
EventType = 1
} }
] }
} }
}, }
Subsystem = new SubsystemInfo { SubsystemType = 0, Name = _configuration["DahuaEvent:SubsystemName"]!, Magic = _configuration["DahuaEvent:SubsystemMagic"]! } }
},
Subsystem = new SubsystemConfig
{
SubsystemType = 0,
Name = "192.168.21.43_alarm",
Magic = "192.168.21.43"
}
} }
}; };
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
// —— 发起请求 —— // —— 发起请求 ——
using var request = new HttpRequestMessage(HttpMethod.Post, url) using var request = new HttpRequestMessage(HttpMethod.Post, url)
{ {
@ -219,7 +138,7 @@ namespace Alarm.DomainService.DahAlarm
}; };
// 大华网关要求:Authorization 放完整值(Bearer xxx) // 大华网关要求:Authorization 放完整值(Bearer xxx)
request.Headers.TryAddWithoutValidation("Authorization", accessToken); request.Headers.TryAddWithoutValidation("Authorization", token);
request.Headers.Accept.ParseAdd("application/json"); request.Headers.Accept.ParseAdd("application/json");
using var resp = await _http.SendAsync(request); using var resp = await _http.SendAsync(request);
@ -303,61 +222,5 @@ namespace Alarm.DomainService.DahAlarm
} }
return result; return result;
} }
#region RES加密
private static String EncryptByPublicKey(String context, String publicKey)
{
RSACryptoServiceProvider rsa = new();
rsa.ImportParameters(FromXmlStringExtensions(ConvertToXmlPublicJavaKey(publicKey)));
byte[] byteText = System.Text.Encoding.UTF8.GetBytes(context);
byte[] byteEntry = rsa.Encrypt(byteText, false);
return Convert.ToBase64String(byteEntry);
}
public static RSAParameters FromXmlStringExtensions(string xmlString)
{
RSAParameters parameters = new RSAParameters();
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.LoadXml(xmlString);
if (xmlDoc.DocumentElement!.Name.Equals("RSAKeyValue"))
{
foreach (System.Xml.XmlNode node in xmlDoc.DocumentElement.ChildNodes)
{
switch (node.Name)
{
case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
}
}
}
else
{
throw new Exception("Invalid XML RSA key.");
}
return parameters;
}
public static string ConvertToXmlPublicJavaKey(string publicJavaKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicJavaKey));
string xmlpublicKey = string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
Console.WriteLine(xmlpublicKey);
return xmlpublicKey;
}
#endregion RES加密
} }
} }

@ -9,25 +9,12 @@ namespace Alarm.DomainService.DahAlarm
/// </summary> /// </summary>
public interface IDahuaGeneralCtlService public interface IDahuaGeneralCtlService
{ {
/// <summary>
/// 获取公钥
/// </summary>
/// <returns></returns>
Task<DaHApiResult<PublicKeyDto>> GetPublicKey();
/// <summary>
/// 鉴权
/// </summary>
/// <param name="pKey">PublicKey</param>
/// <returns></returns>
Task<DaHApiResult<LoginResDto>> GetToken(LoginRequestDto dto);
/// <summary> /// <summary>
/// 新增订阅报警事件 /// 新增订阅报警事件
/// </summary> /// </summary>
/// <param name="dto"></param> /// <param name="dto"></param>
/// <returns></returns> /// <returns></returns>
Task<DaHApiResult<object>> AddSubscribeEvent(string accessToken); Task<DaHApiResult<object>> AddSubscribeEvent();
/// <summary> /// <summary>
/// AddSubscribeEvent回调函数处理 /// AddSubscribeEvent回调函数处理

@ -20,26 +20,14 @@ namespace AlarmService.API.Controllers
_generalCtlService = generalCtlService; _generalCtlService = generalCtlService;
} }
/// <summary>
/// 大华视频的登录获取Token
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("token/dh")]
public async Task<DaHApiResult<LoginResDto>> GetDaHToken(LoginRequestDto dto)
{
return await _generalCtlService.GetToken(dto);
}
/// <summary> /// <summary>
/// 订阅报警事件 /// 订阅报警事件
/// </summary> /// </summary>
/// <param name="accessToken"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<DaHApiResult<object>> AddSubscribeEvent(string accessToken) public async Task<DaHApiResult<object>> AddSubscribeEvent()
{ {
return await _generalCtlService.AddSubscribeEvent(accessToken); return await _generalCtlService.AddSubscribeEvent();
} }
/// <summary> /// <summary>
@ -48,7 +36,7 @@ namespace AlarmService.API.Controllers
/// <param name="env"></param> /// <param name="env"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<ApiResult<bool>> HandleAsync(EventEnvelopeDto env) public async Task<ApiResult<bool>> DahuaAuthCallback(EventEnvelopeDto env)
{ {
return await _generalCtlService.HandleAsync(env); return await _generalCtlService.HandleAsync(env);
} }

@ -13,7 +13,7 @@
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "weatherforecast", "launchUrl": "swagger",
"applicationUrl": "http://localhost:5283", "applicationUrl": "http://localhost:5283",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
@ -23,7 +23,7 @@
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "weatherforecast", "launchUrl": "swagger",
"applicationUrl": "https://localhost:7230;http://localhost:5283", "applicationUrl": "https://localhost:7230;http://localhost:5283",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
@ -32,7 +32,7 @@
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "weatherforecast", "launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }

@ -24,6 +24,9 @@
"ClientSecret": "6d6c78f8-3d4c-4e76-ab6b-827942a7b725", "ClientSecret": "6d6c78f8-3d4c-4e76-ab6b-827942a7b725",
"Username": "system", "Username": "system",
"Password": "Admin123" "Password": "Admin123",
"Callback": "http://demo.weienergy.cn:5000/api/Alarm/DahuaAuthCallback",
"SubsystemName": "192.168.21.43_alarm",
"SubsystemMagic": "192.168.21.43"
} }
} }

@ -6,12 +6,10 @@ var apiService = builder.AddProject<Projects.Manage_AppHost_ApiService>("apiserv
var videoapi = builder.AddProject<Projects.Video_API>("videoapi"); var videoapi = builder.AddProject<Projects.Video_API>("videoapi");
var alarmapi = builder.AddProject<Projects.AlarmService_API>("alarmapi"); var alarmapi = builder.AddProject<Projects.AlarmService_API>("alarmapi");
var sharedapi = builder.AddProject<Projects.Common_Shared_API>("sharedapi");
builder.AddProject<Projects.Manage_AppHost_Web>("webfrontend") builder.AddProject<Projects.Manage_AppHost_Web>("webfrontend")
.WithReference(videoapi) .WithReference(videoapi)
.WithReference(alarmapi) .WithReference(alarmapi)
.WithReference(sharedapi)
.WithExternalHttpEndpoints() .WithExternalHttpEndpoints()
.WithHttpHealthCheck("/health") .WithHttpHealthCheck("/health")
.WithReference(apiService) .WithReference(apiService)

@ -141,6 +141,17 @@ namespace Video.API.Controllers.DaHua
return await _rootVideoPlaybackService.Logout(authorization, openId, userClient); return await _rootVideoPlaybackService.Logout(authorization, openId, userClient);
} }
/// <summary>
/// 返回下载地址
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpGet("download")]
public async Task<string> Download(DownloadReqDto dto)
{
return await _rootVideoPlaybackService.Download(dto);
}
#endregion 大华视频处理 #endregion 大华视频处理
} }
} }

@ -336,4 +336,51 @@ namespace Video.Application
[JsonPropertyName("recordType")] [JsonPropertyName("recordType")]
public string RecordType { get; set; } public string RecordType { get; set; }
} }
public class DownloadReqDto
{
/// <summary>
/// 1. 通道编号(必选)
/// 组成=设备编码%24通道号;
/// 例如:通道编码是1000006$1$0$25,则通道编号为1000006%2425
/// </summary>
[JsonPropertyName("vcuid")]
public required string Vcuid { get; set; }
/// <summary>
/// 2. 码流类型(必选)
/// 1-主码流 2-辅码流
/// </summary>
[JsonPropertyName("subtype")]
public required string Subtype { get; set; } = "1";
/// <summary>
/// 3. 开始时间(必选)
/// 格式:2023_3_23_14_48_36
/// </summary>
[JsonPropertyName("starttime")]
public required string StartTime { get; set; }
/// <summary>
/// 4. 结束时间(必选)
/// 格式:2023_3_23_18_48_36
/// </summary>
[JsonPropertyName("endtime")]
public required string EndTime { get; set; }
/// <summary>
/// 5. 录像回放类型(必选)
/// 2-设备录像 3-中心录像
/// </summary>
[JsonPropertyName("videoType")]
public required string VideoType { get; set; }
/// <summary>
/// 7. 录像类型(必选)
/// 录像存储为设备录像时,即videoType=2时,recordType固定送0;
/// 录像存储是中心存储时,即videoType=3时,参考枚举:1:普通录像 2:报警录像 81:补录录像 82:预录录像
/// </summary>
[JsonPropertyName("recordType")]
public required string RecordType { get; set; }
}
} }

@ -404,5 +404,18 @@ namespace Video.DomainService
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1010", Msg = "实时流请求失败" }; return new DaHApiResult<UrlDataDto> { Success = false, Code = "1010", Msg = "实时流请求失败" };
} }
} }
/// <summary>
/// 下载
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<string> Download(DownloadReqDto dto)
{
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
return _configuration["DahuaAuth:Host"] + $"/evo-apigw/evo-httpnode/vod/cam/download.mp4?vcuid={dto.Vcuid}&subtype={dto.Subtype}&starttime={dto.StartTime}endtime={dto.EndTime}&videoType={dto.VideoType}&token={token}&recordType={dto.RecordType}";
}
} }
} }

@ -56,5 +56,12 @@ namespace Video.DomainService
/// 没有返回值 /// 没有返回值
/// </summary> /// </summary>
Task<DaHApiResult<object>> Logout(string authorization, string? openId, int? userClient); Task<DaHApiResult<object>> Logout(string authorization, string? openId, int? userClient);
/// <summary>
/// 返回下载地址
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
Task<string> Download(DownloadReqDto dto);
} }
} }

@ -49,5 +49,12 @@ namespace Video.DomainService
/// <param name="userClient"></param> /// <param name="userClient"></param>
/// <returns></returns> /// <returns></returns>
Task<ApiResult<object>> Logout(string authorization, string? openId, int? userClient); Task<ApiResult<object>> Logout(string authorization, string? openId, int? userClient);
/// <summary>
/// 返回下载地址
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
Task<string> Download(DownloadReqDto dto);
} }
} }

@ -157,6 +157,16 @@ namespace Video.DomainService
return result; return result;
} }
/// <summary>
/// 返回下载地址
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<string> Download(DownloadReqDto dto)
{
return await _dahuaGeneralCtlService.Download(dto);
}
#endregion 大华视频处理 #endregion 大华视频处理
} }
} }
Loading…
Cancel
Save