Control Utilities
On this page
Namespaces: Nalix.SDK, Nalix.SDK.Transport.Extensions
Assembly: Nalix.SDK
Nalix.SDK provides built-in control-plane extensions on ITransportSession for round-trip latency measurement (PingAsync), graceful disconnect notification (DisconnectGracefullyAsync), NTP-style clock synchronization (SyncTimeAsync + TimeSyncCalculator), and raw control packet transmission (SendControlAsync).
Source Mapping
src/Nalix.SDK/Transport/Extensions/PingExtensions.cssrc/Nalix.SDK/Transport/Extensions/DisconnectExtensions.cssrc/Nalix.SDK/Transport/Extensions/TimeSyncExtensions.cssrc/Nalix.SDK/Transport/Extensions/ControlExtensions.cssrc/Nalix.SDK/TimeSyncCalculator.cssrc/Nalix.Codec/ProtocolFrames/Control.cssrc/Nalix.Codec/ProtocolFrames/TimeSync.cs
Public API Reference
1. PingExtensions (PingAsync)
namespace Nalix.SDK.Transport.Extensions;
public static class PingExtensions
{
public static ValueTask<double> PingAsync(
this ITransportSession session,
int timeoutMs = 5000,
CancellationToken ct = default);
}
- Sends a
TimeSyncpacket (session.NewTimeSync(ControlType.PING).WithSeq(seq).Build()) and awaits a matchingTimeSync(Type == ControlType.PONG && SequenceId == seq). - Computes the round-trip time (RTT) in milliseconds using
Stopwatch.GetElapsedTime(startTicks).TotalMilliseconds. - Used automatically by
TransportSessionwhenTransportOptions.KeepAliveIntervalMillis > 0.
2. DisconnectExtensions (DisconnectGracefullyAsync)
namespace Nalix.SDK.Transport.Extensions;
public static class DisconnectExtensions
{
public static ValueTask DisconnectGracefullyAsync(
this ITransportSession session,
ProtocolReason reason = ProtocolReason.NONE,
bool closeLocalConnection = true,
CancellationToken ct = default);
}
- Sends a
Controlpacket (ControlType.DISCONNECT,Reason = reason) usingsession.NewControl(ControlType.DISCONNECT).WithReason(reason), swallowing send exceptions if the socket is already closed, and callsawait session.DisconnectAsync()whencloseLocalConnection == true.
3. TimeSyncExtensions (SyncTimeAsync) & TimeSyncCalculator
namespace Nalix.SDK.Transport.Extensions;
public static class TimeSyncExtensions
{
public static TimeSyncBuilder NewTimeSync(
this ITransportSession _,
ControlType type);
public static ValueTask<(double RttMs, double AdjustedMs)> SyncTimeAsync(
this ITransportSession session,
int timeoutMs = 5000,
CancellationToken ct = default);
}
namespace Nalix.SDK;
public static class TimeSyncCalculator
{
public static double CalculateOffsetMs(
long serverUnixMs,
double rttMs = 0,
double maxAllowedDriftMs = 1_000.0,
double maxHardAdjustMs = 10_000.0);
}
- Clock Offset Formula:
SyncTimeAsyncsendsTimeSync(ControlType.TIMESYNCREQUEST)and awaitsTimeSync(ControlType.TIMESYNCRESPONSE).- Calls
TimeSyncCalculator.CalculateOffsetMs(pong.Timestamp, rttMs)to compute the clamped clock offset. - When
session.Options.TimeSyncEnabledistrue, updatessession.Options.TimeOffsetMsusing an Exponential Moving Average ((TimeOffsetMs * 0.9) + (offset * 0.1), or direct assignment on first sync) and returns(RttMs, AdjustedMs: session.Options.TimeOffsetMs).
4. ControlExtensions (NewControl, SendControlAsync, AwaitControlAsync)
namespace Nalix.SDK.Transport.Extensions;
public static class ControlExtensions
{
public static ControlBuilder NewControl(
this ITransportSession _,
ControlType type);
public static ValueTask SendControlAsync(
this ITransportSession client,
ControlType type,
Action<Control>? configure = null,
CancellationToken ct = default);
public static ValueTask<TPkt> AwaitPacketAsync<TPkt>(
this ITransportSession client,
Func<TPkt, bool> predicate,
int timeoutMs,
CancellationToken ct = default)
where TPkt : class, IPacket, IPacketStaticOpcode;
public static ValueTask<Control> AwaitControlAsync(
this ITransportSession client,
ControlType expectedType,
uint expectedSequenceId = 0,
int timeoutMs = 5000,
CancellationToken ct = default);
}
SendControlAsync rents a pooled Control packet from ObjectPoolManager, initializes it with type (and optional configure callback), sends it over client, and returns the Control packet to the pool in a finally block.
Usage Example
using System;
using Nalix.Abstractions.Networking.Protocols;
using Nalix.SDK.Transport.Extensions;
// 1. Measure round-trip latency
double rttMs = await session.PingAsync();
Console.WriteLine($"Ping RTT: {rttMs:F2} ms");
// 2. Synchronize client clock with server using EMA filtering
(double rtt, double adjustedOffsetMs) = await session.SyncTimeAsync();
Console.WriteLine($"RTT: {rtt:F2} ms, Smoothed Offset: {adjustedOffsetMs:F2} ms");
// 3. Notify server and close connection cleanly
await session.DisconnectGracefullyAsync(ProtocolReason.NONE);