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.
 
 
 
 

147 lines
3.6 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. private readonly ArrayPool<byte> _pool;
  11. public SpanBasedMqttPacketWriter()
  12. {
  13. _pool = ArrayPool<byte>.Create();
  14. }
  15. private byte[] _buffer;
  16. private 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. Commit(propertyWriter.Length);
  54. }
  55. public void Write(byte[] payload, int start, int length)
  56. {
  57. GrowIfNeeded(length);
  58. payload.AsSpan(start, length).CopyTo(_buffer.AsSpan(_position));
  59. Commit(length);
  60. }
  61. public void WriteVariableLengthInteger(uint value)
  62. {
  63. GrowIfNeeded(4);
  64. var x = value;
  65. do
  66. {
  67. var encodedByte = x % 128;
  68. x = x / 128;
  69. if (x > 0)
  70. {
  71. encodedByte = encodedByte | 128;
  72. }
  73. _buffer[_position] = (byte)encodedByte;
  74. Commit(1);
  75. } while (x > 0);
  76. }
  77. public void WriteWithLengthPrefix(string value)
  78. {
  79. var bytesLength = Encoding.UTF8.GetByteCount(value ?? string.Empty);
  80. GrowIfNeeded(bytesLength + 2);
  81. Write((ushort)bytesLength);
  82. Encoding.UTF8.GetBytes(value ?? string.Empty, 0, value?.Length ?? 0, _buffer, _position);
  83. Commit(bytesLength);
  84. }
  85. public void WriteWithLengthPrefix(byte[] payload)
  86. {
  87. GrowIfNeeded(payload.Length + 2);
  88. Write((ushort)payload.Length);
  89. payload.CopyTo(_buffer, _position);
  90. Commit(payload.Length);
  91. }
  92. private void Commit(int count)
  93. {
  94. if (_position == Length)
  95. {
  96. Length += count;
  97. }
  98. _position += count;
  99. }
  100. private void GrowIfNeeded(int requiredAdditional)
  101. {
  102. var requiredTotal = _position + requiredAdditional;
  103. if (_buffer.Length >= requiredTotal)
  104. {
  105. return;
  106. }
  107. var newBufferLength = _buffer.Length;
  108. while (newBufferLength < requiredTotal)
  109. {
  110. newBufferLength *= 2;
  111. }
  112. var newBuffer = _pool.Rent(newBufferLength);
  113. Array.Copy(_buffer, newBuffer, _buffer.Length);
  114. _pool.Return(_buffer);
  115. _buffer = newBuffer;
  116. }
  117. }
  118. }