using System.Net;
using System.Net.Sockets;
using MoShiro.Protocol;
namespace MoShiro.Backend.Application;
///
/// 自动识别 Agent 的对外地址:Agent 上报本机的公网地址,注册请求的来源地址作为补充(来源是私网或隧道出口时不用)。
/// 管理员手填的(*_manual)永远优先;已经选中的自动地址还在候选里就不换,不会因为网卡顺序变化来回改。
///
public static class AgentAddressPolicy
{
/// 返回要写入的 (public_host, ipv6_host);没有候选的那一项是 null(保持不变)。
public static (string? PublicHost, string? Ipv6Host) Choose(AgentRecord current, IReadOnlyList reported, string? observed)
{
var v4 = new List();
var v6 = new List();
foreach (string text in reported.Append(observed ?? ""))
{
if (!IPAddress.TryParse(text, out IPAddress? address))
{
continue;
}
if (address.AddressFamily == AddressFamily.InterNetwork && PublicAddress.IsPublicIpv4(address) && !v4.Contains(address.ToString()))
{
v4.Add(address.ToString());
}
else if (address.AddressFamily == AddressFamily.InterNetworkV6 && PublicAddress.IsGlobalIpv6(address) && !v6.Contains(address.ToString()))
{
v6.Add(address.ToString());
}
}
return (current.PublicHostManual ? null : Pick(v4, current.PublicHost), current.Ipv6HostManual ? null : Pick(v6, current.Ipv6Host));
}
private static string? Pick(List candidates, string current) =>
candidates.Count == 0 ? null : candidates.Contains(current) ? current : candidates[0];
}