AyCode.Core/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.NamedP...

57 lines
2.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}