web: one line per node pair and RTT/loss on the link board

A pair of nodes now has a single line, dialed by the non-listening side or by the smaller id when both listen, so RTT is measured once. The board draws it undirected and colours it by RTT and loss; a manual setting applies to the pair.
This commit is contained in:
justme committed 2026-10-21 16:20:38 +08:00
1 parent e0f6667cd7
commit 48ffa56285
6 files changed
+172 -72

No files matched your search

@@ -9,7 +9,7 @@ using MoShiro.Protocol;
namespace MoShiro.Backend.Api;
/// <summary>
/// 线路开关:哪些(拨号方,监听方)要连。自动连接的总开关是设置 <c>fleet.auto_link</c>(不监听的节点自动拨所有监听节点);
/// 线路开关:哪些(拨号方,监听方)要连,一对节点一条线路。自动连接的总开关是设置 <c>fleet.auto_link</c>(不监听的节点拨监听节点;两个都监听时 id 较小的一方拨);
/// 这里看每一对的结果,并且手动强制开、关或取消手动设置。把一个节点拖到另一个监听节点上建立线路,就是 <c>PUT</c> 一个 <c>enabled: true</c>。
/// </summary>
public static class LinkEndpoints
@@ -34,11 +34,21 @@ public static class LinkEndpoints
LinkSnapshot snapshot = await links.SnapshotAsync(ct);
AgentView[] nodes = [.. (await agents.ListAsync(ct)).Where(n => n.Agent.Status == NodeStatus.Active).OrderBy(n => n.Agent.Name, StringComparer.Ordinal)];
var items = new List<LinkDto>();
foreach (AgentView dialer in nodes)
for (int i = 0; i < nodes.Length; i++)
{
foreach (AgentView listener in nodes.Where(n => n.Agent.Listens && n.Agent.Id != dialer.Agent.Id))
for (int j = i + 1; j < nodes.Length; j++)
{
items.Add(ToDto(snapshot, dialer, listener, runtime, time));
// 一对节点一条线路:连着的那个方向,没连就是默认方向;两个都不监听的一对没有线路
(AgentView Dialer, AgentView Listener)? pair =
snapshot.IsLinked(nodes[i].Agent, nodes[j].Agent) ? (nodes[i], nodes[j])
: snapshot.IsLinked(nodes[j].Agent, nodes[i].Agent) ? (nodes[j], nodes[i])
: LinkSnapshot.IsDefaultDialer(nodes[i].Agent, nodes[j].Agent) ? (nodes[i], nodes[j])
: LinkSnapshot.IsDefaultDialer(nodes[j].Agent, nodes[i].Agent) ? (nodes[j], nodes[i])
: null;
if (pair is { } p)
{
items.Add(ToDto(snapshot, p.Dialer, p.Listener, runtime, time));
}
}
}
@@ -148,7 +158,7 @@ public static class LinkEndpoints
bool inBackoff = health?.Control.State == ControlState.Backoff;
return new LinkDto(dialer.Agent.Id.Value, dialer.Agent.Name, listener.Agent.Id.Value, listener.Agent.Name, linked,
snapshot.OverrideOf(dialer.Agent.Id.Value, listener.Agent.Id.Value), state == "connected", dialer.RuntimeStatus, listener.RuntimeStatus,
snapshot.PairOverride(dialer.Agent.Id.Value, listener.Agent.Id.Value), state == "connected", dialer.RuntimeStatus, listener.RuntimeStatus,
state, reason, (inBackoff ? health!.Control.LastError : health?.Task.Quic.LastError)?.ToString(),
health is null ? 0 : inBackoff ? health.Control.RetryAttempt : health.Task.Quic.RetryAttempt,
health is null ? null : inBackoff ? health.Control.RetryInMs : health.Task.Quic.RetryInMs);