|
- using MQTTnet.Formatter;
- using System;
- using System.Buffers;
- using System.Buffers.Binary;
- using System.Text;
-
- namespace MQTTnet.AspNetCore
- {
- public class SpanBasedMqttPacketWriter : IMqttPacketWriter
- {
- private readonly ArrayPool<byte> _pool;
-
- public SpanBasedMqttPacketWriter()
- {
- _pool = ArrayPool<byte>.Create();
-
- }
-
- private byte[] _buffer;
- private int _position;
-
- public int Length { get; set; }
-
- public void FreeBuffer()
- {
- _pool.Return(_buffer);
- }
-
- public byte[] GetBuffer()
- {
- return _buffer;
- }
-
- public void Reset(int v)
- {
- _buffer = _pool.Rent(1500);
- Length = v;
- _position = v;
- }
-
- public void Seek(int v)
- {
- _position = v;
- }
-
- public void Write(byte value)
- {
- GrowIfNeeded(1);
- _buffer[_position] = value;
- Commit(1);
- }
-
- public void Write(ushort value)
- {
- GrowIfNeeded(2);
-
- BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_position), value);
- Commit(2);
- }
-
- public void Write(IMqttPacketWriter propertyWriter)
- {
- if (propertyWriter == null) throw new ArgumentNullException(nameof(propertyWriter));
-
- GrowIfNeeded(propertyWriter.Length);
- Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length);
- Commit(propertyWriter.Length);
- }
-
- public void Write(byte[] payload, int start, int length)
- {
- GrowIfNeeded(length);
-
- payload.AsSpan(start, length).CopyTo(_buffer.AsSpan(_position));
- Commit(length);
- }
-
- public void WriteVariableLengthInteger(uint value)
- {
- GrowIfNeeded(4);
-
- var x = value;
- do
- {
- var encodedByte = x % 128;
- x = x / 128;
- if (x > 0)
- {
- encodedByte = encodedByte | 128;
- }
-
- _buffer[_position] = (byte)encodedByte;
- Commit(1);
- } while (x > 0);
- }
-
- public void WriteWithLengthPrefix(string value)
- {
- var bytesLength = Encoding.UTF8.GetByteCount(value ?? string.Empty);
- GrowIfNeeded(bytesLength + 2);
-
- Write((ushort)bytesLength);
- Encoding.UTF8.GetBytes(value ?? string.Empty, 0, value?.Length ?? 0, _buffer, _position);
- Commit(bytesLength);
- }
-
- public void WriteWithLengthPrefix(byte[] payload)
- {
- GrowIfNeeded(payload.Length + 2);
-
- Write((ushort)payload.Length);
- payload.CopyTo(_buffer, _position);
- Commit(payload.Length);
- }
-
- private void Commit(int count)
- {
- if (_position == Length)
- {
- Length += count;
- }
-
- _position += count;
- }
-
- private void GrowIfNeeded(int requiredAdditional)
- {
- var requiredTotal = _position + requiredAdditional;
- if (_buffer.Length >= requiredTotal)
- {
- return;
- }
-
- var newBufferLength = _buffer.Length;
- while (newBufferLength < requiredTotal)
- {
- newBufferLength *= 2;
- }
-
- var newBuffer = _pool.Rent(newBufferLength);
- Array.Copy(_buffer, newBuffer, _buffer.Length);
- _pool.Return(_buffer);
- _buffer = newBuffer;
- }
- }
- }
|