Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

130 рядки
3.9 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net.WebSockets;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. using MQTTnet.Exceptions;
  9. namespace MQTTnet.Implementations
  10. {
  11. public class WebSocketStream : Stream
  12. {
  13. private readonly WebSocket _webSocket;
  14. private readonly byte[] _chunkBuffer = new byte[MqttWebSocketChannel.BufferSize];
  15. private readonly Queue<byte> _buffer = new Queue<byte>(MqttWebSocketChannel.BufferSize);
  16. public WebSocketStream(WebSocket webSocket)
  17. {
  18. _webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
  19. }
  20. public override bool CanRead => true;
  21. public override bool CanSeek => false;
  22. public override bool CanWrite => true;
  23. public override long Length => throw new NotSupportedException();
  24. public override long Position
  25. {
  26. get => throw new NotSupportedException();
  27. set => throw new NotSupportedException();
  28. }
  29. public override void Flush()
  30. {
  31. }
  32. public override Task FlushAsync(CancellationToken cancellationToken)
  33. {
  34. return Task.FromResult(0);
  35. }
  36. public override int Read(byte[] buffer, int offset, int count)
  37. {
  38. return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
  39. }
  40. public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  41. {
  42. var bytesRead = 0;
  43. // Use existing date from buffer.
  44. while (count > 0 && _buffer.Any())
  45. {
  46. buffer[offset++] = _buffer.Dequeue();
  47. count--;
  48. bytesRead++;
  49. }
  50. if (count == 0)
  51. {
  52. return bytesRead;
  53. }
  54. while (_webSocket.State == WebSocketState.Open)
  55. {
  56. await FetchChunkAsync(cancellationToken);
  57. while (count > 0 && _buffer.Any())
  58. {
  59. buffer[offset++] = _buffer.Dequeue();
  60. count--;
  61. bytesRead++;
  62. }
  63. if (count == 0)
  64. {
  65. return bytesRead;
  66. }
  67. }
  68. if (_webSocket.State == WebSocketState.Closed)
  69. {
  70. throw new MqttCommunicationException("WebSocket connection closed.");
  71. }
  72. return bytesRead;
  73. }
  74. public override void Write(byte[] buffer, int offset, int count)
  75. {
  76. WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
  77. }
  78. public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  79. {
  80. return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
  81. }
  82. public override long Seek(long offset, SeekOrigin origin)
  83. {
  84. throw new NotSupportedException();
  85. }
  86. public override void SetLength(long value)
  87. {
  88. throw new NotSupportedException();
  89. }
  90. private async Task FetchChunkAsync(CancellationToken cancellationToken)
  91. {
  92. var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(_chunkBuffer, 0, _chunkBuffer.Length), cancellationToken).ConfigureAwait(false);
  93. for (var i = 0; i < response.Count; i++)
  94. {
  95. var @byte = _chunkBuffer[i];
  96. _buffer.Enqueue(@byte);
  97. }
  98. if (response.MessageType == WebSocketMessageType.Close)
  99. {
  100. await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
  101. }
  102. }
  103. }
  104. }