73 lines
3.7 KiB
C#
73 lines
3.7 KiB
C#
using System;
|
|
using System.IO.Pipelines;
|
|
using System.IO.Pipes;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AyCode.Core.Serializers.Binaries;
|
|
|
|
public static partial class AcBinarySerializer
|
|
{
|
|
/// <summary>
|
|
/// Serializes <paramref name="value"/> to a Windows / Linux named-pipe server using the
|
|
/// AsyncSegment chunked wire format (<c>[201][UINT16 size][data]</c> per chunk via
|
|
/// <see cref="AsyncPipeWriterOutput"/>). One-shot client lifecycle: connects, streams
|
|
/// chunk-by-chunk with per-chunk <c>FlushAsync</c> for real producer/consumer overlap,
|
|
/// completes, disposes.
|
|
///
|
|
/// <para><b>Wire format</b>: same chunked AsyncSegment framing as SignalR uses internally —
|
|
/// unified format across all transports per ADR-0003 §9. The <c>+5 bytes/chunk</c> overhead
|
|
/// (~0.1% at 4 KB chunks, ~2% at 256-byte test chunks) is the cost of a single shared wire
|
|
/// format and a single framing-strip implementation (in <see cref="AsyncPipeReaderInput.Feed"/>).</para>
|
|
///
|
|
/// <para><b>Streaming behavior</b>: every <c>BufferWriterChunkSize</c>-sized chunk is
|
|
/// flushed to the pipe immediately (per-chunk <c>SyncAwaitFlush</c>). Consumer can start
|
|
/// reading WHILE producer is still serializing — true pipeline parallelism even on small
|
|
/// payloads (no buffer-accumulation-then-flush behavior).</para>
|
|
///
|
|
/// <para><b>Cross-platform</b>: NamedPipe BCL APIs work on Windows and Linux (Unix-domain-
|
|
/// socket-backed on Linux). WASM throws <see cref="PlatformNotSupportedException"/> per
|
|
/// BCL contract.</para>
|
|
///
|
|
/// <para><b>For custom connection management</b> (multiple writes, custom NamedPipe options,
|
|
/// pre-existing connection): use
|
|
/// <see cref="Serialize{T}(T, PipeWriter, AcBinarySerializerOptions, bool, TimeSpan?)"/>
|
|
/// directly on a <see cref="PipeWriter"/> wrapping your own
|
|
/// <see cref="NamedPipeClientStream"/>.</para>
|
|
/// </summary>
|
|
/// <param name="pipeName">Pipe name to connect to.</param>
|
|
/// <param name="value">Object to serialize.</param>
|
|
/// <param name="options">Serializer options. Defaults to <see cref="AcBinarySerializerOptions.Default"/>.
|
|
/// <c>BufferWriterChunkSize</c> controls the wire chunk size (max 65535).</param>
|
|
/// <param name="serverName">NamedPipe server host. Defaults to <c>"."</c> (local machine).</param>
|
|
/// <param name="ct">Cancellation token. For connect-timeout, pass the token of a
|
|
/// <c>new CancellationTokenSource(timeout)</c> — uniform cancellation/timeout pattern.</param>
|
|
public static async Task SerializeToNamedPipeAsync<T>(
|
|
string pipeName,
|
|
T value,
|
|
AcBinarySerializerOptions? options = null,
|
|
string serverName = ".",
|
|
CancellationToken ct = default)
|
|
{
|
|
if (pipeName is null) throw new ArgumentNullException(nameof(pipeName));
|
|
if (serverName is null) throw new ArgumentNullException(nameof(serverName));
|
|
|
|
await using var pipeClient = new NamedPipeClientStream(serverName, pipeName, PipeDirection.Out, System.IO.Pipes.PipeOptions.Asynchronous);
|
|
|
|
await pipeClient.ConnectAsync(ct).ConfigureAwait(false);
|
|
|
|
var pipeWriter = PipeWriter.Create(pipeClient);
|
|
try
|
|
{
|
|
// PipeWriter overload — chunked AsyncSegment framing via AsyncPipeWriterOutput.
|
|
// Receiver's AsyncPipeReaderInput.Feed strips framing internally; unified wire format
|
|
// across all transports per ADR-0003 §9.
|
|
Serialize(value, pipeWriter, options ?? AcBinarySerializerOptions.Default);
|
|
}
|
|
finally
|
|
{
|
|
await pipeWriter.CompleteAsync().ConfigureAwait(false);
|
|
}
|
|
}
|
|
}
|