using Birdmap.BLL.Interfaces; using Birdmap.BLL.Services.CommunationServices; using Birdmap.BLL.Services.CommunicationServices.Hubs; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Client; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Options; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Birdmap.BLL.Services.CommunicationServices.Mqtt { internal class MqttClientService : CommunicationServiceBase, IMqttClientService { private readonly IMqttClient _mqttClient; private readonly IMqttClientOptions _options; public override bool IsConnected => _mqttClient.IsConnected; public MqttClientService(IMqttClientOptions options, ILogger logger, IInputService inputService, IHubContext hubContext) : base(logger, inputService, hubContext) { _options = options; _mqttClient = new MqttFactory().CreateMqttClient(); ConfigureMqttClient(); } private void ConfigureMqttClient() { _mqttClient.ConnectedHandler = this; _mqttClient.DisconnectedHandler = this; _mqttClient.ApplicationMessageReceivedHandler = this; } public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs) { var message = eventArgs.ApplicationMessage.ConvertPayloadToString(); _logger.LogDebug($"Recieved [{eventArgs.ClientId}] " + $"Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {message} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel} | Retain: {eventArgs.ApplicationMessage.Retain}"); return ProcessJsonMessageAsync(message); } public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs) { try { var topic = _options.UserProperties.SingleOrDefault(up => up.Name == "Topic")?.Value; _logger.LogInformation($"Connected. Auth result: {eventArgs.AuthenticateResult}. Subscribing to topic: {topic}"); await _mqttClient.SubscribeAsync(topic); StartMessageTimer(); } catch (Exception ex) { _logger.LogError(ex, $"Cannot subscribe..."); } } public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs) { _logger.LogDebug(eventArgs.Exception, $"Disconnected. Reason {eventArgs.ReasonCode}. Auth result: {eventArgs.AuthenticateResult}. Reconnecting..."); await Task.Delay(TimeSpan.FromSeconds(5)); try { StopMessageTimer(); await _mqttClient.ConnectAsync(_options, CancellationToken.None); } catch (Exception ex) { _logger.LogDebug(ex, $"Reconnect failed..."); } } public async Task StartAsync(CancellationToken cancellationToken) { try { await _mqttClient.ConnectAsync(_options); if (!_mqttClient.IsConnected) { await _mqttClient.ReconnectAsync(); } } catch (Exception ex) { _logger.LogError(ex, $"Cannot connect..."); } } public async Task StopAsync(CancellationToken cancellationToken) { try { if (cancellationToken.IsCancellationRequested) { var disconnectOption = new MqttClientDisconnectOptions { ReasonCode = MqttClientDisconnectReason.NormalDisconnection, ReasonString = "NormalDiconnection" }; await _mqttClient.DisconnectAsync(disconnectOption, cancellationToken); } await _mqttClient.DisconnectAsync(); } catch (Exception ex) { _logger.LogError(ex, $"Cannot disconnect..."); } } } }