using PlantBox.Shared.Communication.Commands; using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace PlantBox.Shared.Communication { /// /// Wrap a to send easily, see Wiki > Protocol /// public class CommandStream : IDisposable { private NetworkStream _stream; /// /// Create a new /// /// A connected and valid public CommandStream(NetworkStream networkStream) { _stream = networkStream; } /// /// Release resources associated with the underlying stream /// public void Dispose() { _stream.Dispose(); } /// /// Read a from the stream /// /// public CommandPacket Receive() { // Length byte[] buffer = new byte[4]; _stream.Read(buffer, 0, buffer.Length); uint length = BitConverter.ToUInt32(buffer, 0); // Data buffer = new byte[length]; int position = 0; while (position < length) { int bytesToRead = Math.Min(Connection.BUFFER_SIZE, (int)length - position); int bytesRead = _stream.Read(buffer, position, bytesToRead); position += bytesRead; } string[] packet = Encoding.UTF8.GetString(buffer).Split('\n'); if (!Enum.TryParse(packet[0], true, out Command command)) { command = Command.Invalid; } return new CommandPacket(command, packet[1].Split(';')); } /// /// Read a from the stream and deserialize data to a /// /// A valid /// public (CommandPacket, T) Receive() where T : CommandSerializable, new() { var packet = Receive(); return (packet, new T().Deserialize(packet.Arguments)); } /// /// Read a from the stream asynchronously /// /// public async Task ReceiveAsync() { // Length byte[] buffer = new byte[4]; await _stream.ReadAsync(buffer, 0, buffer.Length); uint length = BitConverter.ToUInt32(buffer, 0); // Data buffer = new byte[length]; int position = 0; while (position < length) { int bytesToRead = Math.Min(Connection.BUFFER_SIZE, (int)length - position); int bytesRead = await _stream.ReadAsync(buffer, position, bytesToRead); position += bytesRead; } string[] packet = Encoding.UTF8.GetString(buffer).Split('\n'); if (!Enum.TryParse(packet[0], true, out Command command)) { command = Command.Invalid; } return new CommandPacket(command, packet[1].Split(';')); } /// /// Read a from the stream and deserialize data to a asynchronously /// /// A valid /// public async Task<(CommandPacket, T)> ReceiveAsync() where T : CommandSerializable, new() { var packet = await ReceiveAsync(); return (packet, new T().Deserialize(packet.Arguments)); } /// /// Write a in the stream /// /// public void Send(CommandPacket command) { string packet = command.ToString(); byte[] data = Encoding.UTF8.GetBytes(packet); uint length = (uint)data.Length; // Length _stream.Write(BitConverter.GetBytes(length), 0, 4); // Data int position = 0; while (position < length) { int bytesToWrite = Math.Min(Connection.BUFFER_SIZE, (int)length - position); _stream.Write(data, position, bytesToWrite); position += bytesToWrite; } } /// /// Write a in the stream asynchronously /// /// /// public async Task SendAsync(CommandPacket command) { string packet = command.ToString(); byte[] data = Encoding.UTF8.GetBytes(packet); uint length = (uint)data.Length; // Length await _stream.WriteAsync(BitConverter.GetBytes(length), 0, 4); // Data int position = 0; while (position < length) { int bytesToWrite = Math.Min(Connection.BUFFER_SIZE, (int)length - position); await _stream.WriteAsync(data, position, bytesToWrite); position += bytesToWrite; } } } }