Merge pull request 'dev_lx' (#10) from dev_lx into main

Reviewed-on: #10
pull/13/head^2
刘鑫 3 months ago
commit e3be1d08c9
  1. 18
      WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs
  2. 4
      WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/Common.Shared.Application.csproj
  3. 2
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/ITokenProviderService.cs
  4. 40
      WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/TokenProviderService.cs
  5. 50
      WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs
  6. 4
      WeiCloud.Fusion/VideoService/Video.API/appsettings.json
  7. 53
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs
  8. 3
      WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs

@ -121,6 +121,12 @@ namespace Alarm.DomainService.DahAlarm
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)
{
@ -226,7 +232,11 @@ namespace Alarm.DomainService.DahAlarm
{
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
@ -269,7 +279,11 @@ namespace Alarm.DomainService.DahAlarm
{
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-event/1.0.0/subscribe/subscribe-list?monitorType=url&category={name}";
try

@ -7,11 +7,13 @@
</PropertyGroup>
<PropertyGroup>
<PackageId>Common.Shared.Application</PackageId>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<Authors>zrh-lx</Authors>
<Company>zrh-lx</Company> <!-- 可选 -->
<Description>包含所有公共使用的 DTO、契约、接口模型等,供微服务之间共享使用</Description>
<PackageTags>shared;dto;contracts;microservices</PackageTags> <!-- 可选但推荐 -->
<RepositoryUrl>https://v4.weienergy.cn/(可选)</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn> <!-- 可选:忽略未注释警告 -->
</PropertyGroup>
</Project>

@ -9,5 +9,7 @@ namespace Common.Shared.DomainService
public interface ITokenProviderService
{
Task<string> GetTokenAsync(string clientId);
bool IsTokenValid(string token);
}
}

@ -51,7 +51,8 @@ namespace Common.Shared.DomainService
}
var refreshed = await TryRefreshOrLoginAsync(clientId, tokenEntry);
return refreshed.AccessToken!;
return refreshed.AccessToken;
}
finally
{
@ -98,9 +99,12 @@ namespace Common.Shared.DomainService
{
refreshed = await GetDaHToken();
}
if (refreshed != null && refreshed.AccessToken != "")
{
// 更新缓存
TokenCache.TokenMap[clientId] = refreshed;
}
// 更新缓存
TokenCache.TokenMap[clientId] = refreshed;
return refreshed;
}
catch (Exception ex)
@ -118,10 +122,17 @@ namespace Common.Shared.DomainService
{
//1. 获取公钥
DaHApiResult<PublicKeyDto> publicKeyResult = await GetPublicKey();
if (publicKeyResult.Success == false)
{
return new TokenEntry
{
AccessToken = string.Empty,
ExpireAt = DateTimeOffset.UtcNow.AddMinutes(1)
};
}
LoginRequestDto dto = new();
//2. 鉴权
dto.PublicKey = publicKeyResult.Data.PublicKey;
dto.PublicKey = publicKeyResult.Data!.PublicKey;
dto.ClientId = _configuration["DahuaAuth:ClientId"]!;
dto.ClientSecret = _configuration["DahuaAuth:ClientSecret"]!;
dto.Password = _configuration["DahuaAuth:Password"]!;
@ -131,7 +142,7 @@ namespace Common.Shared.DomainService
TokenEntry refreshed = new()
{
AccessToken = loginResult.Data.AccessToken,
AccessToken = loginResult.Data!.AccessToken,
ExpireAt = DateTimeOffset.UtcNow.AddSeconds(120)
};
return refreshed;
@ -271,7 +282,7 @@ namespace Common.Shared.DomainService
}
result = tokenInfo!;
//固定的拼接方式
result.Data.AccessToken = string.Concat(tokenInfo?.Data.TokenType, " ", tokenInfo?.Data.AccessToken);
result.Data!.AccessToken = string.Concat(tokenInfo?.Data!.TokenType, " ", tokenInfo?.Data!.AccessToken);
TokenEntry refreshed = new TokenEntry
{
@ -290,6 +301,21 @@ namespace Common.Shared.DomainService
return result;
}
/// <summary>
/// 判断token是否有效
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public bool IsTokenValid(string token)
{
// 避免 NullReferenceException
if (string.IsNullOrWhiteSpace(token))
return true;
// 统一写法,后续改条件只改这里
return token.Length < 10;
}
#region RES加密
private static string EncryptByPublicKey(string context, string publicKey)

@ -92,7 +92,7 @@ namespace Video.API.Controllers.DaHua
/// <param name="dto"></param>
/// <returns></returns>
[HttpGet("download/dh")]
public async Task<IActionResult> DownloadVideoAsync(PlayDownloadReqDto dto)
public async Task<string> DownloadVideoAsync(PlayDownloadReqDto dto)
{
var remoteUrl =
$"https://{_configuration["DahHost"]}/evo-apigw/evo-httpnode/vod/cam/download.mp4" +
@ -103,28 +103,28 @@ namespace Video.API.Controllers.DaHua
$"&videoType={dto.VideoType}" +
$"&token={dto.Token}" +
$"&recordType={dto.RecordType}";
try
{
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
};
using var http = new HttpClient(handler);
var resp = await http.GetAsync(remoteUrl, HttpCompletionOption.ResponseHeadersRead);
resp.EnsureSuccessStatusCode();
var stream = await resp.Content.ReadAsStreamAsync();
var contentType = "video/mp4";
return File(stream, contentType, "video.mp4");
}
catch (Exception ex)
{
return StatusCode(500, new { success = false, message = "下载失败", error = ex.Message });
}
return await Task.FromResult(remoteUrl);
//try
//{
// var handler = new HttpClientHandler
// {
// ServerCertificateCustomValidationCallback = (_, _, _, _) => true
// };
// using var http = new HttpClient(handler);
// var resp = await http.GetAsync(remoteUrl, HttpCompletionOption.ResponseHeadersRead);
// resp.EnsureSuccessStatusCode();
// var stream = await resp.Content.ReadAsStreamAsync();
// var contentType = "video/mp4";
// return File(stream, contentType, "video.mp4");
//}
//catch (Exception ex)
//{
// return StatusCode(500, new { success = false, message = "下载失败", error = ex.Message });
//}
}
/// <summary>
@ -145,8 +145,8 @@ namespace Video.API.Controllers.DaHua
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpGet("download")]
public async Task<string> Download(DownloadReqDto dto)
[HttpPost("download")]
public async Task<string> GetDownUrl(DownloadReqDto dto)
{
return await _rootVideoPlaybackService.Download(dto);
}

@ -27,6 +27,10 @@
"DahuaAuth": {
"Host": "demo.weienergy.cn:15214",
"ClientId": "taiyanggong",
"RealRootHost": "192.168.21.18:9100", //RTSPicc
"RealReplaceHost": "demo.weienergy.cn:15210", //rtps
"TimeRootHost": "192.168.21.18:9320", //RTSPicc
"TimeReplaceHost": "demo.weienergy.cn:15211", //rtps
"ClientSecret": "6d6c78f8-3d4c-4e76-ab6b-827942a7b725",

@ -51,7 +51,11 @@ namespace Video.DomainService
// 2) Token:优先入参,其次缓存/获取(建议返回完整的 "Bearer xxx")
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("hls等录像回放:token无效");
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/record";
// 3) 构造请求(把 dto 放进 Body),并用 SendAsync 发送,才能带上头
@ -71,7 +75,7 @@ namespace Video.DomainService
}
var result = JsonSerializer.Deserialize<DaHApiResult<UrlDataDto>>(body);
if (result == null || !result.Success || result.Code != "0")
if (result == null || !result.Success)
{
_logger.LogWarning("录像请求业务失败: {Body}", body);
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1008", Msg = "录像请求失败" };
@ -103,7 +107,11 @@ namespace Video.DomainService
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("查询普通录像信息列表:token无效");
return new DaHApiResult<RecordsResDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Record/QueryRecords";
using var req = new HttpRequestMessage(HttpMethod.Post, url)
@ -124,7 +132,7 @@ namespace Video.DomainService
}
var result = JsonSerializer.Deserialize<DaHApiResult<RecordsResDto>>(body);
if (result == null || !result.Success || result.Code != "0")
if (result == null || !result.Success)
{
_logger.LogWarning("查询录像信息业务失败: {Body}", body);
return new DaHApiResult<RecordsResDto> { Success = false, Code = "1008", Msg = "查询录像信息失败" };
@ -156,6 +164,11 @@ namespace Video.DomainService
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("通道分页查询失败:token无效");
return new DaHApiResult<PageInfoDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-brm/1.2.0/device/channel/subsystem/page";
@ -177,7 +190,7 @@ namespace Video.DomainService
}
var result = JsonSerializer.Deserialize<DaHApiResult<PageInfoDto>>(body);
if (result == null || !result.Success || result.Code != "0")
if (result == null || !result.Success)
{
_logger.LogWarning("通道分页查询业务失败: {Body}", body);
return new DaHApiResult<PageInfoDto> { Success = false, Code = "1007", Msg = $"通道分页查询失败" };
@ -212,6 +225,11 @@ namespace Video.DomainService
// 2) Token:优先用入参;否则走缓存/获取(建议返回已带前缀的 "Bearer xxx")
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning(" HLS实时流请求失败:token无效");
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/realtime";
@ -232,7 +250,7 @@ namespace Video.DomainService
}
var result = JsonSerializer.Deserialize<DaHApiResult<UrlDataDto>>(body);
if (result == null || !result.Success || result.Code != "0")
if (result == null || !result.Success)
{
_logger.LogWarning("实时流请求业务失败: {Body}", body);
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1010", Msg = "实时流请求失败" };
@ -300,6 +318,7 @@ namespace Video.DomainService
/// <summary>
/// rtsp录像回放
/// (播放命令:ffplay -rtsp_transport tcp -i "rtsp://demo.weienergy.cn:15211/playback/pu/3?token=3")强制走tcp
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
@ -316,6 +335,11 @@ namespace Video.DomainService
// 先用缓存里的 token,不足5分钟过期再刷新(按你之前的口径来)
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("rtsp录像回放:token无效");
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime";
@ -337,12 +361,12 @@ namespace Video.DomainService
}
var result = JsonSerializer.Deserialize<DaHApiResult<UrlDataDto>>(body);
if (result == null || !result.Success || result.Code != "0")
if (result == null || !result.Success)
{
_logger.LogWarning("录像请求业务失败: {Body}", body);
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1008", Msg = "录像请求失败" };
}
result.Data!.Url = result.Data.Url + "?token=" + token;
result.Data!.Url = result.Data.Url.Replace(_configuration["DahuaAuth:TimeRootHost"], _configuration["DahuaAuth:TimeReplaceHost"]) + "?token=" + result.Data.Token;
return result;
}
catch (Exception ex)
@ -369,6 +393,11 @@ namespace Video.DomainService
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("rtsp实时预览接口方式:token无效");
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1009", Msg = "token无效" };
}
var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/MTS/Video/StartVideo";
@ -395,7 +424,7 @@ namespace Video.DomainService
_logger.LogWarning("实时流请求业务失败: {Body}", body);
return new DaHApiResult<UrlDataDto> { Success = false, Code = "1010", Msg = "实时流请求失败" };
}
result.Data!.Url = result.Data.Url + "?token=" + result.Data!.Token;
result.Data!.Url = result.Data.Url.Replace(_configuration["DahuaAuth:RealRootHost"], _configuration["DahuaAuth:RealReplaceHost"]) + "?token=" + result.Data!.Token;
return result;
}
catch (Exception ex)
@ -415,6 +444,12 @@ namespace Video.DomainService
{
var clientId = _configuration["DahuaAuth:ClientId"];
var token = await _tokenProviderService.GetTokenAsync(clientId!);
if (_tokenProviderService.IsTokenValid(token))
{
_logger.LogWarning("下载:token无效");
return "下载地址无效";
}
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}";
}
}

@ -5,6 +5,9 @@ using WeiCloud.Core.BaseModels;
namespace Video.DomainService
{
/// <summary>
/// todo:这块后续要做一个动态适配,只要修改配置文件就可以自由选择对接的厂商
/// </summary>
public class RootVideoPlayBackService : IRootVideoPlaybackService
{
private readonly ILogger<RootVideoPlayBackService> _logger;

Loading…
Cancel
Save