57 lines
2.9 KiB
C#
57 lines
2.9 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 AcBinaryDeserializer
|
||
{
|
||
/// <summary>
|
||
/// Deserializes from a single named-pipe client connection using AsyncSegment chunked
|
||
/// streaming. One-shot server lifecycle: creates pipe server, awaits connection, drains
|
||
/// via <see cref="AsyncPipeReaderInputExtensions.DrainFromAsync"/> while a background task
|
||
/// deserializes incrementally from the same <see cref="AsyncPipeReaderInput"/>, then
|
||
/// disposes.
|
||
///
|
||
/// <para>Receive buffer initial capacity is derived from <c>options.BufferWriterChunkSize × 2</c>
|
||
/// (the streaming-doctrine heuristic per ADR-0003 §4 — two-chunks-worth of headroom plus
|
||
/// reset-to-0 cycling reuses the same buffer for the message's lifetime regardless of total
|
||
/// payload size).</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 reads, custom NamedPipe options,
|
||
/// pre-existing connection): use
|
||
/// <see cref="Deserialize{T}(AsyncPipeReaderInput, AcBinarySerializerOptions)"/> +
|
||
/// <see cref="AsyncPipeReaderInputExtensions.DrainFromAsync"/> directly on your own
|
||
/// <see cref="NamedPipeServerStream"/>.</para>
|
||
/// </summary>
|
||
/// <param name="pipeName">Pipe name to await connection on.</param>
|
||
/// <param name="options">Serializer options. Defaults to <see cref="AcBinarySerializerOptions.Default"/>.
|
||
/// <c>BufferWriterChunkSize</c> controls the receive-side initial buffer
|
||
/// (<c>BufferWriterChunkSize × 2</c>).</param>
|
||
/// <param name="ct">Cancellation token. For connect-timeout, pass the token of a
|
||
/// <c>new CancellationTokenSource(timeout)</c>.</param>
|
||
public static async Task<T?> DeserializeFromNamedPipeAsync<T>(string pipeName, AcBinarySerializerOptions? options = null, CancellationToken ct = default)
|
||
{
|
||
if (pipeName is null) throw new ArgumentNullException(nameof(pipeName));
|
||
|
||
var opts = options ?? AcBinarySerializerOptions.Default;
|
||
|
||
await using var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, System.IO.Pipes.PipeOptions.Asynchronous);
|
||
|
||
await pipeServer.WaitForConnectionAsync(ct).ConfigureAwait(false);
|
||
var pipeReader = PipeReader.Create(pipeServer);
|
||
|
||
using var input = new AsyncPipeReaderInput(initialCapacity: opts.BufferWriterChunkSize * 2);
|
||
var deserTask = Task.Run(() => Deserialize<T>(input, opts), ct);
|
||
|
||
await input.DrainFromAsync(pipeReader, ct).ConfigureAwait(false);
|
||
return await deserTask.ConfigureAwait(false);
|
||
}
|
||
}
|