Add fact-first Link reconciliation, duplicate and orphan cleanup, generation-aware scheduling, retention, Desktop drift visibility, and strict helper contracts. Preserve exact B-3R batching and lock-safe finalization with Linux/native trimmed evidence. Co-authored-by: Ochenstarik <ochenstarik@inbox.ru>
80 lines
3.3 KiB
C#
80 lines
3.3 KiB
C#
namespace ServerMonitorManager_Desktop;
|
||
|
||
public sealed class MeshNodeViewModel
|
||
{
|
||
public MeshNodeViewModel(string name, string address, string state, int handshakeAgeSeconds)
|
||
{
|
||
Name = name;
|
||
Address = address;
|
||
State = state;
|
||
HandshakeAgeSeconds = handshakeAgeSeconds;
|
||
}
|
||
|
||
public string Name { get; set; }
|
||
public string Address { get; set; }
|
||
public string State { get; set; }
|
||
public int HandshakeAgeSeconds { get; set; }
|
||
public string Label => $"{Name} · {Address} · {(State == "online" ? "онлайн" : "не в сети")}";
|
||
}
|
||
|
||
public sealed class MeshLinkViewModel
|
||
{
|
||
public const string FirewallUnavailableErrorCode = "mesh.firewall-unavailable";
|
||
public const string NodeNotActivatedErrorCode = "mesh.node-not-activated";
|
||
|
||
public MeshLinkViewModel(
|
||
string source,
|
||
string target,
|
||
string cidr,
|
||
string protocol,
|
||
int port,
|
||
long expiresUnix,
|
||
string state,
|
||
long version,
|
||
string? id = null,
|
||
string? desiredState = null,
|
||
string? actualState = null,
|
||
string? lastError = null)
|
||
{
|
||
Source = source;
|
||
Target = target;
|
||
Cidr = cidr;
|
||
Protocol = protocol;
|
||
Port = port;
|
||
ExpiresUnix = expiresUnix;
|
||
State = state;
|
||
Version = version;
|
||
Id = id;
|
||
DesiredState = desiredState ?? state;
|
||
ActualState = actualState ?? state;
|
||
LastError = lastError;
|
||
}
|
||
|
||
public string Source { get; set; }
|
||
public string Target { get; set; }
|
||
public string Cidr { get; set; }
|
||
public string Protocol { get; set; }
|
||
public int Port { get; set; }
|
||
public long ExpiresUnix { get; set; }
|
||
public string State { get; set; }
|
||
public long Version { get; set; }
|
||
public string? Id { get; set; }
|
||
public string DesiredState { get; set; }
|
||
public string ActualState { get; set; }
|
||
public string? LastError { get; set; }
|
||
public bool HasDrift => !string.Equals(DesiredState, ActualState, StringComparison.Ordinal);
|
||
public string DesiredStatusText => $"Желаемое состояние: {DesiredState}";
|
||
public string ActualStatusText => LastError == NodeNotActivatedErrorCode
|
||
? "Фактическое состояние: ожидает активации Node в Mesh"
|
||
: $"Фактическое состояние: {ActualState}";
|
||
public string DriftText => LastError == NodeNotActivatedErrorCode
|
||
? "Ожидание: активируйте Node в Mesh — это не ошибка политики"
|
||
: HasDrift ? "Расхождение: требуется сверка политики" : "Расхождение: нет";
|
||
public string ErrorText => LastError is FirewallUnavailableErrorCode or NodeNotActivatedErrorCode ? string.Empty
|
||
: string.IsNullOrWhiteSpace(LastError) ? "Ошибка: нет" : $"Ошибка: {LastError}";
|
||
public string VersionText => $"Версия политики: {Version}";
|
||
public string ExpirationText => ExpiresUnix == 0
|
||
? "вручную"
|
||
: $"до {DateTimeOffset.FromUnixTimeSeconds(ExpiresUnix).ToLocalTime():dd.MM HH:mm}";
|
||
public string Label => $"{Source} → {Target} · {Protocol.ToUpperInvariant()}/{Port} · {Cidr} · {ExpirationText}";
|
||
}
|