chore: initial project import
This commit is contained in:
commit
26620707a0
347 files changed
+56172
No files matched your search
@@ -0,0 +1,102 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Fleet.Core;
|
||||
using Monitor.Protocol;
|
||||
|
||||
namespace Monitor.Backend.Application;
|
||||
|
||||
/// <summary>Agent 眼中的一个已连接 Probe(Agent 在事件和心跳里上报)。</summary>
|
||||
public sealed record ConnectedProbeInfo(string Id, string? Version, string? Remote, long SinceMs);
|
||||
|
||||
/// <summary>Agent 的运行时状态(只在内存中):连着哪些 Probe、最近的进程内计数、端点变化次数。</summary>
|
||||
public sealed class AgentRuntimeState
|
||||
{
|
||||
private readonly object _gate = new();
|
||||
private int _endpointChanges;
|
||||
private IReadOnlyList<ConnectedProbeInfo> _probes = [];
|
||||
|
||||
/// <summary>当前连着这个 Agent 的 Probe(每个 Probe 一项)。</summary>
|
||||
public IReadOnlyList<ConnectedProbeInfo> Probes => Volatile.Read(ref _probes);
|
||||
|
||||
public bool ProbeConnected => Probes.Count > 0;
|
||||
|
||||
public bool IsConnected(string probeId) => Probes.Any(p => p.Id == probeId);
|
||||
|
||||
/// <summary>事件 <c>probe_connected</c>:事件里带着 Probe 的版本和地址;心跳里的完整快照随后会再校正一次。</summary>
|
||||
public void AddProbe(ConnectedProbeInfo info)
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
Volatile.Write(ref _probes, [.. _probes.Where(p => p.Id != info.Id), info]);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveProbe(string id)
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
Volatile.Write(ref _probes, [.. _probes.Where(p => p.Id != id)]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>心跳里的完整快照:覆盖事件推算出的结果。</summary>
|
||||
public void ReplaceProbes(IEnumerable<ConnectedProbeInfo> probes)
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
Volatile.Write(ref _probes, [.. probes.OrderBy(p => p.SinceMs).ThenBy(p => p.Id, StringComparer.Ordinal)]);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearProbes() => ReplaceProbes([]);
|
||||
|
||||
/// <summary>最新的主机资源占用快照,以及收到它的时间。</summary>
|
||||
public HostSnapshot? Host { get; set; }
|
||||
|
||||
public long HostReceivedAtMs { get; set; }
|
||||
|
||||
public AgentHeartbeatExtra? LastHeartbeat { get; set; }
|
||||
|
||||
public long LastHeartbeatAtMs { get; set; }
|
||||
|
||||
public int EndpointChanges => Volatile.Read(ref _endpointChanges);
|
||||
|
||||
public void CountEndpointChange() => Interlocked.Increment(ref _endpointChanges);
|
||||
}
|
||||
|
||||
public sealed class AgentRuntime
|
||||
{
|
||||
private readonly ConcurrentDictionary<NodeId, AgentRuntimeState> _states = new();
|
||||
|
||||
public AgentRuntimeState Get(NodeId agent) => _states.GetOrAdd(agent, _ => new AgentRuntimeState());
|
||||
|
||||
public bool TryGet(NodeId agent, out AgentRuntimeState state) => _states.TryGetValue(agent, out state!);
|
||||
|
||||
public void Remove(NodeId agent) => _states.TryRemove(agent, out _);
|
||||
|
||||
/// <summary>某个 Probe 现在连着哪些 Agent。</summary>
|
||||
public IReadOnlyList<(NodeId Agent, ConnectedProbeInfo Probe)> ConnectionsOf(string probeId)
|
||||
{
|
||||
var result = new List<(NodeId, ConnectedProbeInfo)>();
|
||||
foreach ((NodeId agent, AgentRuntimeState state) in _states)
|
||||
{
|
||||
foreach (ConnectedProbeInfo probe in state.Probes)
|
||||
{
|
||||
if (probe.Id == probeId)
|
||||
{
|
||||
result.Add((agent, probe));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Agent 断开时,它对 Probe 会话的认知也随之失效。</summary>
|
||||
public void MarkOffline(NodeId agent)
|
||||
{
|
||||
if (_states.TryGetValue(agent, out AgentRuntimeState? state))
|
||||
{
|
||||
state.ClearProbes();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user