Files
Ayay/SHH.CameraSdk/Configs/ServiceConfig.cs
2026-01-05 14:54:06 +08:00

227 lines
7.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace SHH.CameraSdk;
/// <summary>
/// 全局服务配置模型 (V3 最终版)
/// <para>负责解析命令行参数,构建网络拓扑和身份标识</para>
/// </summary>
public class ServiceConfig
{
// ==========================================
// 1. 身份与进程属性
// ==========================================
/// <summary>
/// 父进程 PID (用于哨兵守护,--pid)
/// </summary>
public int ParentPid { get; private set; }
/// <summary>
/// 应用完整标识 (例如 "CameraApp_01", --appid)
/// </summary>
public string AppId { get; private set; } = "Unknown_01";
/// <summary>
/// 【核心】从 AppId 自动提取的数字编号
/// <para>规则:取最后一个下划线后的数字</para>
/// <para>示例:"CameraApp_05" -> 5</para>
/// </summary>
public int NumericId { get; private set; } = 1;
// ==========================================
// 2. 网络连接属性 (分流)
// ==========================================
/// <summary>
/// 视频流目标地址列表 (对应 & 符号左侧)
/// <para>ZeroMQBridgeWorker 使用此列表</para>
/// </summary>
public List<string> VideoEndpoints { get; private set; } = new List<string>();
/// <summary>
/// 指令控制目标地址列表 (对应 & 符号右侧)
/// <para>CommandClientWorker 使用此列表</para>
/// </summary>
public List<string> CommandEndpoints { get; private set; } = new List<string>();
/// <summary>
/// WebAPI 基础端口 (--ports 的第一个值)
/// </summary>
public int BasePort { get; private set; } = 5000;
/// <summary>
/// 端口扫描范围 (--ports 的第二个值)
/// </summary>
public int MaxPortRange { get; private set; } = 100;
/// <summary>
/// 网络模式 (--mode)
/// </summary>
public NetworkMode Mode { get; private set; } = NetworkMode.Passive;
// ==========================================
// 3. 辅助属性
// ==========================================
/// <summary>
/// 是否需要执行 Connect 操作
/// </summary>
public bool ShouldConnect => Mode == NetworkMode.Active || Mode == NetworkMode.Hybrid;
// ==========================================
// 4. 解析入口 (Factory Method)
// ==========================================
public static ServiceConfig BuildFromArgs(string[] args)
{
var config = new ServiceConfig();
for (int i = 0; i < args.Length; i++)
{
// 1. 预处理 Key
var key = args[i].ToLower().Trim();
// 2. 预取 Value (如果存在且不是下一个 flag)
var value = (i + 1 < args.Length) ? args[i + 1] : string.Empty;
// 简单判断:如果 value 以 -- 开头,说明当前 key 是开关,或者参数值缺失
if (value.StartsWith("--")) value = string.Empty;
bool consumed = false; // 标记是否消耗了下一个参数
// 3. 匹配参数
switch (key)
{
case "--pid":
if (int.TryParse(value, out int pid)) config.ParentPid = pid;
consumed = true;
break;
case "--appid":
if (!string.IsNullOrWhiteSpace(value))
{
config.AppId = value;
// ★★★ 立即解析数字编号 ★★★
config.NumericId = ParseIdFromAppId(value);
}
consumed = true;
break;
case "--uris":
if (!string.IsNullOrWhiteSpace(value))
{
// ★★★ 解析复杂 URI 字符串 ★★★
ParseUris(config, value);
}
consumed = true;
break;
case "--mode":
if (int.TryParse(value, out int m) && Enum.IsDefined(typeof(NetworkMode), m))
{
config.Mode = (NetworkMode)m;
}
consumed = true;
break;
case "--ports":
// 格式: "BasePort,Range" -> "6003,100"
if (!string.IsNullOrWhiteSpace(value) && value.Contains(","))
{
var parts = value.Split(',');
if (parts.Length >= 1)
{
if (int.TryParse(parts[0], out int baseP)) config.BasePort = baseP;
}
if (parts.Length >= 2)
{
if (int.TryParse(parts[1], out int range)) config.MaxPortRange = range;
}
}
consumed = true;
break;
}
// 4. 如果消耗了 Value跳过下一个索引
if (consumed) i++;
}
return config;
}
// ==========================================
// 5. 核心解析算法实现
// ==========================================
/// <summary>
/// 算法:提取下划线后的数字
/// </summary>
private static int ParseIdFromAppId(string appId)
{
if (string.IsNullOrWhiteSpace(appId)) return 1;
// 查找最后一个下划线
int lastIdx = appId.LastIndexOf('_');
// 确保下划线存在,且后面还有字符
if (lastIdx >= 0 && lastIdx < appId.Length - 1)
{
string numPart = appId.Substring(lastIdx + 1);
if (int.TryParse(numPart, out int id))
{
return id;
}
}
// 解析失败默认返回 1
return 1;
}
/// <summary>
/// 算法:解析 URI 列表并分流
/// <para>格式: IP,VideoPort&CommandPort</para>
/// <para>空缺处理: "&6001" (仅指令), "6002&" (仅视频)</para>
/// </summary>
private static void ParseUris(ServiceConfig config, string rawValue)
{
// 1. 按分号拆分不同主机配置
// "127.0.0.1,6002&6001; 192.168.1.5,&6001"
var groups = rawValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var group in groups)
{
// 2. 按逗号拆分 IP 和 端口段
var hostParts = group.Split(',');
if (hostParts.Length < 2) continue; // 格式非法
string ip = hostParts[0].Trim();
string portSection = hostParts[1].Trim(); // "6002&6001"
// 3. 按 & 拆分端口 (注意:不要 RemoveEmptyEntries位置很重要)
var ports = portSection.Split('&');
// --- 索引 0: 视频端口 ---
if (ports.Length > 0)
{
string p = ports[0].Trim();
if (!string.IsNullOrWhiteSpace(p) && int.TryParse(p, out int port))
{
string uri = $"tcp://{ip}:{port}";
if (!config.VideoEndpoints.Contains(uri))
config.VideoEndpoints.Add(uri);
}
}
// --- 索引 1: 指令端口 ---
if (ports.Length > 1)
{
string p = ports[1].Trim();
if (!string.IsNullOrWhiteSpace(p) && int.TryParse(p, out int port))
{
string uri = $"tcp://{ip}:{port}";
if (!config.CommandEndpoints.Contains(uri))
config.CommandEndpoints.Add(uri);
}
}
}
}
}