agent: unify listening and dialing with directed mutual measurements
Replace Probe with Agent across node runtime, Fleet contracts, backend state, API and storage. Report incoming sessions and outgoing link health through each Agent uplink, and retain directed link controls and retry. Update protocol fixtures and end-to-end coverage for the unified model; accept requested cancellation during the Fleet timeout test cleanup.
This commit is contained in:
1 parent
d5ebf29e57
commit
ad5efc62ff
206 files changed
+4202
-4964
No files matched your search
@@ -61,34 +61,34 @@ public class BackendFixture : IAsyncLifetime
|
||||
|
||||
public IServiceProvider Services => App.Services;
|
||||
|
||||
/// <summary>夹具创建的默认 Probe:合成块(<see cref="ChunkFactory"/>)和单线路的查询都用它。</summary>
|
||||
public string DefaultProbeId { get; private set; } = "";
|
||||
/// <summary>夹具创建的默认拨号侧 Agent:合成块(<see cref="ChunkFactory"/>)和单线路的查询都用它。</summary>
|
||||
public string DefaultDialerId { get; private set; } = "";
|
||||
|
||||
/// <summary>默认 Probe 与这个 Agent 组成的线路 id(<c>agent~probe</c>)。</summary>
|
||||
public string Line(Fleet.Core.NodeId agent) => $"{agent.Value}~{DefaultProbeId}";
|
||||
/// <summary>默认拨号侧 Agent 与这个 Agent 组成的线路 id(<c>agent~dialer</c>)。</summary>
|
||||
public string Line(Fleet.Core.NodeId agent) => $"{agent.Value}~{DefaultDialerId}";
|
||||
|
||||
public string Line(string agentId) => $"{agentId}~{DefaultProbeId}";
|
||||
public string Line(string agentId) => $"{agentId}~{DefaultDialerId}";
|
||||
|
||||
/// <summary>
|
||||
/// 注册一个新的 Probe:和真实部署一样,先在管理端创建 <c>probe</c> 角色的加入令牌,再由节点自己生成密钥、用 <c>fleet-enroll</c> 同样的流程注册。
|
||||
/// 注册一个新的 Agent:和真实部署一样,先在管理端创建 <c>agent</c> 加入令牌,再由节点自己生成密钥、用 <c>fleet-enroll</c> 同样的流程注册。
|
||||
/// 返回的身份目录里有两把密钥:连面板的 <c>Identity</c> 和对等面的 <c>PeerIdentity</c>。调用方负责释放。
|
||||
/// </summary>
|
||||
public async Task<EnrolledProbe> CreateProbeAsync(string? name = null)
|
||||
public async Task<EnrolledDialer> CreateDialerAsync(string? name = null)
|
||||
{
|
||||
string token = await CreateJoinTokenAsync(role: "probe");
|
||||
string directory = Path.Combine(Path.GetTempPath(), "moshiro-probe-id-" + Guid.NewGuid().ToString("N"));
|
||||
string token = await CreateJoinTokenAsync(role: "agent");
|
||||
string directory = Path.Combine(Path.GetTempPath(), "moshiro-dialer-id-" + Guid.NewGuid().ToString("N"));
|
||||
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) };
|
||||
Fleet.Core.Result<Fleet.Enrollment.Client.EnrollmentResult> enrolled = await Fleet.Enrollment.Client.EnrollmentClient.EnrollAsync(
|
||||
http, BaseAddress, token, name ?? UniqueName("probe"), directory, "0.0.0-test", null, TimeProvider.System, default);
|
||||
http, BaseAddress, token, name ?? UniqueName("dialer"), directory, "0.0.0-test", null, TimeProvider.System, default);
|
||||
Assert.True(enrolled.IsSuccess, enrolled.IsSuccess ? "" : enrolled.Error.ToString());
|
||||
return new EnrolledProbe(enrolled.Value.NodeId, directory, Fleet.Hosting.LoadedNodeIdentity.Load(directory));
|
||||
return new EnrolledDialer(enrolled.Value.NodeId, directory, Fleet.Hosting.LoadedNodeIdentity.Load(directory));
|
||||
}
|
||||
|
||||
/// <summary>注册一个 Probe,只要它的 id(密钥用完即释放)。</summary>
|
||||
public async Task<string> CreateProbeIdAsync(string? name = null)
|
||||
/// <summary>注册一个拨号侧 Agent,只要它的 id(密钥用完即释放)。</summary>
|
||||
public async Task<string> CreateDialerIdAsync(string? name = null)
|
||||
{
|
||||
using EnrolledProbe probe = await CreateProbeAsync(name);
|
||||
return probe.ProbeId;
|
||||
using EnrolledDialer dialer = await CreateDialerAsync(name);
|
||||
return dialer.DialerId;
|
||||
}
|
||||
|
||||
public async ValueTask InitializeAsync()
|
||||
@@ -97,9 +97,9 @@ public class BackendFixture : IAsyncLifetime
|
||||
await StartAsync();
|
||||
_adminToken = await CreateAdminTokenAsync();
|
||||
CreateClients();
|
||||
using (EnrolledProbe probe = await CreateProbeAsync("default"))
|
||||
using (EnrolledDialer dialer = await CreateDialerAsync("default"))
|
||||
{
|
||||
DefaultProbeId = probe.ProbeId;
|
||||
DefaultDialerId = dialer.DialerId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ public class BackendFixture : IAsyncLifetime
|
||||
public async Task<AgentSimulator> ReconnectAsync(AgentSimulator previous)
|
||||
{
|
||||
AgentSimulator agent = AgentSimulator.Restore(previous.ExportedKey, previous.NodeId);
|
||||
agent.ProbeForChunks = new MoShiro.Protocol.ProbeId(DefaultProbeId);
|
||||
agent.DialerForChunks = new Fleet.Core.NodeId(DefaultDialerId);
|
||||
_agents.Add(agent);
|
||||
await agent.ConnectAsync(BaseAddress);
|
||||
return agent;
|
||||
@@ -207,7 +207,7 @@ public class BackendFixture : IAsyncLifetime
|
||||
{
|
||||
string token = await CreateJoinTokenAsync(autoApprove);
|
||||
AgentSimulator agent = await AgentSimulator.EnrollAsync(Anonymous, token, name ?? UniqueName("agent"), kinds);
|
||||
agent.ProbeForChunks = new MoShiro.Protocol.ProbeId(DefaultProbeId);
|
||||
agent.DialerForChunks = new Fleet.Core.NodeId(DefaultDialerId);
|
||||
_agents.Add(agent);
|
||||
await agent.ConnectAsync(BaseAddress, hello, kinds);
|
||||
return agent;
|
||||
@@ -340,8 +340,8 @@ public sealed class StrictLoginFixture : BackendFixture
|
||||
protected override int LoginAttemptsPerMinute => 10;
|
||||
}
|
||||
|
||||
/// <summary>注册好的 Probe:身份目录(节点自己生成的两把密钥)和加载出来的身份。</summary>
|
||||
public sealed record EnrolledProbe(string ProbeId, string Directory, Fleet.Hosting.LoadedNodeIdentity Identity) : IDisposable
|
||||
/// <summary>注册好的拨号侧 Agent:身份目录(节点自己生成的两把密钥)和加载出来的身份。</summary>
|
||||
public sealed record EnrolledDialer(string DialerId, string Directory, Fleet.Hosting.LoadedNodeIdentity Identity) : IDisposable
|
||||
{
|
||||
public void Dispose() => Identity.Dispose();
|
||||
}
|
||||
Reference in new issue
Block a user