Files
justme ad5efc62ff 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.
2026-10-21 11:55:36 +08:00

63 lines
2.1 KiB
C#

using Fleet.Core;
using Fleet.Hosting;
using MoShiro.Agent;
namespace MoShiro.Backend.Tests;
/// <summary>进程内的真实拨号节点:用加入令牌注册出来的身份启动 <see cref="AgentApp"/>,监听关闭(<c>listen.enabled = false</c>),只向 Backend 下发的目标拨出。</summary>
public sealed class DialerHarness : IAsyncDisposable
{
private readonly CancellationTokenSource _stop = new();
private readonly string _directory;
private readonly Task _run;
private readonly EnrolledDialer _enrolled;
private DialerHarness(string directory, AgentApp app, EnrolledDialer enrolled)
{
_directory = directory;
_enrolled = enrolled;
App = app;
_run = Task.Run(() => app.RunAsync(_stop.Token), CancellationToken.None);
}
public AgentApp App { get; }
public string Directory => _directory;
public string DialerId { get; init; } = "";
public static async Task<DialerHarness> StartAsync(BackendFixture backend, Action<AgentConfig>? configure = null)
{
EnrolledDialer enrolled = await backend.CreateDialerAsync();
var config = new AgentConfig { Fleet = { Server = backend.BaseAddress.ToString(), IdentityDir = enrolled.Directory }, Listen = { Enabled = false } };
configure?.Invoke(config);
var app = new AgentApp(config, enrolled.Identity, enrolled.Directory, TimeProvider.System, NullNodeLog.Instance);
return new DialerHarness(enrolled.Directory, app, enrolled) { DialerId = enrolled.DialerId };
}
public async ValueTask DisposeAsync()
{
await _stop.CancelAsync();
try
{
await _run.WaitAsync(TimeSpan.FromSeconds(15));
}
catch (Exception ex) when (ex is OperationCanceledException or TimeoutException)
{
// 停止中
}
await App.DisposeAsync();
_enrolled.Dispose();
_stop.Dispose();
try
{
System.IO.Directory.Delete(_directory, recursive: true);
}
catch (IOException)
{
// 临时目录清理失败不影响测试结果
}
}
}