fix: address windows agent host review feedback

This commit is contained in:
sladro 2026-03-27 11:00:35 +08:00
parent b825249a7e
commit bc5e980326
8 changed files with 112 additions and 28 deletions

View File

@ -8,7 +8,7 @@ public sealed class AgentOptions
public string BindAddress { get; set; } = "0.0.0.0";
public int HttpsPort { get; set; }
public int Port { get; set; }
public int WebSocketFrameFlushMilliseconds { get; set; }

View File

@ -0,0 +1,36 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace TermRemoteCtl.Agent.Configuration;
public static class AgentOptionsServiceCollectionExtensions
{
public static AgentOptions AddAgentOptions(this IServiceCollection services, IConfiguration configuration)
{
var effectiveOptions = BuildEffectiveOptions(configuration);
services.AddSingleton<IValidateOptions<AgentOptions>, AgentOptionsValidator>();
services
.AddOptions<AgentOptions>()
.Configure(options =>
{
options.DataRoot = effectiveOptions.DataRoot;
options.BindAddress = effectiveOptions.BindAddress;
options.Port = effectiveOptions.Port;
options.WebSocketFrameFlushMilliseconds = effectiveOptions.WebSocketFrameFlushMilliseconds;
options.RingBufferLineLimit = effectiveOptions.RingBufferLineLimit;
})
.ValidateOnStart();
return effectiveOptions;
}
private static AgentOptions BuildEffectiveOptions(IConfiguration configuration)
{
var options = new AgentOptions();
configuration.GetSection(AgentOptions.SectionName).Bind(options);
options.DataRoot = AppPaths.ResolveDataRoot(configuration);
return options;
}
}

View File

@ -13,9 +13,9 @@ public sealed class AgentOptionsValidator : IValidateOptions<AgentOptions>
failures.Add("Agent:DataRoot must be configured.");
}
if (options.HttpsPort is < 1 or > 65535)
if (options.Port is < 1 or > 65535)
{
failures.Add("Agent:HttpsPort must be between 1 and 65535.");
failures.Add("Agent:Port must be between 1 and 65535.");
}
if (options.WebSocketFrameFlushMilliseconds <= 0)

View File

@ -1,23 +1,13 @@
using Microsoft.Extensions.Options;
using TermRemoteCtl.Agent;
using TermRemoteCtl.Agent.Configuration;
var builder = WebApplication.CreateBuilder(args);
var agentSection = builder.Configuration.GetSection(AgentOptions.SectionName);
var bindAddress = agentSection[nameof(AgentOptions.BindAddress)] ?? "0.0.0.0";
var httpsPort = agentSection.GetValue<int?>(nameof(AgentOptions.HttpsPort)) ?? 9443;
builder.WebHost.UseUrls($"http://{bindAddress}:{httpsPort}");
builder.Services.AddSingleton<IValidateOptions<AgentOptions>, AgentOptionsValidator>();
builder.Services
.AddOptions<AgentOptions>()
.Bind(agentSection)
.PostConfigure(options => options.DataRoot = AppPaths.ResolveDataRoot(builder.Configuration))
.ValidateOnStart();
var agentOptions = builder.Services.AddAgentOptions(builder.Configuration);
builder.WebHost.UseUrls($"http://{agentOptions.BindAddress}:{agentOptions.Port}");
var app = builder.Build();
var agentOptions = app.Services.GetRequiredService<IOptions<AgentOptions>>().Value;
agentOptions = app.Services.GetRequiredService<IOptions<AgentOptions>>().Value;
Directory.CreateDirectory(agentOptions.DataRoot);

View File

@ -2,7 +2,7 @@
"Agent": {
"DataRoot": "C:\\ProgramData\\TermRemoteCtl",
"BindAddress": "0.0.0.0",
"HttpsPort": 9443,
"Port": 9443,
"WebSocketFrameFlushMilliseconds": 33,
"RingBufferLineLimit": 4000
}

View File

@ -0,0 +1,68 @@
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using TermRemoteCtl.Agent.Configuration;
namespace TermRemoteCtl.Agent.Tests.Configuration;
public class AgentOptionsPipelineTests
{
[Fact]
public void ResolveOptions_Uses_DataRoot_Fallback_When_Config_Omits_DataRoot()
{
var configuration = BuildConfiguration(new Dictionary<string, string?>
{
["Agent:BindAddress"] = "127.0.0.1",
["Agent:Port"] = "9443",
["Agent:WebSocketFrameFlushMilliseconds"] = "33",
["Agent:RingBufferLineLimit"] = "4000"
});
var services = new ServiceCollection();
services.AddAgentOptions(configuration);
using var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<AgentOptions>>().Value;
var expectedDataRoot = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"TermRemoteCtl");
Assert.Equal(expectedDataRoot, options.DataRoot);
}
[Theory]
[InlineData("0", "33", "Port")]
[InlineData("9443", "0", "WebSocketFrameFlushMilliseconds")]
public void ResolveOptions_Fails_When_Config_Is_Invalid(
string port,
string flushMilliseconds,
string expectedFailure)
{
var configuration = BuildConfiguration(new Dictionary<string, string?>
{
["Agent:BindAddress"] = "127.0.0.1",
["Agent:Port"] = port,
["Agent:WebSocketFrameFlushMilliseconds"] = flushMilliseconds,
["Agent:RingBufferLineLimit"] = "4000"
});
var services = new ServiceCollection();
services.AddAgentOptions(configuration);
using var provider = services.BuildServiceProvider();
var exception = Assert.Throws<OptionsValidationException>(
() => provider.GetRequiredService<IOptions<AgentOptions>>().Value);
Assert.Contains(exception.Failures, failure => failure.Contains(expectedFailure));
}
private static IConfiguration BuildConfiguration(IReadOnlyDictionary<string, string?> values)
{
return new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();
}
}

View File

@ -11,7 +11,7 @@ public class AgentOptionsValidatorTests
{
DataRoot = "",
BindAddress = "0.0.0.0",
HttpsPort = 9443
Port = 9443
};
var validator = new AgentOptionsValidator();

View File

@ -1,10 +0,0 @@
namespace TermRemoteCtl.Agent.Tests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}