Refactor NucuCar.Telemetry to use interfaces.

This commit is contained in:
Denis-Cosmin Nutiu 2021-08-02 21:28:02 +03:00
parent 8749b6d23a
commit e1ae7ecdd0
13 changed files with 91 additions and 38 deletions

View file

@ -1,17 +1,18 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NucuCar.Sensors.Abstractions;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors.Modules.BME680
{
public class Bme680Worker : SensorWorker
{
public Bme680Worker(ILogger<Bme680Worker> logger, Telemetry.Telemetry telemetry, ISensor<Bme680Sensor> sensor,
public Bme680Worker(ILogger<Bme680Worker> logger, ITelemetryPublisher telemetryPublisherProxy, ISensor<Bme680Sensor> sensor,
IOptions<Bme680Config> options)
{
Logger = logger;
MeasurementInterval = options.Value.MeasurementInterval;
TelemetryPublisher = telemetry.Publisher;
TelemetryPublisher = telemetryPublisherProxy;
Sensor = sensor.Object;
}
}

View file

@ -1,17 +1,18 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NucuCar.Sensors.Abstractions;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors.Modules.CpuTemperature
{
public class CpuTempWorker : SensorWorker
{
public CpuTempWorker(ILogger<CpuTempWorker> logger, Telemetry.Telemetry telemetry,
public CpuTempWorker(ILogger<CpuTempWorker> logger, ITelemetryPublisher telemetryPublisherProxy,
ISensor<CpuTempSensor> sensor, IOptions<CpuTempConfig> options)
{
Logger = logger;
MeasurementInterval = options.Value.MeasurementInterval;
TelemetryPublisher = telemetry.Publisher;
TelemetryPublisher = telemetryPublisherProxy;
Sensor = sensor.Object;
}
}

View file

@ -1,17 +1,18 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NucuCar.Sensors.Abstractions;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors.Modules.Heartbeat
{
public class HeartbeatWorker : SensorWorker
{
public HeartbeatWorker(ILogger<HeartbeatWorker> logger, Telemetry.Telemetry telemetry,
public HeartbeatWorker(ILogger<HeartbeatWorker> logger, ITelemetryPublisher telemetryPublisherProxy,
ISensor<HeartbeatSensor> sensor, IOptions<HeartbeatConfig> options)
{
Logger = logger;
MeasurementInterval = options.Value.MeasurementInterval;
TelemetryPublisher = telemetry.Publisher;
TelemetryPublisher = telemetryPublisherProxy;
Sensor = sensor.Object;
}
}

View file

@ -1,17 +1,18 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NucuCar.Sensors.Abstractions;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors.Modules.PMS5003
{
public class Pms5003Worker : SensorWorker
{
public Pms5003Worker(ILogger<Pms5003Worker> logger, Telemetry.Telemetry telemetry,
public Pms5003Worker(ILogger<Pms5003Worker> logger, ITelemetryPublisher telemetryPublisherProxy,
ISensor<Pms5003Sensor> sensor, IOptions<Pms5003Config> options)
{
Logger = logger;
MeasurementInterval = options.Value.MeasurementInterval;
TelemetryPublisher = telemetry.Publisher;
TelemetryPublisher = telemetryPublisherProxy;
Sensor = sensor.Object;
}
}

View file

@ -6,6 +6,7 @@ using NucuCar.Sensors.Modules.CpuTemperature;
using NucuCar.Sensors.Modules.Heartbeat;
using NucuCar.Sensors.Modules.PMS5003;
using NucuCar.Telemetry;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors
{
@ -27,7 +28,7 @@ namespace NucuCar.Sensors
services.Configure<Pms5003Config>(hostContext.Configuration.GetSection("Pms5003Sensor"));
// Singletons
services.AddSingleton<Telemetry.Telemetry>();
services.AddSingleton<ITelemetryPublisher, TelemetryPublisherProxy>();
services.AddSingleton<ISensor<Bme680Sensor>, Bme680Sensor>();
services.AddSingleton<ISensor<CpuTempSensor>, CpuTempSensor>();
services.AddSingleton<ISensor<HeartbeatSensor>, HeartbeatSensor>();

View file

@ -17,7 +17,7 @@ namespace NucuCar.Sensors
private int _intializationDelay = 10000;
protected int MeasurementInterval;
protected ILogger Logger;
protected TelemetryPublisher TelemetryPublisher;
protected ITelemetryPublisher TelemetryPublisher;
protected GenericTelemeterSensor Sensor;
@ -25,6 +25,7 @@ namespace NucuCar.Sensors
{
if (Sensor == null)
{
Logger?.LogDebug("{Message}","Sensor is null, abandoning execution.");
return;
}

View file

@ -14,6 +14,7 @@ namespace NucuCar.Telemetry.Abstractions
/// <returns>An identifier for the telemetry source.</returns>
string GetIdentifier();
// TODO: Perhaps here it's better if we return a string.
/// <summary>
/// This function should return a dictionary containing the telemetry data.
/// When implementing this function you should return null if the telemetry is disabled.

View file

@ -0,0 +1,30 @@
using System.Threading;
using System.Threading.Tasks;
namespace NucuCar.Telemetry.Abstractions
{
public interface ITelemetryPublisher
{
/// <summary>
/// Publishes telemetry data.
/// </summary>
/// <param name="cancellationToken">A cancellation token.</param>
/// <returns>A task</returns>
public abstract Task PublishAsync(CancellationToken cancellationToken);
/// <summary>
/// Adds a telemeter to the collection.
/// The telemeter can register only once.
/// </summary>
/// <param name="t">The <see cref="ITelemeter"/></param>
/// <returns>Returns true if the telemeter has registered successfully and false otherwise.</returns>
public bool RegisterTelemeter(ITelemeter t);
/// <summary>
/// Method that deletes a telemeter from the collection.
/// </summary>
/// <param name="t">The <see cref="ITelemeter"/></param>
/// <returns>Returns true if the telemeter has unregistered successfully and false otherwise.</returns>
public bool UnRegisterTelemeter(ITelemeter t);
}
}

View file

@ -7,10 +7,9 @@ using Microsoft.Extensions.Logging;
namespace NucuCar.Telemetry.Abstractions
{
/// <summary>
/// TODO: make an interface.
/// The TelemetryPublisher is an abstract class, which provides a base for implementing telemetry publishers.
/// </summary>
public abstract class TelemetryPublisher : IDisposable
public abstract class TelemetryPublisher : IDisposable, ITelemetryPublisher
{
/// <summary>
/// Raw connection string that is used to connect to the cloud service. Should be parsed if required.
@ -40,6 +39,19 @@ namespace NucuCar.Telemetry.Abstractions
{
RegisteredTelemeters = new List<ITelemeter>(10);
}
/// <summary>
/// Constructor for <see cref="TelemetryPublisher"/>.
/// </summary>
/// <param name="opts">TelemetryPublisher options, see: <see cref="TelemetryPublisherOptions"/></param>
protected TelemetryPublisher(TelemetryPublisherOptions opts)
{
ConnectionString = opts.ConnectionString;
TelemetrySource = opts.TelemetrySource;
Logger = opts.Logger;
RegisteredTelemeters = new List<ITelemeter>(10);
}
/// <summary>
/// Method that sends all data from the (<see cref="RegisteredTelemeters"/>) to the cloud.
@ -80,19 +92,7 @@ namespace NucuCar.Telemetry.Abstractions
RegisteredTelemeters.Remove(t);
return true;
}
/// <summary>
/// Constructor for <see cref="TelemetryPublisher"/>.
/// </summary>
/// <param name="opts">TelemetryPublisher options, see: <see cref="TelemetryPublisherOptions"/></param>
protected TelemetryPublisher(TelemetryPublisherOptions opts)
{
ConnectionString = opts.ConnectionString;
TelemetrySource = opts.TelemetrySource;
Logger = opts.Logger;
RegisteredTelemeters = new List<ITelemeter>(10);
}
/// <summary>
/// Iterates through the registered telemeters and returns the telemetry data as dictionary.
/// It also adds metadata information such as: source and timestamp.

View file

@ -19,7 +19,7 @@ namespace NucuCar.Telemetry
/// <param name="telemetrySource">String that is used to identify the source of the telemetry data.</param>
/// <param name="logger">An <see cref="ILogger"/> logger instance. </param>
/// <returns>A <see cref="TelemetryPublisher"/> instance.</returns>
public static TelemetryPublisher Create(string type, string connectionString,
public static ITelemetryPublisher Create(string type, string connectionString,
string telemetrySource, ILogger logger)
{
Guard.ArgumentNotNullOrWhiteSpace(nameof(connectionString), connectionString);
@ -36,7 +36,7 @@ namespace NucuCar.Telemetry
/// <param name="type">The type of the publisher. See <see cref="TelemetryPublisherType"/> </param>
/// <param name="connectionString">The device connection string for the selected publisher.</param>
/// <returns>A <see cref="TelemetryPublisher"/> instance.</returns>
public static TelemetryPublisher CreateFromConnectionString(string type, string connectionString)
public static ITelemetryPublisher CreateFromConnectionString(string type, string connectionString)
{
Guard.ArgumentNotNullOrWhiteSpace(nameof(connectionString), connectionString);
var opts = new TelemetryPublisherOptions()
@ -44,7 +44,7 @@ namespace NucuCar.Telemetry
return SpawnPublisher(type, opts);
}
private static TelemetryPublisher SpawnPublisher(string type, TelemetryPublisherOptions opts)
private static ITelemetryPublisher SpawnPublisher(string type, TelemetryPublisherOptions opts)
{
return type switch
{

View file

@ -1,24 +1,25 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NucuCar.Telemetry.Abstractions;
// ReSharper disable ClassWithVirtualMembersNeverInherited.Global
namespace NucuCar.Telemetry
{
public class Telemetry
public class TelemetryPublisherProxy : ITelemetryPublisher
{
public TelemetryPublisher Publisher { get; set; }
private ITelemetryPublisher Publisher { get; set; }
/// <summary>
/// Class used together with the DI, holds a Publisher instance that's being create by options from
/// TelemetryConfig.
/// </summary>
public Telemetry()
public TelemetryPublisherProxy()
{
}
public Telemetry(ILogger<Telemetry> logger, IOptions<TelemetryConfig> options)
public TelemetryPublisherProxy(ILogger<TelemetryPublisherProxy> logger, IOptions<TelemetryConfig> options)
{
if (options.Value.ServiceEnabled)
{
@ -30,5 +31,20 @@ namespace NucuCar.Telemetry
Publisher = null;
}
}
public Task PublishAsync(CancellationToken cancellationToken)
{
return Publisher.PublishAsync(cancellationToken);
}
public bool RegisterTelemeter(ITelemeter t)
{
return Publisher.RegisterTelemeter(t);
}
public bool UnRegisterTelemeter(ITelemeter t)
{
return Publisher.UnRegisterTelemeter(t);
}
}
}

View file

@ -16,15 +16,15 @@ namespace NucuCar.Telemetry
private readonly int _interval;
private readonly bool _serviceEnabled;
private readonly ILogger _logger;
private readonly TelemetryPublisher _telemetryPublisher;
private readonly ITelemetryPublisher _telemetryPublisher;
public TelemetryWorker(ILogger<TelemetryWorker> logger, IOptions<TelemetryConfig> options,
Telemetry telemetry)
ITelemetryPublisher telemetryPublisherProxy)
{
_logger = logger;
_interval = options.Value.PublishInterval;
_serviceEnabled = options.Value.ServiceEnabled;
_telemetryPublisher = telemetry.Publisher;
_telemetryPublisher = telemetryPublisherProxy;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)

View file

@ -18,7 +18,7 @@ namespace NucuCar.UnitTests.NucuCar.Sensors.Tests
{
private readonly Mock<ILogger<Bme680Worker>> _mockLogger;
private readonly Mock<IOptions<Bme680Config>> _mockOptions;
private readonly Mock<global::NucuCar.Telemetry.Telemetry> _mockSensorTelemetry;
private readonly Mock<global::NucuCar.Telemetry.TelemetryPublisherProxy> _mockSensorTelemetry;
private readonly Mock<TestBme680Sensor> _mockTestBme680Sensor;
private readonly Mock<ISensor<Bme680Sensor>> _mockBme680ISensor;
private readonly CancellationTokenSource _cts;
@ -28,7 +28,7 @@ namespace NucuCar.UnitTests.NucuCar.Sensors.Tests
_cts = new CancellationTokenSource();
_mockLogger = new Mock<ILogger<Bme680Worker>>();
_mockOptions = new Mock<IOptions<Bme680Config>>();
_mockSensorTelemetry = new Mock<global::NucuCar.Telemetry.Telemetry>();
_mockSensorTelemetry = new Mock<global::NucuCar.Telemetry.TelemetryPublisherProxy>();
_mockTestBme680Sensor = new Mock<TestBme680Sensor>();
_mockBme680ISensor = new Mock<ISensor<Bme680Sensor>>();