Implement InMemory Transport Layer for StellaOps Router

- Added InMemoryTransportOptions class for configuration settings including timeouts and latency.
- Developed InMemoryTransportServer class to handle connections, frame processing, and event management.
- Created ServiceCollectionExtensions for easy registration of InMemory transport services.
- Established project structure and dependencies for InMemory transport library.
- Implemented comprehensive unit tests for endpoint discovery, connection management, request/response flow, and streaming capabilities.
- Ensured proper handling of cancellation, heartbeat, and hello frames within the transport layer.
This commit is contained in:
StellaOps Bot
2025-12-05 01:00:10 +02:00
parent 8768c27f30
commit 175b750e29
111 changed files with 25407 additions and 19242 deletions

View File

@@ -0,0 +1,12 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Payload for the Cancel frame.
/// </summary>
public sealed record CancelPayload
{
/// <summary>
/// Gets the reason for cancellation.
/// </summary>
public string? Reason { get; init; }
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Represents a claim requirement for endpoint authorization.
/// </summary>
public sealed record ClaimRequirement
{
/// <summary>
/// Gets the claim type that must be present.
/// </summary>
public required string Type { get; init; }
/// <summary>
/// Gets the optional claim value that must match.
/// </summary>
public string? Value { get; init; }
}

View File

@@ -0,0 +1,44 @@
using StellaOps.Router.Common.Enums;
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Represents the state of a connection between a microservice and the router.
/// </summary>
public sealed class ConnectionState
{
/// <summary>
/// Gets the unique identifier for this connection.
/// </summary>
public required string ConnectionId { get; init; }
/// <summary>
/// Gets the instance descriptor for the connected microservice.
/// </summary>
public required InstanceDescriptor Instance { get; init; }
/// <summary>
/// Gets or sets the health status of this connection.
/// </summary>
public InstanceHealthStatus Status { get; set; } = InstanceHealthStatus.Unknown;
/// <summary>
/// Gets or sets the UTC timestamp of the last heartbeat.
/// </summary>
public DateTime LastHeartbeatUtc { get; set; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets the average ping time in milliseconds.
/// </summary>
public double AveragePingMs { get; set; }
/// <summary>
/// Gets the endpoints served by this connection.
/// </summary>
public Dictionary<(string Method, string Path), EndpointDescriptor> Endpoints { get; } = new();
/// <summary>
/// Gets the transport type used for this connection.
/// </summary>
public required TransportType TransportType { get; init; }
}

View File

@@ -0,0 +1,42 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Describes an endpoint's identity and metadata.
/// </summary>
public sealed record EndpointDescriptor
{
/// <summary>
/// Gets the name of the service that owns this endpoint.
/// </summary>
public required string ServiceName { get; init; }
/// <summary>
/// Gets the semantic version of the service.
/// </summary>
public required string Version { get; init; }
/// <summary>
/// Gets the HTTP method (GET, POST, PUT, PATCH, DELETE).
/// </summary>
public required string Method { get; init; }
/// <summary>
/// Gets the path template (e.g., "/billing/invoices/{id}").
/// </summary>
public required string Path { get; init; }
/// <summary>
/// Gets the default timeout for this endpoint.
/// </summary>
public TimeSpan DefaultTimeout { get; init; } = TimeSpan.FromSeconds(30);
/// <summary>
/// Gets the claim requirements for authorization.
/// </summary>
public IReadOnlyList<ClaimRequirement> RequiringClaims { get; init; } = [];
/// <summary>
/// Gets a value indicating whether this endpoint supports streaming.
/// </summary>
public bool SupportsStreaming { get; init; }
}

View File

@@ -0,0 +1,24 @@
using StellaOps.Router.Common.Enums;
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Represents a protocol frame in the router transport layer.
/// </summary>
public sealed record Frame
{
/// <summary>
/// Gets the type of this frame.
/// </summary>
public required FrameType Type { get; init; }
/// <summary>
/// Gets the correlation ID for request/response matching.
/// </summary>
public string? CorrelationId { get; init; }
/// <summary>
/// Gets the raw payload bytes.
/// </summary>
public ReadOnlyMemory<byte> Payload { get; init; }
}

View File

@@ -0,0 +1,34 @@
using StellaOps.Router.Common.Enums;
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Payload for the Heartbeat frame sent periodically by microservices.
/// </summary>
public sealed record HeartbeatPayload
{
/// <summary>
/// Gets the instance ID.
/// </summary>
public required string InstanceId { get; init; }
/// <summary>
/// Gets the health status.
/// </summary>
public required InstanceHealthStatus Status { get; init; }
/// <summary>
/// Gets the current in-flight request count.
/// </summary>
public int InFlightRequestCount { get; init; }
/// <summary>
/// Gets the error rate (0.0 to 1.0).
/// </summary>
public double ErrorRate { get; init; }
/// <summary>
/// Gets the timestamp when this heartbeat was created.
/// </summary>
public DateTime TimestampUtc { get; init; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,17 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Payload for the Hello frame sent by microservices on connection.
/// </summary>
public sealed record HelloPayload
{
/// <summary>
/// Gets the instance descriptor.
/// </summary>
public required InstanceDescriptor Instance { get; init; }
/// <summary>
/// Gets the endpoints registered by this instance.
/// </summary>
public required IReadOnlyList<EndpointDescriptor> Endpoints { get; init; }
}

View File

@@ -0,0 +1,27 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Describes a microservice instance's identity.
/// </summary>
public sealed record InstanceDescriptor
{
/// <summary>
/// Gets the unique identifier for this instance.
/// </summary>
public required string InstanceId { get; init; }
/// <summary>
/// Gets the name of the service.
/// </summary>
public required string ServiceName { get; init; }
/// <summary>
/// Gets the semantic version of the service.
/// </summary>
public required string Version { get; init; }
/// <summary>
/// Gets the region where this instance is deployed.
/// </summary>
public required string Region { get; init; }
}

View File

@@ -0,0 +1,30 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Configuration for payload and memory limits.
/// </summary>
public sealed record PayloadLimits
{
/// <summary>
/// Default payload limits.
/// </summary>
public static readonly PayloadLimits Default = new();
/// <summary>
/// Gets the maximum request bytes per call.
/// Default: 10 MB.
/// </summary>
public long MaxRequestBytesPerCall { get; init; } = 10 * 1024 * 1024;
/// <summary>
/// Gets the maximum request bytes per connection.
/// Default: 100 MB.
/// </summary>
public long MaxRequestBytesPerConnection { get; init; } = 100 * 1024 * 1024;
/// <summary>
/// Gets the maximum aggregate in-flight bytes across all requests.
/// Default: 1 GB.
/// </summary>
public long MaxAggregateInflightBytes { get; init; } = 1024 * 1024 * 1024;
}

View File

@@ -0,0 +1,48 @@
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Neutral routing context that does not depend on ASP.NET.
/// Gateway will adapt from HttpContext to this neutral model.
/// </summary>
public sealed record RoutingContext
{
/// <summary>
/// Gets the HTTP method (GET, POST, PUT, PATCH, DELETE).
/// </summary>
public required string Method { get; init; }
/// <summary>
/// Gets the request path.
/// </summary>
public required string Path { get; init; }
/// <summary>
/// Gets the request headers.
/// </summary>
public IReadOnlyDictionary<string, string> Headers { get; init; } = new Dictionary<string, string>();
/// <summary>
/// Gets the resolved endpoint descriptor.
/// </summary>
public EndpointDescriptor? Endpoint { get; init; }
/// <summary>
/// Gets the available connections for routing.
/// </summary>
public IReadOnlyList<ConnectionState> AvailableConnections { get; init; } = [];
/// <summary>
/// Gets the gateway's region for routing decisions.
/// </summary>
public required string GatewayRegion { get; init; }
/// <summary>
/// Gets the requested version, if specified.
/// </summary>
public string? RequestedVersion { get; init; }
/// <summary>
/// Gets the cancellation token for the request.
/// </summary>
public CancellationToken CancellationToken { get; init; }
}

View File

@@ -0,0 +1,29 @@
using StellaOps.Router.Common.Enums;
namespace StellaOps.Router.Common.Models;
/// <summary>
/// Represents the outcome of a routing decision.
/// </summary>
public sealed record RoutingDecision
{
/// <summary>
/// Gets the selected endpoint.
/// </summary>
public required EndpointDescriptor Endpoint { get; init; }
/// <summary>
/// Gets the selected connection.
/// </summary>
public required ConnectionState Connection { get; init; }
/// <summary>
/// Gets the transport type to use.
/// </summary>
public required TransportType TransportType { get; init; }
/// <summary>
/// Gets the effective timeout for the request.
/// </summary>
public required TimeSpan EffectiveTimeout { get; init; }
}