Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

136 řádky
4.5 KiB

  1. using System;
  2. using System.Net.WebSockets;
  3. using System.Security.Cryptography.X509Certificates;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MQTTnet.Channel;
  7. using MQTTnet.Client;
  8. namespace MQTTnet.Implementations
  9. {
  10. public sealed class MqttWebSocketChannel : IMqttChannel
  11. {
  12. private readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
  13. private readonly MqttClientWebSocketOptions _options;
  14. private WebSocket _webSocket;
  15. public MqttWebSocketChannel(MqttClientWebSocketOptions options)
  16. {
  17. _options = options ?? throw new ArgumentNullException(nameof(options));
  18. }
  19. public MqttWebSocketChannel(WebSocket webSocket, string endpoint)
  20. {
  21. _webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
  22. Endpoint = endpoint;
  23. }
  24. public string Endpoint { get; }
  25. public async Task ConnectAsync(CancellationToken cancellationToken)
  26. {
  27. var uri = _options.Uri;
  28. if (!uri.StartsWith("ws://", StringComparison.OrdinalIgnoreCase) && !uri.StartsWith("wss://", StringComparison.OrdinalIgnoreCase))
  29. {
  30. if (_options.TlsOptions?.UseTls == false)
  31. {
  32. uri = "ws://" + uri;
  33. }
  34. else
  35. {
  36. uri = "wss://" + uri;
  37. }
  38. }
  39. var clientWebSocket = new ClientWebSocket();
  40. if (_options.RequestHeaders != null)
  41. {
  42. foreach (var requestHeader in _options.RequestHeaders)
  43. {
  44. clientWebSocket.Options.SetRequestHeader(requestHeader.Key, requestHeader.Value);
  45. }
  46. }
  47. if (_options.SubProtocols != null)
  48. {
  49. foreach (var subProtocol in _options.SubProtocols)
  50. {
  51. clientWebSocket.Options.AddSubProtocol(subProtocol);
  52. }
  53. }
  54. if (_options.CookieContainer != null)
  55. {
  56. clientWebSocket.Options.Cookies = _options.CookieContainer;
  57. }
  58. if (_options.TlsOptions?.UseTls == true && _options.TlsOptions?.Certificates != null)
  59. {
  60. clientWebSocket.Options.ClientCertificates = new X509CertificateCollection();
  61. foreach (var certificate in _options.TlsOptions.Certificates)
  62. {
  63. clientWebSocket.Options.ClientCertificates.Add(new X509Certificate(certificate));
  64. }
  65. }
  66. await clientWebSocket.ConnectAsync(new Uri(uri), cancellationToken).ConfigureAwait(false);
  67. _webSocket = clientWebSocket;
  68. }
  69. public async Task DisconnectAsync()
  70. {
  71. if (_webSocket == null)
  72. {
  73. return;
  74. }
  75. if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.Connecting)
  76. {
  77. await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false);
  78. }
  79. Dispose();
  80. }
  81. public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  82. {
  83. var response = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken).ConfigureAwait(false);
  84. return response.Count;
  85. }
  86. public async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  87. {
  88. // This lock is required because the client will throw an exception if _SendAsync_ is
  89. // called from multiple threads at the same time. But this issue only happens with several
  90. // framework versions.
  91. await _sendLock.WaitAsync(cancellationToken).ConfigureAwait(false);
  92. try
  93. {
  94. await _webSocket.SendAsync(new ArraySegment<byte>(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken).ConfigureAwait(false);
  95. }
  96. finally
  97. {
  98. _sendLock.Release();
  99. }
  100. }
  101. public void Dispose()
  102. {
  103. _sendLock?.Dispose();
  104. try
  105. {
  106. _webSocket?.Dispose();
  107. }
  108. catch (ObjectDisposedException)
  109. {
  110. }
  111. finally
  112. {
  113. _webSocket = null;
  114. }
  115. }
  116. }
  117. }