mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
146 lines
3.6 KiB
C#
146 lines
3.6 KiB
C#
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|