233 lines
7.9 KiB
C#
233 lines
7.9 KiB
C#
using System.ComponentModel;
|
||
using System.ComponentModel.DataAnnotations;
|
||
using System.Text.Json.Serialization;
|
||
|
||
namespace SHH.CameraDashboard
|
||
{
|
||
public partial class CameraRepository
|
||
{
|
||
// 文件: Services\WebApis\CameraReps\CameraRepository.cs
|
||
|
||
public async Task<bool> UpdateSubscriptionAsync(long cameraId, SubscriptionDto dto)
|
||
{
|
||
var serviceNode = AppGlobal.UseServiceNode;
|
||
if (serviceNode == null) return false;
|
||
|
||
// URL: POST /api/Cameras/{id}/subscriptions
|
||
string requestUrl = $"http://{serviceNode.ServiceNodeIp}:{serviceNode.ServiceNodePort}{WebApiRoutes.Cameras.Root}/{cameraId}/subscriptions";
|
||
|
||
try
|
||
{
|
||
string jsonBody = JsonHelper.Serialize(dto);
|
||
// 发送 POST 请求
|
||
await WebApiService.Instance.PostAsync(requestUrl, jsonBody, "更新订阅配置");
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"更新订阅失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// [新增] 获取订阅列表
|
||
/// </summary>
|
||
public async Task<List<SubscriptionDto>> GetSubscriptionsAsync(long cameraId)
|
||
{
|
||
var serviceNode = AppGlobal.UseServiceNode;
|
||
if (serviceNode == null) return new List<SubscriptionDto>();
|
||
|
||
// URL: GET /api/Cameras/{id}/subscriptions
|
||
string requestUrl = $"http://{serviceNode.ServiceNodeIp}:{serviceNode.ServiceNodePort}{WebApiRoutes.Cameras.Root}/{cameraId}/subscriptions";
|
||
|
||
try
|
||
{
|
||
string json = await WebApiService.Instance.GetAsync(requestUrl, "获取订阅列表");
|
||
|
||
// 如果返回空或null,返回空列表
|
||
if (string.IsNullOrEmpty(json)) return new List<SubscriptionDto>();
|
||
|
||
var list = JsonHelper.Deserialize<List<SubscriptionDto>>(json);
|
||
return list ?? new List<SubscriptionDto>();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"获取订阅列表失败: {ex.Message}");
|
||
return new List<SubscriptionDto>();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// [修改] 删除/注销订阅
|
||
/// 改为标准的 DELETE 请求
|
||
/// </summary>
|
||
public async Task<bool> DeleteSubscriptionAsync(long cameraId, string appId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(appId)) return false;
|
||
|
||
var serviceNode = AppGlobal.UseServiceNode;
|
||
if (serviceNode == null) return false;
|
||
|
||
// 拼接 URL: DELETE /api/Cameras/1001/subscriptions/Client_01
|
||
// 注意:AppId 如果包含特殊字符,建议 UrlEncode,但一般 ID 都是字母数字
|
||
string requestUrl = $"http://{serviceNode.ServiceNodeIp}:{serviceNode.ServiceNodePort}{WebApiRoutes.Cameras.Root}/{cameraId}/subscriptions/{appId}";
|
||
|
||
try
|
||
{
|
||
// 调用刚刚在 WebApiService 里加的 DeleteAsync
|
||
await WebApiService.Instance.DeleteAsync(requestUrl, "注销订阅");
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"注销订阅失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 视频流订阅配置请求对象
|
||
/// 用于定义第三方应用或内部模块对指定相机流的消费需求
|
||
/// </summary>
|
||
public class SubscriptionDto
|
||
{
|
||
/// <summary>
|
||
/// 进程唯一标识 (如 "AI_Process_01"、"Main_Display_02")
|
||
/// </summary>
|
||
public string AppId { get; set; } = string.Empty;
|
||
|
||
/// <summary>
|
||
/// 订阅业务类型。
|
||
/// 决定了后端流控引擎后续的资源分配(如是否开启录像机或渲染器)。
|
||
/// </summary>
|
||
public int Type { get; set; }
|
||
|
||
/// <summary>
|
||
/// 显示帧率需求 (单位: fps)
|
||
/// <para>不需要显示则设为 0,控制器会自动注销该类型需求</para>
|
||
/// </summary>
|
||
public int DisplayFps
|
||
{
|
||
get => TargetFps;
|
||
set => TargetFps = value;
|
||
}
|
||
|
||
public int TargetFps { get; set; }
|
||
|
||
/// <summary>
|
||
/// [新增] 实际显示/分发帧率
|
||
/// JSON: "realFps"
|
||
/// </summary>
|
||
[JsonPropertyName("realFps")]
|
||
public double RealFps { get; set; }
|
||
|
||
/// <summary>
|
||
/// 备注信息。
|
||
/// 用于记录订阅的用途、申请人或关联业务系统。
|
||
/// </summary>
|
||
public string Memo { get; set; }
|
||
= string.Empty;
|
||
|
||
/// <summary>
|
||
/// 窗口句柄(HWND)。
|
||
/// 仅在 Type 为 HandleDisplay 时必填。格式通常为十六进制或十进制字符串。
|
||
/// </summary>
|
||
public string Handle { get; set; }
|
||
= string.Empty;
|
||
|
||
/// <summary>
|
||
/// 录像持续时长(分钟,范围 1-60)。
|
||
/// 仅在 Type 为 LocalRecord 时有效。
|
||
/// </summary>
|
||
public int RecordDuration { get; set; }
|
||
|
||
/// <summary>
|
||
/// 录像文件存放绝对路径。
|
||
/// 仅在 Type 为 LocalRecord 时有效,例如:C:\Recordings\Room01。
|
||
/// </summary>
|
||
public string SavePath { get; set; }
|
||
= string.Empty;
|
||
|
||
/// <summary>
|
||
/// 通讯方式协议。
|
||
/// 仅在 Type 为 NetworkTrans 或 WebPush 时有效,默认为 Network。
|
||
/// </summary>
|
||
public int Protocol { get; set; }
|
||
|
||
/// <summary>
|
||
/// 目标接收端 IP 地址。
|
||
/// 仅在 Type 为 NetworkTrans 或 WebPush 且 Protocol 为 Network 时必填。
|
||
/// </summary>
|
||
public string TargetIp { get; set; }
|
||
= string.Empty;
|
||
|
||
/// <summary>
|
||
/// 目标接收端端口号。
|
||
/// 仅在 Type 为 NetworkTrans 或 WebPush 时必填。
|
||
/// </summary>
|
||
public int TargetPort { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 订阅业务类型枚举
|
||
/// 描述视频流的最终去向和业务用途,用于帧分发策略的路由决策
|
||
/// </summary>
|
||
public enum SubscriptionType
|
||
{
|
||
/// <summary>
|
||
/// 本地窗口渲染
|
||
/// <para>直接在服务器端显示器绘制(如 OpenCV Window、WinForm 控件)</para>
|
||
/// </summary>
|
||
[Description("本地窗口显示")]
|
||
LocalWindow = 0,
|
||
|
||
/// <summary>
|
||
/// 本地录像存储
|
||
/// <para>写入磁盘文件(如 MP4/AVI 格式,支持定时切割、循环覆盖)</para>
|
||
/// </summary>
|
||
[Description("本地录像存储")]
|
||
LocalRecord = 1,
|
||
|
||
/// <summary>
|
||
/// 句柄绑定显示
|
||
/// <para>渲染到指定 HWND 窗口句柄(如 SDK 硬件解码渲染到客户端控件)</para>
|
||
/// </summary>
|
||
[Description("句柄绑定显示")]
|
||
HandleDisplay = 2,
|
||
|
||
/// <summary>
|
||
/// 自定义网络传输
|
||
/// <para>通过私有协议转发给第三方系统(如工控机、告警服务器)</para>
|
||
/// </summary>
|
||
[Description("自定义网络传输")]
|
||
NetworkTrans = 3,
|
||
|
||
/// <summary>
|
||
/// 网页端推流
|
||
/// <para>转码为 Web 标准协议(如 WebRTC、HLS、RTMP)供浏览器播放</para>
|
||
/// </summary>
|
||
[Description("网页端推流")]
|
||
WebPush = 4
|
||
}
|
||
|
||
/// <summary>
|
||
/// 网络传输协议类型
|
||
/// </summary>
|
||
public enum TransportProtocol
|
||
{
|
||
/// <summary> 可靠传输 (默认) </summary>
|
||
Tcp = 0,
|
||
|
||
/// <summary> 快速传输 (可能丢包/花屏) </summary>
|
||
Udp = 1,
|
||
|
||
/// <summary> 组播 (节省带宽) </summary>
|
||
Multicast = 2,
|
||
|
||
/// <summary> 内存交互 </summary>
|
||
Memory = 99,
|
||
}
|
||
}
|