public Task ConnectAsync(TimeSpan timeout) { ThrowIfDisposed(); _logger.Trace <MqttChannelAdapter>("Connecting [Timeout={0}]", timeout); return(ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout))); }
public async Task SendPacketsAsync(TimeSpan timeout, CancellationToken cancellationToken, IEnumerable <MqttBasePacket> packets) { await ExecuteAndWrapExceptionAsync(async() => { await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { foreach (var packet in packets) { if (packet == null) { continue; } _logger.Trace <MqttChannelAdapter>("TX >>> {0} [Timeout={1}]", packet, timeout); var writeBuffer = PacketSerializer.Serialize(packet); await _channel.SendStream.WriteAsync(writeBuffer, 0, writeBuffer.Length, cancellationToken).ConfigureAwait(false); } if (timeout > TimeSpan.Zero) { await _channel.SendStream.FlushAsync(cancellationToken).TimeoutAfter(timeout).ConfigureAwait(false); } else { await _channel.SendStream.FlushAsync(cancellationToken).ConfigureAwait(false); } } finally { _semaphore.Release(); } }); }
public void Enqueue(MqttBasePacket packet) { if (packet == null) { throw new ArgumentNullException(nameof(packet)); } _queue.Add(packet); _logger.Trace <MqttClientPendingMessagesQueue>("Enqueued packet (ClientId: {0}).", _session.ClientId); }
private async Task <GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) { await _semaphore.WaitAsync().ConfigureAwait(false); try { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); if (isSessionPresent) { if (connectPacket.CleanSession) { _sessions.Remove(connectPacket.ClientId); await clientSession.StopAsync().ConfigureAwait(false); clientSession.Dispose(); clientSession = null; _logger.Trace <MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Trace <MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } var isExistingSession = true; if (clientSession == null) { isExistingSession = false; clientSession = new MqttClientSession(connectPacket.ClientId, _options, _retainedMessagesManager, _logger) { ApplicationMessageReceivedCallback = DispatchApplicationMessageAsync }; clientSession.SubscriptionsManager.TopicSubscribedCallback = ClientSubscribedTopicCallback; clientSession.SubscriptionsManager.TopicUnsubscribedCallback = ClientUnsubscribedTopicCallback; _sessions[connectPacket.ClientId] = clientSession; _logger.Trace <MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId); } return(new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }); } finally { _semaphore.Release(); } }
public async Task <MqttClientConnectResult> ConnectAsync(IMqttClientOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (options.ChannelOptions == null) { throw new ArgumentException("ChannelOptions are not set."); } ThrowIfConnected("It is not allowed to connect with a server after the connection is established."); try { _options = options; _cancellationTokenSource = new CancellationTokenSource(); _packetIdentifierProvider.Reset(); _packetDispatcher.Reset(); _adapter = _adapterFactory.CreateClientAdapter(options.ChannelOptions, _logger); _logger.Trace <MqttClient>("Trying to connect with server."); await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false); _logger.Trace <MqttClient>("Connection with server established."); await StartReceivingPacketsAsync().ConfigureAwait(false); var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false); _logger.Trace <MqttClient>("MQTT connection with server established."); _sendTracker.Restart(); if (_options.KeepAlivePeriod != TimeSpan.Zero) { StartSendingKeepAliveMessages(); } IsConnected = true; Connected?.Invoke(this, new MqttClientConnectedEventArgs(connectResponse.IsSessionPresent)); return(new MqttClientConnectResult(connectResponse.IsSessionPresent)); } catch (Exception exception) { _logger.Error <MqttClient>(exception, "Error while connecting with server."); await DisconnectInternalAsync(exception).ConfigureAwait(false); throw; } }
private async Task CheckKeepAliveTimeoutAsync(TimeSpan keepAlivePeriod, CancellationToken cancellationToken) { try { while (!cancellationToken.IsCancellationRequested) { // Values described here: [MQTT-3.1.2-24]. if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod.TotalSeconds * 1.5D) { _logger.Warning <MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", ClientId); await StopAsync(); return; } await Task.Delay(keepAlivePeriod, cancellationToken); } } catch (OperationCanceledException) { } catch (Exception exception) { _logger.Error <MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", ClientId); } finally { _logger.Trace <MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", ClientId); } }
private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken) { try { while (!cancellationToken.IsCancellationRequested) { var message = _messageQueue.Take(cancellationToken); if (message == null) { continue; } if (cancellationToken.IsCancellationRequested) { continue; } await TryPublishQueuedMessageAsync(message).ConfigureAwait(false); } } catch (OperationCanceledException) { } catch (Exception exception) { _logger.Error <ManagedMqttClient>(exception, "Unhandled exception while publishing queued application messages."); } finally { _logger.Trace <ManagedMqttClient>("Stopped publishing messages."); } }
private async Task <GetOrCreateClientSessionResult> GetOrCreateClientSessionAsync(MqttConnectPacket connectPacket) { await _sessionsSemaphore.WaitAsync().ConfigureAwait(false); try { var isSessionPresent = _sessions.TryGetValue(connectPacket.ClientId, out var clientSession); if (isSessionPresent) { if (connectPacket.CleanSession) { _sessions.Remove(connectPacket.ClientId); await clientSession.StopAsync(); clientSession = null; _logger.Trace <MqttClientSessionsManager>("Stopped existing session of client '{0}'.", connectPacket.ClientId); } else { _logger.Trace <MqttClientSessionsManager>("Reusing existing session of client '{0}'.", connectPacket.ClientId); } } var isExistingSession = true; if (clientSession == null) { isExistingSession = false; clientSession = new MqttClientSession(connectPacket.ClientId, _options, this, _logger); _sessions[connectPacket.ClientId] = clientSession; _logger.Trace <MqttClientSessionsManager>("Created a new session for client '{0}'.", connectPacket.ClientId); } return(new GetOrCreateClientSessionResult { IsExistingSession = isExistingSession, Session = clientSession }); } finally { _sessionsSemaphore.Release(); } }
private async Task HandleMessageInternalAsync(string clientId, MqttApplicationMessage applicationMessage) { var saveIsRequired = false; if (applicationMessage.Payload?.Any() == false) { saveIsRequired = _retainedMessages.Remove(applicationMessage.Topic); _logger.Info <MqttRetainedMessagesManager>("Client '{0}' cleared retained message for topic '{1}'.", clientId, applicationMessage.Topic); } else { if (!_retainedMessages.ContainsKey(applicationMessage.Topic)) { _retainedMessages[applicationMessage.Topic] = applicationMessage; saveIsRequired = true; } else { var existingMessage = _retainedMessages[applicationMessage.Topic]; if (existingMessage.QualityOfServiceLevel != applicationMessage.QualityOfServiceLevel || !existingMessage.Payload.SequenceEqual(applicationMessage.Payload ?? new byte[0])) { _retainedMessages[applicationMessage.Topic] = applicationMessage; saveIsRequired = true; } } _logger.Info <MqttRetainedMessagesManager>("Client '{0}' set retained message for topic '{1}'.", clientId, applicationMessage.Topic); } if (!saveIsRequired) { _logger.Trace <MqttRetainedMessagesManager>("Skipped saving retained messages because no changes were detected."); } if (saveIsRequired && _options.Storage != null) { await _options.Storage.SaveRetainedMessagesAsync(_retainedMessages.Values.ToList()); } }
private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken) { try { _lastPacketReceivedTracker.Restart(); _lastNonKeepAlivePacketReceivedTracker.Restart(); while (!cancellationToken.IsCancellationRequested) { // Values described here: [MQTT-3.1.2-24]. if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D) { _logger.Warning <MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", _clientId); if (_timeoutCallback != null) { await _timeoutCallback().ConfigureAwait(false); } return; } await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) { } catch (Exception exception) { _logger.Error <MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId); } finally { _logger.Trace <MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", _clientId); } }