using InABox.Core; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; namespace InABox.WebSocket.Shared { public class ByteReader { public byte[] Data; public int Index; public ByteReader(byte[] data) { Data = data; Index = 0; } public Guid ReadGuid() { var guid = new Guid(new ReadOnlySpan(Data, Index, 16)); Index += 16; return guid; } public string ReadUTF8String() { int i = Index; while (i < Data.Length && Data[i] != 0) { i++; } var str = Encoding.UTF8.GetString(Data, Index, i - Index); Index = i + 1; return str; } public byte ReadByte() { return Data[Index++]; } public ByteReader Skip(int count) { Index += count; return this; } } public class ByteWriter { private Stream Stream; public ByteWriter(Stream stream) { Stream = stream; } public ByteWriter WriteByte(byte b) { Stream.WriteByte(b); return this; } public ByteWriter WriteGuid(Guid guid) { Stream.Write(guid.ToByteArray()); return this; } /// /// Writes a null-terminated UTF-8 encoded string to the buffer /// /// /// public ByteWriter WriteUTF8String(string str) { Stream.Write(Encoding.UTF8.GetBytes(str)); Stream.WriteByte(0); return this; } } public abstract class SocketMessage { public enum MessageType { Initial = 0x00, Notify = 0x01 } public abstract MessageType Type { get; } protected abstract void Write(ByteWriter writer); public void Write(Stream stream) { var writer = new ByteWriter(stream) .WriteByte((byte)Type); Write(writer); } public byte[] WriteToBytes() { using(var stream = new MemoryStream()) { Write(stream); return stream.GetBuffer().ToArray(); } } public static SocketMessage? ReadMessage(byte[] data) { try { var type = (MessageType)data[0]; var byteReader = new ByteReader(data).Skip(1); switch (type) { case MessageType.Initial: return InitialMessage.ReadMessage(byteReader); case MessageType.Notify: return NotifyMessage.ReadMessage(byteReader); } } catch (Exception) { return null; } return null; } } public class InitialMessage : SocketMessage { public override MessageType Type => MessageType.Initial; public Guid SessionID { get; set; } public Platform Platform { get; set; } public InitialMessage(Guid sessionID, Platform platform) { SessionID = sessionID; Platform = platform; } protected override void Write(ByteWriter writer) { writer.WriteGuid(SessionID) .WriteByte((byte)Platform); } public static InitialMessage ReadMessage(ByteReader data) { var session = data.ReadGuid(); var platform = (Platform)data.ReadByte(); return new InitialMessage(session, platform); } } public class NotifyMessage : SocketMessage { public override MessageType Type => MessageType.Notify; public string EntityType; public string EntityData; private NotifyMessage(string entityType, string entityData) { EntityType = entityType; EntityData = entityData; } protected override void Write(ByteWriter writer) { writer.WriteUTF8String(EntityType); writer.WriteUTF8String(EntityData); } public static NotifyMessage ReadMessage(ByteReader reader) { var type = reader.ReadUTF8String(); var data = reader.ReadUTF8String(); return new NotifyMessage(type, data); } public static NotifyMessage Notify(TNotification notification) { return new NotifyMessage(typeof(TNotification).EntityName(), Serialization.Serialize(notification)); } public static NotifyMessage Notify(Type TNotification, object notification) { return new NotifyMessage(TNotification.EntityName(), Serialization.Serialize(notification)); } } }