Innovenergy_trunk/csharp/lib/Protocols/DBus/Transport/BufferedSocketReader.cs

93 lines
2.2 KiB
C#

using System.Net.Sockets;
namespace InnovEnergy.Lib.Protocols.DBus.Transport;
// one could use new BufferedStream(new NetworkStream(socket)) instead.
// I did not know this when I wrote this code...
// then again, the Streams API kinda sucks...
public class BufferedSocketReader
{
private readonly Socket _Socket;
private Byte[] _Buffer ;
private Int32 _DataEnd = 0;
private Int32 Free => _Buffer.Length - _DataEnd;
private Int32 Available => _DataEnd - BytesRead;
public Int32 BytesRead { get; private set; } = 0; // TODO: un-expose this?
public BufferedSocketReader(Socket socket, Byte[]? buffer = null)
{
_Socket = socket;
_Buffer = buffer ?? new Byte[1024];
}
private void FetchData()
{
var free = GetFreeSpace();
var span = new Span<Byte>(_Buffer, _DataEnd, free);
_DataEnd += Read(span);
}
private Int32 Read(Span<Byte> targetArea)
{
var nReceived = _Socket.Receive(targetArea, SocketFlags.None, out var err);
if (err != SocketError.Success) throw new Exception($"Failed to read from socket: {err}");
if (nReceived <= 0) throw new Exception("Socket closed");
return nReceived;
}
private Int32 GetFreeSpace()
{
if (Free != 0)
return Free;
Array.Resize(ref _Buffer, _Buffer.Length * 2);
return Free;
}
public Byte PeekByte(Int32 pos = 0)
{
if (Available < 1 + pos)
FetchData();
return _Buffer[BytesRead + pos];
}
public Byte ReadByte()
{
if (Available < 1)
FetchData();
return _Buffer[BytesRead++];
}
public ArraySegment<Byte> ReadSegment(Int32 size)
{
var segment = PeekSegment(size);
BytesRead += size;
return segment;
}
public ArraySegment<Byte> PeekSegment(Int32 size)
{
while (Available < size)
FetchData();
return new ArraySegment<Byte>(_Buffer, BytesRead, size);
}
public void Reset()
{
if (BytesRead > 0 && Available > 0)
Array.Copy(_Buffer, BytesRead, _Buffer, 0, Available);
_DataEnd = Available;
BytesRead = 0;
}
}