Nalix.SDK.Transport.Extensions — TcpSession Helpers for Control, Directive, and Request Flows¶
The Nalix.SDK.Transport.Extensions namespace enriches IClientConnection/TcpSession with helpers for protocol control packets, directives, secure handshakes, request/response coordination, throttling safety, and subscription management. The helpers keep receive loops resilient by owning leases and catching handler faults.
Source mapping¶
src/Nalix.SDK/Transport/Extensions/ControlExtensions.cssrc/Nalix.SDK/Transport/Extensions/DirectiveClientExtensions.cssrc/Nalix.SDK/Transport/Extensions/HandshakeExtensions.cssrc/Nalix.SDK/Transport/Extensions/RequestExtensions.cssrc/Nalix.SDK/Transport/Extensions/TcpSessionSubscriptions.cs
Key capabilities¶
- Checklist:
- Control helpers:
NewControl,PingAsync,AwaitControlAsync. - Handshake:
HandshakeAsync(X25519 + Keccak256) updatesTransportOptions.Secret. - Directives:
TryHandleDirectiveAsync, throttle/redirect/NACK/NOTICE handling. - Requests:
RequestAsyncwithRequestOptions(timeout, retry, encrypt). -
Subscriptions:
On,OnOnce,SubscribeTemp,CompositeSubscription. -
Fluent
Controlbuilders, PING/PONG helpers, and awaiters that usePacketAwaiterto avoid race conditions. - Secure X25519 handshake +
Keccak256key derivation that installs the shared secret onTransportOptions.Secret. - Directive processing (
THROTTLE,REDIRECT,NACK,NOTICE) with optional callbacks and default auto-redirect nursing. - Request/response helpers (
RequestAsync,RequestOptions) that send, await, optionally encrypt, and retry safely. - Subscription helpers (
On<T>,OnOnce<T>,SubscribeTemp,Subscribe) that automatically dispose leases and log handler errors.
Control helpers (ControlExtensions)¶
NewControl(opCode, ControlType, ProtocolType)starts a fluent builder that stampsMonoTicks/Timestampand lets you chain.WithSeq(),.WithReason(),.WithTransport(), then.Build().AwaitPacketAsync<TPkt>/AwaitControlAsyncwaits for a matching packet/control with timeout and cancellation.PingAsyncsends a CONTROL PING and awaits the corresponding PONG, returns(rttMs, Control pong)and optionally syncs the client clock with the server timestamp.SendControlAsyncmaterializes the builder, applies any extra configuration, and transmits the CONTROL frame.- All helpers use
PACKET_AWAITERto avoid races and to ensure timeouts/reconnects are handled uniformly.
Handshake (HandshakeExtensions)¶
HandshakeAsyncperforms a full X25519 Diffie-Hellman exchange using a helperHandshakepacket (op code default 1).- The server response is validated via an optional
validateServerPublicKeycallback; if accepted, the derived secret is hashed with SHA3 (Keccak256) and stored inTransportOptions.Secret. - Sensitive material (private key + shared secret) is zeroed when the handshake completes or fails.
- A temporary subscription (
SubscribeTemp) ensures the handshake response is captured without leaking listeners or leases.
Directive handling (DirectiveClientExtensions)¶
TryHandleDirectiveAsyncinspects an incomingDirectivepacket and handles the four protocol control types:THROTTLE: records the throttle window in monotonic ticks and triggersOnThrottlecallbacks.REDIRECT: optionally delegates to a callback, otherwise resolves(host, port)from the directive args, updatesTransportOptions, disconnects, and reconnects.NACK/NOTICE: forwards to callbacks and logs the reason.IsThrottled(out TimeSpan remaining)reports active throttle windows based on monotonic clocks.SendWithThrottleAsyncwaits for the active throttle window before sending a packet, keeping the client protocol-compliant.ClearThrottleresets any stored throttle state for the client.
Request/response helpers (RequestExtensions)¶
RequestAsync<TRequest, TResponse>combines send+await into a single, race-free operation.- Overload with
RequestOptionscontrols timeout, retry count, and optional encryption (Encrypt = truerequiresTcpSessionBase). RequestOptions.Defaultships with 5s timeout, no retries, and no encryption; fluent builders (WithTimeout,WithRetry,WithEncrypt) make tweaks easy.- Only
TimeoutExceptionis retried; other fatal errors (disconnects, invalid packets) propagate immediately. RequestAsync<TResponse>(IPacket request, RequestOptions? options = null, Func<TResponse, bool>? predicate = null)handles both wildcard and filtered waits.- The helpers log retry attempts via
ILoggerwhenInstanceManagerprovides one.
Subscription helpers (TcpSessionSubscriptions)¶
On<TPacket>/On(predicate, handler)register handlers that own theIBufferLeaseand dispose it inside afinallyblock.OnOnce<TPacket>fires exactly once, auto-unsubscribing even under concurrent arrivals.SubscribeTemp<TPacket>combines a temporary message handler with an optionalOnDisconnectedhook for request/response scenarios.Subscribeop encodes multiple subscriptions into aCompositeSubscriptionfor easy disposal.- Exceptions thrown by subscribers are caught and logged so that the receive loop never faults.
Best practices¶
Flow: connect session → perform handshake → optionally handle directives/throttle → use PingAsync/RequestAsync with awaiters → dispose subscriptions.
- Always dispose the
IDisposablereturned by subscription helpers (useusing var), especially before issuingRequestAsynccalls. - When sending throttled traffic, wrap
SendWithThrottleAsyncaround your packets so you never violate server directives. - Pin server public keys via
HandshakeAsync(... validateServerPublicKey: ...)to harden clients against MITM. - Use
RequestOptions.WithEncrypt()only onTcpSession/IoTTcpSessioninstances; the base class exposesSendAsync(packet, encrypt: true)for encryption-aware transports.
Example¶
await session.HandshakeAsync(validateServerPublicKey: key => key.SequenceEqual(expectedKey), ct);
using var sub = session.On<PingResponse>((packet, lease) =>
{
Console.WriteLine("pong received");
});
PingResponse reply = await session.RequestAsync<PingRequest, PingResponse>(
new PingRequest(),
RequestOptions.Default.WithTimeout(TimeSpan.FromSeconds(3)),
ct);