Compare commits
15 Commits
265a59d4c3
...
master
Author | SHA1 | Date | |
---|---|---|---|
324d2ac7f4 | |||
8a0212a139 | |||
802806b4c2 | |||
1d4bf2d0b6 | |||
79dcb4d75a | |||
7c67fa7de0 | |||
89a416ac38 | |||
e9ffe514dd | |||
6a579772df | |||
20a4b4d349 | |||
0085b95198 | |||
579481ce16 | |||
645f2bb44b | |||
c3bbbd3d13 | |||
0df5b350d9 |
45
.drone.yml
Normal file
45
.drone.yml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: code-analysis
|
||||||
|
image: aosapps/drone-sonar-plugin
|
||||||
|
settings:
|
||||||
|
sonar_host:
|
||||||
|
from_secret: SONAR_HOST
|
||||||
|
sonar_token:
|
||||||
|
from_secret: SONAR_CODE
|
||||||
|
|
||||||
|
- name: kaniko
|
||||||
|
image: banzaicloud/drone-kaniko
|
||||||
|
settings:
|
||||||
|
registry: registry.kmlabz.com
|
||||||
|
repo: birbnetes/${DRONE_REPO_NAME}
|
||||||
|
username:
|
||||||
|
from_secret: DOCKER_USERNAME
|
||||||
|
password:
|
||||||
|
from_secret: DOCKER_PASSWORD
|
||||||
|
tags:
|
||||||
|
- latest
|
||||||
|
- ${DRONE_BUILD_NUMBER}
|
||||||
|
|
||||||
|
- name: dockerhub
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: birbnetes/${DRONE_REPO_NAME}
|
||||||
|
username:
|
||||||
|
from_secret: DOCKERHUB_USER
|
||||||
|
password:
|
||||||
|
from_secret: DOCKERHUB_PASSWORD
|
||||||
|
tags:
|
||||||
|
- latest
|
||||||
|
- ${DRONE_BUILD_NUMBER}
|
||||||
|
|
||||||
|
- name: ms-teams
|
||||||
|
image: kuperiu/drone-teams
|
||||||
|
settings:
|
||||||
|
webhook:
|
||||||
|
from_secret: TEAMS_WEBHOOK
|
||||||
|
when:
|
||||||
|
status: [ failure ]
|
@ -2,7 +2,6 @@
|
|||||||
using Birdmap.API.DTOs;
|
using Birdmap.API.DTOs;
|
||||||
using Birdmap.BLL.Interfaces;
|
using Birdmap.BLL.Interfaces;
|
||||||
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
||||||
using Birdmap.BLL.Services.CommunicationServices.Mqtt;
|
|
||||||
using Birdmap.DAL.Entities;
|
using Birdmap.DAL.Entities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -25,16 +24,16 @@ namespace Birdmap.API.Controllers
|
|||||||
{
|
{
|
||||||
private readonly IServiceService _service;
|
private readonly IServiceService _service;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly IMqttClientService _mqttClientService;
|
private readonly ICommunicationService _communicationService;
|
||||||
private readonly IHubContext<ServicesHub, IServicesHubClient> _hubContext;
|
private readonly IHubContext<ServicesHub, IServicesHubClient> _hubContext;
|
||||||
private readonly ILogger<ServicesController> _logger;
|
private readonly ILogger<ServicesController> _logger;
|
||||||
|
|
||||||
public ServicesController(IServiceService service, IMapper mapper, MqttClientServiceProvider mqttClientProvider,
|
public ServicesController(IServiceService service, IMapper mapper, ICommunicationServiceProvider communicationServiceProvider,
|
||||||
IHubContext<ServicesHub, IServicesHubClient> hubContext, ILogger<ServicesController> logger)
|
IHubContext<ServicesHub, IServicesHubClient> hubContext, ILogger<ServicesController> logger)
|
||||||
{
|
{
|
||||||
_service = service;
|
_service = service;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
_mqttClientService = mqttClientProvider.MqttClientService;
|
_communicationService = communicationServiceProvider.Service;
|
||||||
_hubContext = hubContext;
|
_hubContext = hubContext;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@ -83,11 +82,11 @@ namespace Birdmap.API.Controllers
|
|||||||
Service = new()
|
Service = new()
|
||||||
{
|
{
|
||||||
Id = 0,
|
Id = 0,
|
||||||
Name = "Mqtt Client Service",
|
Name = "Message Queue Service",
|
||||||
Uri = "localhost",
|
Uri = "localhost",
|
||||||
},
|
},
|
||||||
Response = $"IsConnected: {_mqttClientService.IsConnected}",
|
Response = $"IsConnected: {_communicationService.IsConnected}",
|
||||||
StatusCode = _mqttClientService.IsConnected ? HttpStatusCode.OK : HttpStatusCode.ServiceUnavailable,
|
StatusCode = _communicationService.IsConnected ? HttpStatusCode.OK : HttpStatusCode.ServiceUnavailable,
|
||||||
});
|
});
|
||||||
|
|
||||||
return serviceInfos.ToList();
|
return serviceInfos.ToList();
|
||||||
|
@ -12,6 +12,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using NSwag.Generation.Processors.Security;
|
using NSwag.Generation.Processors.Security;
|
||||||
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Birdmap.API
|
namespace Birdmap.API
|
||||||
@ -71,7 +72,7 @@ namespace Birdmap.API
|
|||||||
{
|
{
|
||||||
opt.Title = "Birdmap";
|
opt.Title = "Birdmap";
|
||||||
opt.OperationProcessors.Add(new OperationSecurityScopeProcessor("Jwt Token"));
|
opt.OperationProcessors.Add(new OperationSecurityScopeProcessor("Jwt Token"));
|
||||||
opt.AddSecurity("Jwt Token", new string[] { },
|
opt.AddSecurity("Jwt Token", Array.Empty<string>(),
|
||||||
new NSwag.OpenApiSecurityScheme
|
new NSwag.OpenApiSecurityScheme
|
||||||
{
|
{
|
||||||
Type = NSwag.OpenApiSecuritySchemeType.ApiKey,
|
Type = NSwag.OpenApiSecuritySchemeType.ApiKey,
|
||||||
@ -95,11 +96,9 @@ namespace Birdmap.API
|
|||||||
app.UseOpenApi();
|
app.UseOpenApi();
|
||||||
app.UseSwaggerUi3();
|
app.UseSwaggerUi3();
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseSpaStaticFiles();
|
app.UseSpaStaticFiles();
|
||||||
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
"UseDummyServices": true,
|
"UseDummyServices": true,
|
||||||
"ServicesBaseUrl": "https://birb.k8s.kmlabz.com/",
|
"ServicesBaseUrl": "https://birb.k8s.kmlabz.com/",
|
||||||
|
"UseRabbitMq": false,
|
||||||
"Mqtt": {
|
"Mqtt": {
|
||||||
"BrokerHostSettings": {
|
"BrokerHostSettings": {
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
|
@ -24,12 +24,28 @@
|
|||||||
},
|
},
|
||||||
"UseDummyServices": false,
|
"UseDummyServices": false,
|
||||||
"ServicesBaseUrl": "https://birb.k8s.kmlabz.com/",
|
"ServicesBaseUrl": "https://birb.k8s.kmlabz.com/",
|
||||||
|
"UseRabbitMq": false,
|
||||||
"Mqtt": {
|
"Mqtt": {
|
||||||
"BrokerHostSettings": {
|
"BrokerHostSettings": {
|
||||||
|
"VirtualHost": "",
|
||||||
"Host": "",
|
"Host": "",
|
||||||
"Port": 1883
|
"Port": 1883
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"ExchangeSettings": {
|
||||||
|
"Name": "",
|
||||||
|
"Type": "",
|
||||||
|
"Durable": false,
|
||||||
|
"AutoDelete": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"QueueSettings": {
|
||||||
|
"Name": "",
|
||||||
|
"Durable": false,
|
||||||
|
"Exclusive": false,
|
||||||
|
"AutoDelete": false
|
||||||
|
},
|
||||||
|
|
||||||
"ClientSettings": {
|
"ClientSettings": {
|
||||||
"Id": "ASP.NET Core client",
|
"Id": "ASP.NET Core client",
|
||||||
"Username": "",
|
"Username": "",
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
<!--Skip non-critical Mqtt logs-->
|
<!--Skip non-critical Mqtt logs-->
|
||||||
<logger name="*.*Mqtt*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
|
<logger name="*.*Mqtt*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
|
||||||
|
<logger name="*.*RabbitMq*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
|
||||||
|
<logger name="*.*CommunicationServiceBase*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
|
||||||
|
|
||||||
<!--Skip non-critical Hub logs-->
|
<!--Skip non-critical Hub logs-->
|
||||||
<logger name="*.*Hubs*.*" minlevel="Trace" maxlevel="Warning" writeTo="hubsFile" final="true"/>
|
<logger name="*.*Hubs*.*" minlevel="Trace" maxlevel="Warning" writeTo="hubsFile" final="true"/>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
||||||
<PackageReference Include="MQTTnet" Version="3.0.13" />
|
<PackageReference Include="MQTTnet" Version="3.0.13" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
9
Birdmap.BLL/Interfaces/ICommunicationService.cs
Normal file
9
Birdmap.BLL/Interfaces/ICommunicationService.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
namespace Birdmap.BLL.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICommunicationService : IHostedService
|
||||||
|
{
|
||||||
|
public bool IsConnected { get; }
|
||||||
|
}
|
||||||
|
}
|
7
Birdmap.BLL/Interfaces/ICommunicationServiceProvider.cs
Normal file
7
Birdmap.BLL/Interfaces/ICommunicationServiceProvider.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Birdmap.BLL.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICommunicationServiceProvider
|
||||||
|
{
|
||||||
|
public ICommunicationService Service { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,11 +5,9 @@ using MQTTnet.Client.Receiving;
|
|||||||
|
|
||||||
namespace Birdmap.BLL.Interfaces
|
namespace Birdmap.BLL.Interfaces
|
||||||
{
|
{
|
||||||
public interface IMqttClientService : IHostedService,
|
public interface IMqttClientService : IMqttClientConnectedHandler,
|
||||||
IMqttClientConnectedHandler,
|
|
||||||
IMqttClientDisconnectedHandler,
|
IMqttClientDisconnectedHandler,
|
||||||
IMqttApplicationMessageReceivedHandler
|
IMqttApplicationMessageReceivedHandler
|
||||||
{
|
{
|
||||||
public bool IsConnected { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,16 @@ using System;
|
|||||||
|
|
||||||
namespace Birdmap.BLL.Options
|
namespace Birdmap.BLL.Options
|
||||||
{
|
{
|
||||||
public class AspCoreMqttClientOptions : MqttClientOptionsBuilder
|
public class MqttClientOptions : MqttClientOptionsBuilder
|
||||||
{
|
{
|
||||||
public IServiceProvider ServiceProvider { get; }
|
public IServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
public AspCoreMqttClientOptions(IServiceProvider serviceProvider)
|
public MqttClientOptions(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AspCoreMqttClientOptions WithTopic(string topic)
|
public MqttClientOptions WithTopic(string topic)
|
||||||
{
|
{
|
||||||
WithUserProperty("Topic", topic);
|
WithUserProperty("Topic", topic);
|
||||||
|
|
11
Birdmap.BLL/Options/RabbitMqClientOptions.cs
Normal file
11
Birdmap.BLL/Options/RabbitMqClientOptions.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Birdmap.BLL.Options
|
||||||
|
{
|
||||||
|
public record RabbitMqClientOptions(
|
||||||
|
string Hostname, int Port, string VirtualHost,
|
||||||
|
string Username, string Password,
|
||||||
|
string ExchangeName, string ExchangeType,
|
||||||
|
bool ExchangeDurable, bool ExchangeAutoDelete,
|
||||||
|
string QueueName,
|
||||||
|
bool QueueDurable, bool QueueAutoDelete, bool QueueExclusive,
|
||||||
|
string Topic);
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
using Birdmap.BLL.Interfaces;
|
||||||
|
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
namespace Birdmap.BLL.Services.CommunationServices
|
||||||
|
{
|
||||||
|
internal class Payload
|
||||||
|
{
|
||||||
|
[JsonProperty("tag")]
|
||||||
|
public Guid TagID { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("probability")]
|
||||||
|
public double Probability { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class CommunicationServiceBase : ICommunicationService
|
||||||
|
{
|
||||||
|
protected readonly ILogger _logger;
|
||||||
|
protected readonly IInputService _inputService;
|
||||||
|
protected readonly IHubContext<DevicesHub, IDevicesHubClient> _hubContext;
|
||||||
|
private readonly Timer _hubTimer;
|
||||||
|
private readonly List<Message> _messages = new();
|
||||||
|
private readonly object _messageLock = new();
|
||||||
|
|
||||||
|
public abstract bool IsConnected { get; }
|
||||||
|
|
||||||
|
public CommunicationServiceBase(ILogger logger, IInputService inputService, IHubContext<DevicesHub, IDevicesHubClient> hubContext)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_inputService = inputService;
|
||||||
|
_hubContext = hubContext;
|
||||||
|
_hubTimer = new Timer()
|
||||||
|
{
|
||||||
|
AutoReset = true,
|
||||||
|
Interval = 1000,
|
||||||
|
};
|
||||||
|
_hubTimer.Elapsed += SendMqttMessagesWithSignalR;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task ProcessJsonMessageAsync(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var payload = JsonConvert.DeserializeObject<Payload>(json);
|
||||||
|
var inputResponse = await _inputService.GetInputAsync(payload.TagID);
|
||||||
|
|
||||||
|
lock (_messageLock)
|
||||||
|
{
|
||||||
|
_messages.Add(new Message(inputResponse.Message.Device_id, inputResponse.Message.Date.UtcDateTime, payload.Probability));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Could not handle application message.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void StartMessageTimer()
|
||||||
|
{
|
||||||
|
_hubTimer.Start();
|
||||||
|
}
|
||||||
|
protected void StopMessageTimer()
|
||||||
|
{
|
||||||
|
_hubTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendMqttMessagesWithSignalR(object sender, System.Timers.ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
lock (_messageLock)
|
||||||
|
{
|
||||||
|
if (_messages.Any())
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Sending ({_messages.Count}) messages: {string.Join(" | ", _messages)}");
|
||||||
|
_hubContext.Clients.All.NotifyMessagesAsync(_messages);
|
||||||
|
_messages.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task StartAsync(CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
public abstract Task StopAsync(CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using Birdmap.BLL.Interfaces;
|
||||||
|
|
||||||
|
namespace Birdmap.BLL.Services.CommunicationServices
|
||||||
|
{
|
||||||
|
internal class CommunicationServiceProvider : ICommunicationServiceProvider
|
||||||
|
{
|
||||||
|
public ICommunicationService Service { get; }
|
||||||
|
|
||||||
|
public CommunicationServiceProvider(ICommunicationService service)
|
||||||
|
{
|
||||||
|
Service = service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Birdmap.BLL.Interfaces;
|
using Birdmap.BLL.Interfaces;
|
||||||
|
using Birdmap.BLL.Services.CommunationServices;
|
||||||
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -7,59 +8,29 @@ using MQTTnet.Client;
|
|||||||
using MQTTnet.Client.Connecting;
|
using MQTTnet.Client.Connecting;
|
||||||
using MQTTnet.Client.Disconnecting;
|
using MQTTnet.Client.Disconnecting;
|
||||||
using MQTTnet.Client.Options;
|
using MQTTnet.Client.Options;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Timer = System.Timers.Timer;
|
|
||||||
|
|
||||||
namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
||||||
{
|
{
|
||||||
public class MqttClientService : IMqttClientService
|
internal class MqttClientService : CommunicationServiceBase, IMqttClientService
|
||||||
{
|
{
|
||||||
private readonly IMqttClient _mqttClient;
|
private readonly IMqttClient _mqttClient;
|
||||||
private readonly IMqttClientOptions _options;
|
private readonly IMqttClientOptions _options;
|
||||||
private readonly ILogger<MqttClientService> _logger;
|
|
||||||
private readonly IInputService _inputService;
|
|
||||||
private readonly IHubContext<DevicesHub, IDevicesHubClient> _hubContext;
|
|
||||||
private readonly Timer _hubTimer;
|
|
||||||
private readonly List<Message> _messages = new();
|
|
||||||
private readonly object _messageLock = new();
|
|
||||||
|
|
||||||
public bool IsConnected => _mqttClient.IsConnected;
|
public override bool IsConnected => _mqttClient.IsConnected;
|
||||||
|
|
||||||
public MqttClientService(IMqttClientOptions options, ILogger<MqttClientService> logger, IInputService inputService, IHubContext<DevicesHub, IDevicesHubClient> hubContext)
|
public MqttClientService(IMqttClientOptions options, ILogger<MqttClientService> logger, IInputService inputService, IHubContext<DevicesHub, IDevicesHubClient> hubContext)
|
||||||
|
: base(logger, inputService, hubContext)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
_logger = logger;
|
|
||||||
_inputService = inputService;
|
|
||||||
_hubContext = hubContext;
|
|
||||||
_hubTimer = new Timer()
|
|
||||||
{
|
|
||||||
AutoReset = true,
|
|
||||||
Interval = 1000,
|
|
||||||
};
|
|
||||||
_hubTimer.Elapsed += SendMqttMessagesWithSignalR;
|
|
||||||
|
|
||||||
_mqttClient = new MqttFactory().CreateMqttClient();
|
_mqttClient = new MqttFactory().CreateMqttClient();
|
||||||
ConfigureMqttClient();
|
ConfigureMqttClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendMqttMessagesWithSignalR(object sender, System.Timers.ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
lock (_messageLock)
|
|
||||||
{
|
|
||||||
if (_messages.Any())
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Sending ({_messages.Count}) messages: {string.Join(" | ", _messages)}");
|
|
||||||
_hubContext.Clients.All.NotifyMessagesAsync(_messages);
|
|
||||||
_messages.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureMqttClient()
|
private void ConfigureMqttClient()
|
||||||
{
|
{
|
||||||
_mqttClient.ConnectedHandler = this;
|
_mqttClient.ConnectedHandler = this;
|
||||||
@ -67,36 +38,14 @@ namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|||||||
_mqttClient.ApplicationMessageReceivedHandler = this;
|
_mqttClient.ApplicationMessageReceivedHandler = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Payload
|
public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
||||||
{
|
|
||||||
[JsonProperty("tag")]
|
|
||||||
public Guid TagID { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("probability")]
|
|
||||||
public double Probability { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
|
|
||||||
{
|
{
|
||||||
var message = eventArgs.ApplicationMessage.ConvertPayloadToString();
|
var message = eventArgs.ApplicationMessage.ConvertPayloadToString();
|
||||||
|
|
||||||
_logger.LogDebug($"Recieved [{eventArgs.ClientId}] " +
|
_logger.LogDebug($"Recieved [{eventArgs.ClientId}] " +
|
||||||
$"Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {message} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel} | Retain: {eventArgs.ApplicationMessage.Retain}");
|
$"Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {message} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel} | Retain: {eventArgs.ApplicationMessage.Retain}");
|
||||||
|
|
||||||
try
|
return ProcessJsonMessageAsync(message);
|
||||||
{
|
|
||||||
var payload = JsonConvert.DeserializeObject<Payload>(message);
|
|
||||||
var inputResponse = await _inputService.GetInputAsync(payload.TagID);
|
|
||||||
|
|
||||||
lock (_messageLock)
|
|
||||||
{
|
|
||||||
_messages.Add(new Message(inputResponse.Message.Device_id, inputResponse.Message.Date.UtcDateTime, payload.Probability));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, $"Could not handle application message.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
|
public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
|
||||||
@ -107,7 +56,7 @@ namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|||||||
_logger.LogInformation($"Connected. Auth result: {eventArgs.AuthenticateResult}. Subscribing to topic: {topic}");
|
_logger.LogInformation($"Connected. Auth result: {eventArgs.AuthenticateResult}. Subscribing to topic: {topic}");
|
||||||
|
|
||||||
await _mqttClient.SubscribeAsync(topic);
|
await _mqttClient.SubscribeAsync(topic);
|
||||||
_hubTimer.Start();
|
StartMessageTimer();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -123,7 +72,7 @@ namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_hubTimer.Stop();
|
StopMessageTimer();
|
||||||
await _mqttClient.ConnectAsync(_options, CancellationToken.None);
|
await _mqttClient.ConnectAsync(_options, CancellationToken.None);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -132,7 +81,7 @@ namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -148,7 +97,7 @@ namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopAsync(CancellationToken cancellationToken)
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
using Birdmap.BLL.Interfaces;
|
|
||||||
|
|
||||||
namespace Birdmap.BLL.Services.CommunicationServices.Mqtt
|
|
||||||
{
|
|
||||||
public class MqttClientServiceProvider
|
|
||||||
{
|
|
||||||
public IMqttClientService MqttClientService { get; }
|
|
||||||
|
|
||||||
public MqttClientServiceProvider(IMqttClientService mqttClientService)
|
|
||||||
{
|
|
||||||
MqttClientService = mqttClientService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,114 @@
|
|||||||
|
using Birdmap.BLL.Interfaces;
|
||||||
|
using Birdmap.BLL.Options;
|
||||||
|
using Birdmap.BLL.Services.CommunicationServices.Hubs;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using RabbitMQ.Client.Events;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Birdmap.BLL.Services.CommunationServices.RabbitMq
|
||||||
|
{
|
||||||
|
internal class RabbitMqClientService : CommunicationServiceBase
|
||||||
|
{
|
||||||
|
private IConnection _connection;
|
||||||
|
private IModel _channel;
|
||||||
|
private readonly IConnectionFactory _factory;
|
||||||
|
private readonly RabbitMqClientOptions _options;
|
||||||
|
|
||||||
|
public override bool IsConnected => _connection.IsOpen;
|
||||||
|
|
||||||
|
public RabbitMqClientService(RabbitMqClientOptions options, ILogger<RabbitMqClientService> logger, IInputService inputService, IHubContext<DevicesHub, IDevicesHubClient> hubContext)
|
||||||
|
: base(logger, inputService, hubContext)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
_factory = new ConnectionFactory()
|
||||||
|
{
|
||||||
|
HostName = options.Hostname,
|
||||||
|
Port = options.Port,
|
||||||
|
UserName = options.Username,
|
||||||
|
Password = options.Password,
|
||||||
|
|
||||||
|
AutomaticRecoveryEnabled = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task OnRecieved(object sender, BasicDeliverEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
var props = eventArgs.BasicProperties;
|
||||||
|
var body = Encoding.UTF8.GetString(eventArgs.Body.ToArray());
|
||||||
|
|
||||||
|
_logger.LogDebug($"Recieved [{props.UserId}] " +
|
||||||
|
$"ConsumerTag: {eventArgs.ConsumerTag} | DeliveryTag: {eventArgs.DeliveryTag} | Payload: {body} | Priority: {props.Priority}");
|
||||||
|
|
||||||
|
return ProcessJsonMessageAsync(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Cannot connect. Reconnecting...");
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
await StartAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StopMessageTimer();
|
||||||
|
_channel?.Close();
|
||||||
|
_connection?.Close();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Cannot disconnect...");
|
||||||
|
return Task.FromException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Connect()
|
||||||
|
{
|
||||||
|
|
||||||
|
_connection = _factory.CreateConnection();
|
||||||
|
_channel = _connection.CreateModel();
|
||||||
|
|
||||||
|
_channel.ExchangeDeclare(
|
||||||
|
exchange: _options.ExchangeName,
|
||||||
|
type: _options.ExchangeType,
|
||||||
|
durable: _options.ExchangeDurable,
|
||||||
|
autoDelete: _options.ExchangeAutoDelete);
|
||||||
|
|
||||||
|
_channel.QueueDeclare(
|
||||||
|
queue: _options.QueueName,
|
||||||
|
durable: _options.QueueDurable,
|
||||||
|
exclusive: _options.QueueExclusive,
|
||||||
|
autoDelete: _options.QueueAutoDelete);
|
||||||
|
|
||||||
|
_channel.QueueBind(queue: _options.QueueName,
|
||||||
|
exchange: _options.ExchangeName,
|
||||||
|
routingKey: _options.Topic);
|
||||||
|
|
||||||
|
var consumer = new AsyncEventingBasicConsumer(_channel);
|
||||||
|
consumer.Received += OnRecieved;
|
||||||
|
|
||||||
|
_channel.BasicConsume(queue: _options.QueueName,
|
||||||
|
autoAck: true,
|
||||||
|
consumer: consumer);
|
||||||
|
|
||||||
|
StartMessageTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using Birdmap.BLL.Interfaces;
|
using Birdmap.BLL.Interfaces;
|
||||||
using Birdmap.BLL.Options;
|
using Birdmap.BLL.Options;
|
||||||
using Birdmap.BLL.Services;
|
using Birdmap.BLL.Services;
|
||||||
|
using Birdmap.BLL.Services.CommunationServices.RabbitMq;
|
||||||
|
using Birdmap.BLL.Services.CommunicationServices;
|
||||||
using Birdmap.BLL.Services.CommunicationServices.Mqtt;
|
using Birdmap.BLL.Services.CommunicationServices.Mqtt;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -43,54 +45,109 @@ namespace Birdmap.BLL
|
|||||||
|
|
||||||
services.AddSignalR();
|
services.AddSignalR();
|
||||||
|
|
||||||
services.AddMqttClientServiceWithConfig(opt =>
|
var mqtt = configuration.GetSection("Mqtt");
|
||||||
|
|
||||||
|
var client = mqtt.GetSection("ClientSettings");
|
||||||
|
var clientSettings = new
|
||||||
{
|
{
|
||||||
var mqtt = configuration.GetSection("Mqtt");
|
Id = client.GetValue<string>("Id"),
|
||||||
|
Username = client.GetValue<string>("Username"),
|
||||||
|
Password = client.GetValue<string>("Password"),
|
||||||
|
Topic = client.GetValue<string>("Topic"),
|
||||||
|
};
|
||||||
|
|
||||||
var mqttClient = mqtt.GetSection("ClientSettings");
|
var brokerHost = mqtt.GetSection("BrokerHostSettings");
|
||||||
var clientSettings = new
|
var brokerHostSettings = new
|
||||||
|
{
|
||||||
|
Host = brokerHost.GetValue<string>("Host"),
|
||||||
|
Port = brokerHost.GetValue<int>("Port"),
|
||||||
|
VirtualHost = brokerHost.GetValue<string>("VirtualHost"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var exchange = mqtt.GetSection("ExchangeSettings");
|
||||||
|
var exchangeSettings = new
|
||||||
|
{
|
||||||
|
Name = exchange.GetValue<string>("Name"),
|
||||||
|
Type = exchange.GetValue<string>("Type"),
|
||||||
|
Durable = exchange.GetValue<bool>("Durable"),
|
||||||
|
AutoDelete = exchange.GetValue<bool>("AutoDelete"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var queue = mqtt.GetSection("QueueSettings");
|
||||||
|
var queueSettings = new
|
||||||
|
{
|
||||||
|
Name = queue.GetValue<string>("Name"),
|
||||||
|
Durable = exchange.GetValue<bool>("Durable"),
|
||||||
|
Exclusive = exchange.GetValue<bool>("Exclusive"),
|
||||||
|
AutoDelete = exchange.GetValue<bool>("AutoDelete"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("UseRabbitMq"))
|
||||||
|
{
|
||||||
|
services.AddRabbitMqClientServiceWithConfig(new RabbitMqClientOptions(
|
||||||
|
Hostname: brokerHostSettings.Host,
|
||||||
|
Port: brokerHostSettings.Port,
|
||||||
|
VirtualHost: brokerHostSettings.VirtualHost,
|
||||||
|
Username: clientSettings.Username,
|
||||||
|
Password: clientSettings.Password,
|
||||||
|
ExchangeName: exchangeSettings.Name,
|
||||||
|
ExchangeType: exchangeSettings.Type,
|
||||||
|
ExchangeDurable: exchangeSettings.Durable,
|
||||||
|
ExchangeAutoDelete: exchangeSettings.AutoDelete,
|
||||||
|
QueueName: queueSettings.Name,
|
||||||
|
QueueDurable: queueSettings.Durable,
|
||||||
|
QueueExclusive: queueSettings.Exclusive,
|
||||||
|
QueueAutoDelete: queueSettings.AutoDelete,
|
||||||
|
Topic: clientSettings.Topic));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddMqttClientServiceWithConfig(opt =>
|
||||||
{
|
{
|
||||||
Id = mqttClient.GetValue<string>("Id"),
|
opt
|
||||||
Username = mqttClient.GetValue<string>("Username"),
|
.WithTopic(clientSettings.Topic)
|
||||||
Password = mqttClient.GetValue<string>("Password"),
|
.WithCredentials(clientSettings.Username, clientSettings.Password)
|
||||||
Topic = mqttClient.GetValue<string>("Topic"),
|
.WithClientId(clientSettings.Id)
|
||||||
};
|
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
|
||||||
|
});
|
||||||
var mqttBrokerHost = mqtt.GetSection("BrokerHostSettings");
|
}
|
||||||
var brokerHostSettings = new
|
|
||||||
{
|
|
||||||
Host = mqttBrokerHost.GetValue<string>("Host"),
|
|
||||||
Port = mqttBrokerHost.GetValue<int>("Port"),
|
|
||||||
};
|
|
||||||
|
|
||||||
opt
|
|
||||||
.WithTopic(clientSettings.Topic)
|
|
||||||
.WithCredentials(clientSettings.Username, clientSettings.Password)
|
|
||||||
.WithClientId(clientSettings.Id)
|
|
||||||
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
|
|
||||||
});
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<AspCoreMqttClientOptions> configureOptions)
|
private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<MqttClientOptions> configureOptions)
|
||||||
{
|
{
|
||||||
services.AddSingleton(serviceProvider =>
|
services.AddSingleton(serviceProvider =>
|
||||||
{
|
{
|
||||||
var optionBuilder = new AspCoreMqttClientOptions(serviceProvider);
|
var optionBuilder = new MqttClientOptions(serviceProvider);
|
||||||
configureOptions(optionBuilder);
|
configureOptions(optionBuilder);
|
||||||
return optionBuilder.Build();
|
return optionBuilder.Build();
|
||||||
});
|
});
|
||||||
services.AddSingleton<MqttClientService>();
|
|
||||||
|
services.AddClientServiceWithProvider<MqttClientService>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddRabbitMqClientServiceWithConfig(this IServiceCollection services, RabbitMqClientOptions options)
|
||||||
|
{
|
||||||
|
services.AddSingleton(options);
|
||||||
|
|
||||||
|
services.AddClientServiceWithProvider<RabbitMqClientService>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddClientServiceWithProvider<T>(this IServiceCollection services) where T : class, ICommunicationService
|
||||||
|
{
|
||||||
|
services.AddSingleton<T>();
|
||||||
services.AddSingleton<IHostedService>(serviceProvider =>
|
services.AddSingleton<IHostedService>(serviceProvider =>
|
||||||
{
|
{
|
||||||
return serviceProvider.GetService<MqttClientService>();
|
return serviceProvider.GetService<T>();
|
||||||
});
|
});
|
||||||
services.AddSingleton(serviceProvider =>
|
services.AddSingleton<ICommunicationServiceProvider>(serviceProvider =>
|
||||||
{
|
{
|
||||||
var mqttClientService = serviceProvider.GetService<MqttClientService>();
|
var clientService = serviceProvider.GetService<T>();
|
||||||
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
|
var clientServiceProvider = new CommunicationServiceProvider(clientService);
|
||||||
return mqttClientServiceProvider;
|
return clientServiceProvider;
|
||||||
});
|
});
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
2
MQTTnet.TestApp.WinForm/Form1.Designer.cs
generated
2
MQTTnet.TestApp.WinForm/Form1.Designer.cs
generated
@ -267,7 +267,7 @@
|
|||||||
this.trackBar1.LargeChange = 500;
|
this.trackBar1.LargeChange = 500;
|
||||||
this.trackBar1.Location = new System.Drawing.Point(180, 162);
|
this.trackBar1.Location = new System.Drawing.Point(180, 162);
|
||||||
this.trackBar1.Maximum = 5050;
|
this.trackBar1.Maximum = 5050;
|
||||||
this.trackBar1.Minimum = 50;
|
this.trackBar1.Minimum = 1;
|
||||||
this.trackBar1.Name = "trackBar1";
|
this.trackBar1.Name = "trackBar1";
|
||||||
this.trackBar1.Size = new System.Drawing.Size(247, 45);
|
this.trackBar1.Size = new System.Drawing.Size(247, 45);
|
||||||
this.trackBar1.SmallChange = 100;
|
this.trackBar1.SmallChange = 100;
|
||||||
|
@ -17,7 +17,7 @@ services:
|
|||||||
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
|
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Birdmap.API/Dockerfile
|
dockerfile: Dockerfile
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
environment:
|
environment:
|
||||||
@ -38,8 +38,18 @@ services:
|
|||||||
- Birdmap_Defaults__Services__KMLabz-Service=https://birb.k8s.kmlabz.com/devices
|
- Birdmap_Defaults__Services__KMLabz-Service=https://birb.k8s.kmlabz.com/devices
|
||||||
- Birdmap_UseDummyServices=true
|
- Birdmap_UseDummyServices=true
|
||||||
- Birdmap_ServicesBaseUrl=https://birb.k8s.kmlabz.com/
|
- Birdmap_ServicesBaseUrl=https://birb.k8s.kmlabz.com/
|
||||||
|
- Birdmap_UseRabbitMq=false
|
||||||
- Birdmap_Mqtt__BrokerHostSettings__Host=localhost
|
- Birdmap_Mqtt__BrokerHostSettings__Host=localhost
|
||||||
- Birdmap_Mqtt__BrokerHostSettings__Port=1883
|
- Birdmap_Mqtt__BrokerHostSettings__Port=1883
|
||||||
|
- Birdmap_Mqtt__BrokerHostSettings__VirtualHost=/
|
||||||
|
- Birdmap_Mqtt__ExchangeSettings__Name=birbmapexchange
|
||||||
|
- Birdmap_Mqtt__ExchangeSettings__Type=fanout
|
||||||
|
- Birdmap_Mqtt__ExchangeSettings__Durable=true
|
||||||
|
- Birdmap_Mqtt__ExchangeSettings__AutoDelete=true
|
||||||
|
- Birdmap_Mqtt__QueueSettings__Name=birbmapqueue
|
||||||
|
- Birdmap_Mqtt__QueueSettings__Durable=true
|
||||||
|
- Birdmap_Mqtt__QueueSettings__Exclusive=true
|
||||||
|
- Birdmap_Mqtt__QueueSettings__AutoDelete=true
|
||||||
- Birdmap_Mqtt__ClientSettings__Id=ASP.NET Core client
|
- Birdmap_Mqtt__ClientSettings__Id=ASP.NET Core client
|
||||||
- Birdmap_Mqtt__ClientSettings__Username=username
|
- Birdmap_Mqtt__ClientSettings__Username=username
|
||||||
- Birdmap_Mqtt__ClientSettings__Password=password
|
- Birdmap_Mqtt__ClientSettings__Password=password
|
||||||
|
BIN
docs/thesis.pdf
Normal file
BIN
docs/thesis.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user