feat: add no-pool route fallback for backward compatibility (Gap 13.6)
Add SupportsPooling/IsLegacyRoute properties to RouteConnection and GetLegacyRoute/GetLegacyRoutes/HasLegacyRoutes to RouteManager. Update GetRouteForAccount to fall back to legacy routes when no dedicated or pool-capable route is available, matching Go route.go getRoutesExcludePool.
This commit is contained in:
@@ -30,6 +30,20 @@ public sealed class RouteConnection(Socket socket) : IAsyncDisposable
|
||||
/// </summary>
|
||||
public int NegotiatedPoolSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when pool size negotiation has completed and the remote peer
|
||||
/// supports route pooling (<see cref="NegotiatedPoolSize"/> > 0).
|
||||
/// Go reference: server/route.go — pool-capable route check.
|
||||
/// </summary>
|
||||
public bool SupportsPooling => NegotiatedPoolSize > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when this connection is a legacy (pre-pool) route, i.e. the
|
||||
/// remote peer does not support route pooling (<see cref="NegotiatedPoolSize"/> == 0).
|
||||
/// Go reference: server/route.go getRoutesExcludePool.
|
||||
/// </summary>
|
||||
public bool IsLegacyRoute => NegotiatedPoolSize == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Negotiates the effective route pool size between local and remote peers.
|
||||
/// Returns <c>Math.Min(localPoolSize, remotePoolSize)</c>, but returns 0 if
|
||||
|
||||
@@ -166,27 +166,58 @@ public sealed class RouteManager : IAsyncDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Returns the route connection responsible for the given account. Checks
|
||||
/// dedicated account routes first, then falls back to pool-based selection.
|
||||
/// Go reference: server/route.go — per-account dedicated route lookup.
|
||||
/// dedicated account routes first, then falls back to pool-based selection,
|
||||
/// and finally falls back to the first legacy (pre-pool) route.
|
||||
/// Go reference: server/route.go — per-account dedicated route lookup,
|
||||
/// getRoutesExcludePool (legacy fallback).
|
||||
/// </summary>
|
||||
public RouteConnection? GetRouteForAccount(string account)
|
||||
{
|
||||
// Check dedicated account routes first (Gap 13.2).
|
||||
// 1st: Check dedicated account routes (Gap 13.2).
|
||||
if (_accountRoutes.TryGetValue(account, out var dedicated))
|
||||
return dedicated;
|
||||
|
||||
if (_routes.IsEmpty)
|
||||
return null;
|
||||
|
||||
var routes = _routes.Values.ToArray();
|
||||
if (routes.Length == 0)
|
||||
return null;
|
||||
// 2nd: Try pool-based routes (current behavior).
|
||||
var poolRoutes = _routes.Values.Where(r => r.SupportsPooling).ToArray();
|
||||
if (poolRoutes.Length > 0)
|
||||
{
|
||||
var idx = ComputeRoutePoolIdx(poolRoutes.Length, account);
|
||||
return poolRoutes[idx % poolRoutes.Length];
|
||||
}
|
||||
|
||||
var poolSize = routes.Length;
|
||||
var idx = ComputeRoutePoolIdx(poolSize, account);
|
||||
return routes[idx % routes.Length];
|
||||
// 3rd: Fall back to legacy route when no pool routes exist (Gap 13.6).
|
||||
return GetLegacyRoute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first route connection with <see cref="RouteConnection.IsLegacyRoute"/>
|
||||
/// equal to <c>true</c>, or <c>null</c> if no legacy routes are registered.
|
||||
/// Legacy routes are connections to pre-pool peers that did not negotiate a
|
||||
/// pool size during the handshake.
|
||||
/// Go reference: server/route.go getRoutesExcludePool.
|
||||
/// </summary>
|
||||
public RouteConnection? GetLegacyRoute()
|
||||
=> _routes.Values.FirstOrDefault(r => r.IsLegacyRoute);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all route connections with <see cref="RouteConnection.IsLegacyRoute"/>
|
||||
/// equal to <c>true</c>. Returns an empty list when no legacy routes exist.
|
||||
/// Go reference: server/route.go getRoutesExcludePool.
|
||||
/// </summary>
|
||||
public IReadOnlyList<RouteConnection> GetLegacyRoutes()
|
||||
=> _routes.Values.Where(r => r.IsLegacyRoute).ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> when at least one registered route connection is a
|
||||
/// legacy (pre-pool) route.
|
||||
/// Go reference: server/route.go getRoutesExcludePool.
|
||||
/// </summary>
|
||||
public bool HasLegacyRoutes
|
||||
=> _routes.Values.Any(r => r.IsLegacyRoute);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a dedicated route connection for a specific account. If a
|
||||
/// previous connection was registered for the same account it is replaced.
|
||||
|
||||
Reference in New Issue
Block a user