refactor(historian): remove named-pipe transport

This commit is contained in:
Joseph Doherty
2026-06-12 11:51:53 -04:00
parent 6104eaba60
commit 72f32045a4
16 changed files with 84 additions and 819 deletions
@@ -1,4 +1,3 @@
using System.IO.Pipes;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
@@ -31,22 +30,6 @@ internal sealed class FrameChannel : IAsyncDisposable
private FrameWriter? _writer;
private bool _disposed;
/// <summary>
/// Default factory: connects to a real <see cref="NamedPipeClientStream"/> by name.
/// </summary>
public static Func<WonderwareHistorianClientOptions, CancellationToken, Task<Stream>> DefaultNamedPipeConnectFactory =
async (opts, ct) =>
{
var pipe = new NamedPipeClientStream(
serverName: ".",
pipeName: opts.PipeName,
direction: PipeDirection.InOut,
options: PipeOptions.Asynchronous);
await pipe.ConnectAsync((int)opts.EffectiveConnectTimeout.TotalMilliseconds, ct).ConfigureAwait(false);
return pipe;
};
/// <summary>
/// Default TCP factory: connects to the sidecar over TCP, optionally wrapping the stream
/// in TLS (server-auth; pinned-thumbprint or CA-chain validation). The Hello handshake +
@@ -63,7 +46,7 @@ internal sealed class FrameChannel : IAsyncDisposable
{
using var connectCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
connectCts.CancelAfter(opts.EffectiveConnectTimeout);
await tcp.ConnectAsync(opts.Host!, opts.Port, connectCts.Token).ConfigureAwait(false);
await tcp.ConnectAsync(opts.Host, opts.Port, connectCts.Token).ConfigureAwait(false);
}
catch
{
@@ -85,7 +68,7 @@ internal sealed class FrameChannel : IAsyncDisposable
});
try
{
await ssl.AuthenticateAsClientAsync(opts.Host!).ConfigureAwait(false);
await ssl.AuthenticateAsClientAsync(opts.Host).ConfigureAwait(false);
}
catch
{
@@ -527,12 +527,12 @@ public sealed class WonderwareHistorianClient : IHistorianDataSource, IAlarmHist
/// <summary>
/// Synchronous dispose required by <see cref="IDisposable"/> on
/// <see cref="IHistorianDataSource"/>. The underlying channel's async cleanup runs
/// <see cref="System.IO.Pipes.NamedPipeClientStream"/> teardown, which can block briefly
/// on OS handle release — strictly speaking it is not non-blocking — but the
/// <c>GetAwaiter()/GetResult()</c> bridge is deadlock-safe because the cleanup never
/// awaits a captured <see cref="System.Threading.SynchronizationContext"/> nor takes any
/// lock that the caller could hold. (Finding 010.)
/// <see cref="IHistorianDataSource"/>. The underlying channel's async cleanup runs the
/// TCP socket teardown, which can block briefly on OS handle release — strictly speaking
/// it is not non-blocking — but the <c>GetAwaiter()/GetResult()</c> bridge is
/// deadlock-safe because the cleanup never awaits a captured
/// <see cref="System.Threading.SynchronizationContext"/> nor takes any lock that the
/// caller could hold. (Finding 010.)
/// </summary>
public void Dispose() => _channel.DisposeAsync().AsTask().GetAwaiter().GetResult();
}