Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

138 linhas
4.3 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 byte[] _chunckBuffer = new byte[MqttWebSocketChannel.BufferSize];
  14. private readonly Queue<byte> _buffer = new Queue<byte>(MqttWebSocketChannel.BufferSize);
  15. private readonly WebSocket _webSocket;
  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. offset++;
  50. }
  51. if (count == 0)
  52. {
  53. return bytesRead;
  54. }
  55. // Fetch new data if the buffer is not full.
  56. while (_webSocket.State == WebSocketState.Open)
  57. {
  58. await FetchChunkAsync(cancellationToken).ConfigureAwait(false);
  59. while (count > 0 && _buffer.Any())
  60. {
  61. buffer[offset] = _buffer.Dequeue();
  62. count--;
  63. bytesRead++;
  64. offset++;
  65. }
  66. if (count == 0)
  67. {
  68. return bytesRead;
  69. }
  70. }
  71. if (_webSocket.State == WebSocketState.Closed)
  72. {
  73. throw new MqttCommunicationException("WebSocket connection closed.");
  74. }
  75. return bytesRead;
  76. }
  77. public override void Write(byte[] buffer, int offset, int count)
  78. {
  79. WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
  80. }
  81. public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  82. {
  83. return _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken);
  84. }
  85. public override long Seek(long offset, SeekOrigin origin)
  86. {
  87. throw new NotSupportedException();
  88. }
  89. public override void SetLength(long value)
  90. {
  91. throw new NotSupportedException();
  92. }
  93. private async Task FetchChunkAsync(CancellationToken cancellationToken)
  94. {
  95. var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(_chunckBuffer, 0, _chunckBuffer.Length), cancellationToken).ConfigureAwait(false);
  96. if (response.MessageType == WebSocketMessageType.Close)
  97. {
  98. await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken).ConfigureAwait(false);
  99. }
  100. else if (response.MessageType == WebSocketMessageType.Binary)
  101. {
  102. for (var i = 0; i < response.Count; i++)
  103. {
  104. _buffer.Enqueue(_chunckBuffer[i]);
  105. }
  106. }
  107. else if (response.MessageType == WebSocketMessageType.Text)
  108. {
  109. throw new MqttProtocolViolationException("WebSocket channel received TEXT message.");
  110. }
  111. }
  112. }
  113. }