using System.Net.Sockets; namespace InnovEnergy.Lib.Channels.V2; public class TcpChannel : IChannel> { private Int32 TimeoutMs { get; } private String Hostname { get; } private UInt16 Port { get; } private Byte[] Buffer { get; } private Socket? Socket { get; set; } public TcpChannel(String hostname, UInt16 port, TimeSpan timeout = default, Int32 bufferSize = 8192) { if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize)); Hostname = hostname; Port = port; TimeoutMs = (Int32)timeout.TotalMilliseconds; Buffer = new Byte[bufferSize]; } public async Task> Read() { try { await Open(); var nRead = await Socket!.ReceiveAsync(Buffer, SocketFlags.None); if (nRead <= 0) throw new Exception("TCP Connection was closed"); // copy from buffer, so we can reuse it var data = new Byte[nRead]; Array.Copy(Buffer, data, nRead); return data; } catch { Close(); throw; } } private async Task Open() { if (Socket is not null) return; Socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { Blocking = true, NoDelay = true, LingerState = new LingerOption(false, 0), ReceiveBufferSize = Buffer.Length, SendBufferSize = Buffer.Length, ReceiveTimeout = TimeoutMs, SendTimeout = TimeoutMs, }; var cts = new CancellationTokenSource(); cts.CancelAfter(TimeoutMs); try { await Socket.ConnectAsync(Hostname, Port, cts.Token).AsTask(); } catch { Socket = null!; throw; } } public async Task Write(IReadOnlyList tx) { try { await Open(); await Socket!.SendAsync(tx as Byte[] ?? tx.ToArray(), SocketFlags.None); } catch { Close(); throw; } } private void Close() { if (Socket is null) return; try { Socket.Dispose(); } finally { Socket = null; } } }