using System; using System.IO; using System.Text; namespace Questionable.LgbWorker; internal static class LgbWorkerFraming { public static void Write(Stream stream, in LgbWorkerMessage message) { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true); binaryWriter.Write((byte)message.Type); switch (message.Type) { case LgbMessageType.Progress: binaryWriter.Write(message.Done); binaryWriter.Write(message.Total); break; case LgbMessageType.Final: binaryWriter.Write(message.Success); binaryWriter.Write(message.DurationMs); binaryWriter.Write(message.Error ?? string.Empty); break; default: throw new ArgumentOutOfRangeException("message"); } binaryWriter.Flush(); byte[] array = memoryStream.ToArray(); Span span = stackalloc byte[4]; BitConverter.TryWriteBytes(span, array.Length); stream.Write(span); stream.Write(array); } public static LgbWorkerMessage Read(Stream stream) { Span span = stackalloc byte[4]; ReadExact(stream, span); int num = BitConverter.ToInt32(span); if ((num <= 0 || num > 65536) ? true : false) { throw new InvalidDataException($"Invalid frame length: {num}"); } byte[] array = new byte[num]; ReadExact(stream, array); using BinaryReader binaryReader = new BinaryReader(new MemoryStream(array), Encoding.UTF8); LgbMessageType lgbMessageType = (LgbMessageType)binaryReader.ReadByte(); return lgbMessageType switch { LgbMessageType.Progress => new LgbWorkerMessage { Type = lgbMessageType, Done = binaryReader.ReadInt32(), Total = binaryReader.ReadInt32() }, LgbMessageType.Final => new LgbWorkerMessage { Type = lgbMessageType, Success = binaryReader.ReadBoolean(), DurationMs = binaryReader.ReadInt64(), Error = binaryReader.ReadString() }, _ => throw new InvalidDataException($"Unknown message type: {lgbMessageType}"), }; } private static void ReadExact(Stream stream, Span buffer) { int num; for (int i = 0; i < buffer.Length; i += num) { num = stream.Read(buffer.Slice(i)); if (num == 0) { throw new EndOfStreamException(); } } } }