/// <summary>
/// Reads a packet from a stream.
/// </summary>
/// <param name="stream"> The stream. </param>
/// <returns> </returns>
internal static async Task<Frame> FromStream(Stream stream)
{
//read header
int read = 0;
var header = new byte[8];
while (read < 8)
read += await stream.ReadAsync(header, read, 8 - read).ConfigureAwait(false);
//get length
if (BitConverter.IsLittleEndian) Array.Reverse(header, 4, 4);
int length = BitConverter.ToInt32(header, 4);
Frame frame;
switch ((FrameOpcode)header[3])
{
case FrameOpcode.Error:
frame = new ErrorFrame();
break;
case FrameOpcode.Ready:
frame = new ReadyFrame();
break;
case FrameOpcode.Authenticate:
frame = new AuthenticateFrame();
break;
case FrameOpcode.Supported:
frame = new SupportedFrame();
break;
case FrameOpcode.Result:
frame = new ResultFrame();
break;
case FrameOpcode.Event:
frame = new EventFrame();
break;
default:
throw new ProtocolException(0, "Unexpected OpCode received.");
}
frame.Version = (FrameVersion)header[0];
frame.Flags = (FrameFlags)header[1];
frame.Stream = unchecked((sbyte)header[2]);
frame.OpCode = (FrameOpcode)header[3];
frame.Length = length;
//wrap the stream in a window, that will be completely read when disposed
var reader = new FrameReader(stream, length);
frame.Reader = reader;
//decompress the contents of the frame (implicity loads the entire frame body!)
if (frame.Flags.HasFlag(FrameFlags.Compression))
await reader.DecompressAsync();
//read tracing id if set
if (frame.Flags.HasFlag(FrameFlags.Tracing))
frame.TracingId = await reader.ReadUuidAsync().ConfigureAwait(false);
await frame.InitializeAsync().ConfigureAwait(false);
return frame;
}