public async Task <Dictionary <string, Qos> > SubscribeAsync(Dictionary <string, Qos> subscriptions, CancellationToken cancellationToken) { var builder = new MqttClientSubscribeOptionsBuilder(); foreach (var entry in subscriptions) { builder.WithTopicFilter(entry.Key, MapQos(entry.Value)); } try { var subscribeResult = await client.SubscribeAsync(builder.Build(), cancellationToken); var gainedQoses = new Dictionary <string, Qos>(); foreach (var item in subscribeResult.Items) { var gained = (int)item.ResultCode; if (gained < 0 || gained > 2) { throw new MqttException(message: $"Subscribe [topiic={item.TopicFilter.Topic}, qos={item.TopicFilter.QualityOfServiceLevel} failed: [resultCode={item.ResultCode}]."); } gainedQoses[item.TopicFilter.Topic] = (Qos)gained; } return(gainedQoses); } catch (Exception e) { throw new MqttException(cause: e); } }
public MQTTClient() { var mqttClient = new MqttFactory().CreateMqttClient(); var optionBuilder = new MqttClientOptionsBuilder(); optionBuilder .WithClientId("c001") .WithTcpServer(opts => { opts.Server = "127.0.0.1"; opts.Port = 108; }) .WithCredentials("u001", "p001") .WithCleanSession(true); var options = optionBuilder.Build(); mqttClient.ConnectAsync(options, CancellationToken.None).Wait(); var recieveHander = new MsgRecieveHandler(); mqttClient.ApplicationMessageReceivedHandler = recieveHander; var topicBuilder = new TopicFilterBuilder(); topicBuilder.WithTopic("家/客厅/空调/#") .WithAtMostOnceQoS(); var topicHome = topicBuilder.Build(); var subscribOptionBuilder = new MqttClientSubscribeOptionsBuilder(); subscribOptionBuilder.WithTopicFilter(topicHome); var subOpt = subscribOptionBuilder.Build(); mqttClient.SubscribeAsync(subOpt, CancellationToken.None).Wait(); var appMsg = new MqttApplicationMessage(); appMsg.Topic = "家/客厅/空调/开关"; appMsg.Payload = Encoding.UTF8.GetBytes("我来了~"); appMsg.QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce; appMsg.Retain = false; mqttClient.PublishAsync(appMsg, CancellationToken.None).Wait(); //var appMsg = new MqttApplicationMessage("家/客厅/空调/开关", // Encoding.UTF8.GetBytes("消息内容"), // MqttQualityOfServiceLevel.AtMostOnce, false); }
public RemoteMqttBroker( ILogger <RemoteMqttBroker> logger, IEventIdCreationSource eventIdCreationSource, IOptions <MqttNetworkOptions>?options = null) { _logger = logger; _eventIdCreationSource = eventIdCreationSource; EventId eventId = GetNextEventId(); _logger.LogInformation(eventId, $"Creating Mqtt Client (Id: {ClientId})."); MqttNetworkOptions mqttNetworkOptions = options?.Value ?? MqttNetworkOptions.Default; mqttNetworkOptions.Host ??= MqttNetworkOptions.Default.Host !; if (mqttNetworkOptions.Port < 0x0000) { throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Port), mqttNetworkOptions.Port, "Port number too small."); } else if (mqttNetworkOptions.Port > 0xffff) { throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Port), mqttNetworkOptions.Port, "Port number too large."); } if (mqttNetworkOptions.Timeout < 1) { throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Timeout), mqttNetworkOptions.Timeout, "Timeout timespan too small."); } else if (mqttNetworkOptions.Timeout > 99999) { throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Timeout), mqttNetworkOptions.Timeout, "Timeout timespan too large."); } _logger.LogInformation(eventId, $"MQTT Client Communication Timeout: {mqttNetworkOptions.Timeout} ms."); var clientOptionsBuilder = new MqttClientOptionsBuilder() .WithClientId(ClientId) .WithCommunicationTimeout(TimeSpan.FromSeconds(60)) .WithTcpServer(mqttNetworkOptions.Host, mqttNetworkOptions.Port); _mqttClient = new MqttFactory().CreateMqttClient(); _mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate(eventArgs => { _logger.LogDebug("Client Connected. Reason: " + (eventArgs.AuthenticateResult?.ReasonString ?? "null")); }); _mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(eventArgs => { _logger.LogDebug(eventArgs.Exception, "Client Disconnected. Reason: " + (eventArgs.AuthenticateResult?.ReasonString ?? "null")); }); CancellationTokenSource?cancellationTokenSource = null; #region Connecting to remote Mqtt Broker try { _logger.LogInformation(eventId, $"Connecting to remote Mqtt-Broker (mqtt://{mqttNetworkOptions.Host}:{mqttNetworkOptions.Port})."); cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan); var result = _mqttClient.ConnectAsync(clientOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult(); if (result.ResultCode != MqttClientConnectResultCode.Success) { throw new Exception("Mqtt-Client ConnectResultCode Success expected. Actual: " + result.ResultCode); } } catch (OperationCanceledException) { string errorMessage = "Connect to remote Mqtt-Broker timed out."; _logger.LogCritical(eventId, errorMessage); throw new Exception(errorMessage); } catch (Exception exception) { string errorMessage = "Failed to connect to remote Mqtt-Broker."; _logger.LogCritical(eventId, exception, errorMessage); throw new Exception(errorMessage); } finally { cancellationTokenSource?.Dispose(); } #endregion #region Subscribing to relevant Events try { _logger.LogInformation(eventId, $"Subscribing to relevant events."); MqttQualityOfServiceLevel mqttQualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce; MqttClientSubscribeResultCode expectedSubscribeResultCode = MqttClientSubscribeResultCode.GrantedQoS1; MqttClientSubscribeOptionsBuilder subscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder() .WithTopicFilter(MqttTopics.TrackerHello, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.TrackerGoodbye, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.ClientJoinAccepted, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.ClientJoinDenied, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.ClientRegistered, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.ClientGoodbye, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.FileInfoPublished, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.FragmentDistributionStarted, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.FragmentDistributionDelivered, mqttQualityOfServiceLevel) .WithTopicFilter(MqttTopics.FragmentDistributionEnded, mqttQualityOfServiceLevel); cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan); //timeout MqttClientSubscribeResult result = _mqttClient.SubscribeAsync(subscribeOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult(); foreach (MqttClientSubscribeResultItem item in result.Items) { if (item.ResultCode != expectedSubscribeResultCode) { throw new Exception($"Expected SubscribeResultCode {expectedSubscribeResultCode} for topic \"{item.TopicFilter.Topic}\". Actual: {item.ResultCode}"); } } } catch (Exception exception) { string errorMessage; if (exception is OperationCanceledException) { errorMessage = "Subscribing to all relevant Events to remote Mqtt-Broker timed out."; _logger.LogCritical(eventId, errorMessage); } else { errorMessage = "Failed to subscribe to all relevant topics with expected SubscribeResultCode."; _logger.LogCritical(eventId, exception, errorMessage); } try { _logger.LogInformation("Disconnecting from remote Mqtt-Broker"); MqttClientDisconnectOptions disconnectOptions = new MqttClientDisconnectOptions() { ReasonCode = MqttClientDisconnectReason.NormalDisconnection, ReasonString = errorMessage }; cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan); _mqttClient.DisconnectAsync(disconnectOptions, cancellationTokenSource.Token).GetAwaiter().GetResult(); } catch (OperationCanceledException) { _logger.LogError(eventId, "Disconnecting from remote Mqtt-Broker timed out."); } catch (Exception disconnectException) { _logger.LogError(eventId, disconnectException, "Disconnecting from remote Mqtt-Broker failed."); } finally { cancellationTokenSource?.Dispose(); } throw new Exception(errorMessage); } finally { cancellationTokenSource?.Dispose(); } #endregion }