fix(nodes): locate agents behind a proxy and retry missing countries [CI]
This commit is contained in:
1 parent
1145a53004
commit
0d532caf08
13 files changed
+93
-15
No files matched your search
@@ -6,6 +6,17 @@ namespace Fleet.Server;
|
||||
|
||||
public sealed record EnrollmentContext(string? RemoteIp, JsonElement? ProductMeta);
|
||||
|
||||
/// <summary>
|
||||
/// 节点的真实来源地址:前面有反向代理时,套接字上只有代理的地址,产品在这里决定信不信转发头。
|
||||
/// 没有注册就用套接字地址。
|
||||
/// </summary>
|
||||
public interface IClientAddressSource
|
||||
{
|
||||
/// <param name="socket">套接字上看到的对端地址。</param>
|
||||
/// <param name="header">按名字取请求头的所有值。</param>
|
||||
string? Resolve(System.Net.IPAddress? socket, Func<string, IEnumerable<string>> header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器的身份密钥:操作员用 passkey 把它的公钥签进操作员集合。有它的时候,认证挑战会带上服务器的签名,节点据此确认对面是真的服务器,
|
||||
/// 并在这条链路上用应用层加密。没有注册就是旧的行为(没有服务器身份)。
|
||||
@@ -38,7 +49,8 @@ public enum NodeEventKind
|
||||
Heartbeat,
|
||||
}
|
||||
|
||||
public sealed record NodeEvent(NodeEventKind Kind, NodeRecord Node, long AtMs, HelloParams? Hello = null, JsonElement? Extra = null, string? Reason = null);
|
||||
/// <param name="RemoteIp">这条连接的来源地址(经过 <see cref="IClientAddressSource"/>);没有就是 null。</param>
|
||||
public sealed record NodeEvent(NodeEventKind Kind, NodeRecord Node, long AtMs, HelloParams? Hello = null, JsonElement? Extra = null, string? Reason = null, string? RemoteIp = null);
|
||||
|
||||
public interface INodeEventSink
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ public static class FleetEnrollmentEndpoints
|
||||
return Problem(StatusCodes.Status400BadRequest, FleetErrors.InvalidParams, "request body is not valid");
|
||||
}
|
||||
|
||||
Result<EnrollResponse> result = await service.EnrollAsync(request, http.Connection.RemoteIpAddress?.ToString(), http.RequestAborted);
|
||||
Result<EnrollResponse> result = await service.EnrollAsync(request, ClientIp(http), http.RequestAborted);
|
||||
if (result.TryGet(out EnrollResponse? response, out FleetError? error))
|
||||
{
|
||||
return Results.Json(response, EnrollmentJsonContext.Default.EnrollResponse, statusCode: StatusCodes.Status201Created);
|
||||
@@ -88,6 +88,11 @@ public static class FleetEnrollmentEndpoints
|
||||
return Problem(status, error.Code, error.Message);
|
||||
}
|
||||
|
||||
private static string? ClientIp(HttpContext http) =>
|
||||
http.RequestServices.GetService<IClientAddressSource>() is { } source
|
||||
? source.Resolve(http.Connection.RemoteIpAddress, name => http.Request.Headers[name].Select(v => v ?? ""))
|
||||
: http.Connection.RemoteIpAddress?.ToString();
|
||||
|
||||
private static async Task<EnrollRequest?> ReadBodyAsync(HttpContext http, CancellationToken ct)
|
||||
{
|
||||
if (http.Request.ContentLength > MaxBodyBytes)
|
||||
|
||||
@@ -67,9 +67,9 @@ public sealed class FleetLinkHost : IFleetConnections, IStateNotifier
|
||||
_connections.TryGetValue(node, out NodeConnection? c) ? c.Session : null;
|
||||
|
||||
/// <summary>处理一条 WebSocket 连接,直到连接结束。</summary>
|
||||
public async Task RunConnectionAsync(WebSocket socket, CancellationToken ct)
|
||||
public async Task RunConnectionAsync(WebSocket socket, string? remoteIp, CancellationToken ct)
|
||||
{
|
||||
using var connection = new NodeConnection(this, socket);
|
||||
using var connection = new NodeConnection(this, socket, remoteIp);
|
||||
await connection.RunAsync(ct);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,10 @@ public static class FleetServerExtensions
|
||||
}
|
||||
|
||||
using System.Net.WebSockets.WebSocket socket = await http.WebSockets.AcceptWebSocketAsync();
|
||||
await http.RequestServices.GetRequiredService<FleetLinkHost>().RunConnectionAsync(socket, http.RequestAborted);
|
||||
string? remote = http.RequestServices.GetService<IClientAddressSource>() is { } source
|
||||
? source.Resolve(http.Connection.RemoteIpAddress, name => http.Request.Headers[name].Select(v => v ?? ""))
|
||||
: http.Connection.RemoteIpAddress?.ToString();
|
||||
await http.RequestServices.GetRequiredService<FleetLinkHost>().RunConnectionAsync(socket, remote, http.RequestAborted);
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ internal sealed partial class NodeConnection
|
||||
|
||||
private async Task FireAsync(NodeEventKind kind, CancellationToken ct, HelloParams? hello = null, JsonElement? extra = null)
|
||||
{
|
||||
var nodeEvent = new NodeEvent(kind, _node!, _host.Time.GetUtcNow().ToUnixTimeMilliseconds(), hello, extra, kind == NodeEventKind.Offline ? _closeReason : null);
|
||||
var nodeEvent = new NodeEvent(kind, _node!, _host.Time.GetUtcNow().ToUnixTimeMilliseconds(), hello, extra, kind == NodeEventKind.Offline ? _closeReason : null, _remoteIp);
|
||||
foreach (INodeEventSink sink in _host.Sinks)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -34,10 +34,13 @@ internal sealed partial class NodeConnection : IDisposable
|
||||
private bool _helloDone;
|
||||
private int _violations;
|
||||
|
||||
public NodeConnection(FleetLinkHost host, WebSocket socket)
|
||||
private readonly string? _remoteIp;
|
||||
|
||||
public NodeConnection(FleetLinkHost host, WebSocket socket, string? remoteIp = null)
|
||||
{
|
||||
_host = host;
|
||||
_socket = socket;
|
||||
_remoteIp = remoteIp;
|
||||
}
|
||||
|
||||
public NodeId NodeId => _node!.Id;
|
||||
|
||||
Reference in new issue
Block a user