You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

145 lines
3.5 KiB

  1. using MQTTnet.Formatter;
  2. using System;
  3. using System.Buffers;
  4. using System.Buffers.Binary;
  5. using System.Text;
  6. namespace MQTTnet.AspNetCore
  7. {
  8. public class SpanBasedMqttPacketWriter : IMqttPacketWriter
  9. {
  10. readonly ArrayPool<byte> _pool = ArrayPool<byte>.Create();
  11. public SpanBasedMqttPacketWriter()
  12. {
  13. Reset(0);
  14. }
  15. byte[] _buffer;
  16. int _position;
  17. public int Length { get; set; }
  18. public void FreeBuffer()
  19. {
  20. _pool.Return(_buffer);
  21. }
  22. public byte[] GetBuffer()
  23. {
  24. return _buffer;
  25. }
  26. public void Reset(int v)
  27. {
  28. _buffer = _pool.Rent(1500);
  29. Length = v;
  30. _position = v;
  31. }
  32. public void Seek(int v)
  33. {
  34. _position = v;
  35. }
  36. public void Write(byte value)
  37. {
  38. GrowIfNeeded(1);
  39. _buffer[_position] = value;
  40. Commit(1);
  41. }
  42. public void Write(ushort value)
  43. {
  44. GrowIfNeeded(2);
  45. BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_position), value);
  46. Commit(2);
  47. }
  48. public void Write(IMqttPacketWriter propertyWriter)
  49. {
  50. if (propertyWriter == null) throw new ArgumentNullException(nameof(propertyWriter));
  51. GrowIfNeeded(propertyWriter.Length);
  52. Write(propertyWriter.GetBuffer(), 0, propertyWriter.Length);
  53. }
  54. public void Write(byte[] payload, int start, int length)
  55. {
  56. GrowIfNeeded(length);
  57. payload.AsSpan(start, length).CopyTo(_buffer.AsSpan(_position));
  58. Commit(length);
  59. }
  60. public void WriteVariableLengthInteger(uint value)
  61. {
  62. GrowIfNeeded(4);
  63. var x = value;
  64. do
  65. {
  66. var encodedByte = x % 128;
  67. x = x / 128;
  68. if (x > 0)
  69. {
  70. encodedByte = encodedByte | 128;
  71. }
  72. _buffer[_position] = (byte)encodedByte;
  73. Commit(1);
  74. } while (x > 0);
  75. }
  76. public void WriteWithLengthPrefix(string value)
  77. {
  78. var bytesLength = Encoding.UTF8.GetByteCount(value ?? string.Empty);
  79. GrowIfNeeded(bytesLength + 2);
  80. Write((ushort)bytesLength);
  81. Encoding.UTF8.GetBytes(value ?? string.Empty, 0, value?.Length ?? 0, _buffer, _position);
  82. Commit(bytesLength);
  83. }
  84. public void WriteWithLengthPrefix(byte[] payload)
  85. {
  86. GrowIfNeeded(payload.Length + 2);
  87. Write((ushort)payload.Length);
  88. payload.CopyTo(_buffer, _position);
  89. Commit(payload.Length);
  90. }
  91. void Commit(int count)
  92. {
  93. if (_position == Length)
  94. {
  95. Length += count;
  96. }
  97. _position += count;
  98. }
  99. void GrowIfNeeded(int requiredAdditional)
  100. {
  101. var requiredTotal = _position + requiredAdditional;
  102. if (_buffer.Length >= requiredTotal)
  103. {
  104. return;
  105. }
  106. var newBufferLength = _buffer.Length;
  107. while (newBufferLength < requiredTotal)
  108. {
  109. newBufferLength *= 2;
  110. }
  111. var newBuffer = _pool.Rent(newBufferLength);
  112. Array.Copy(_buffer, newBuffer, _buffer.Length);
  113. _pool.Return(_buffer);
  114. _buffer = newBuffer;
  115. }
  116. }
  117. }