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.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NucuCar.Sensors.Abstractions; using NucuCar.Sensors.Abstractions;
using NucuCar.Telemetry.Abstractions;
namespace NucuCar.Sensors.Modules.BME680 namespace NucuCar.Sensors.Modules.BME680
{ {
public class Bme680Worker : SensorWorker 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) IOptions<Bme680Config> options)
{ {
Logger = logger; Logger = logger;
MeasurementInterval = options.Value.MeasurementInterval; MeasurementInterval = options.Value.MeasurementInterval;
TelemetryPublisher = telemetry.Publisher; TelemetryPublisher = telemetryPublisherProxy;
Sensor = sensor.Object; Sensor = sensor.Object;
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -14,6 +14,7 @@ namespace NucuCar.Telemetry.Abstractions
/// <returns>An identifier for the telemetry source.</returns> /// <returns>An identifier for the telemetry source.</returns>
string GetIdentifier(); string GetIdentifier();
// TODO: Perhaps here it's better if we return a string.
/// <summary> /// <summary>
/// This function should return a dictionary containing the telemetry data. /// This function should return a dictionary containing the telemetry data.
/// When implementing this function you should return null if the telemetry is disabled. /// 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 namespace NucuCar.Telemetry.Abstractions
{ {
/// <summary> /// <summary>
/// TODO: make an interface.
/// The TelemetryPublisher is an abstract class, which provides a base for implementing telemetry publishers. /// The TelemetryPublisher is an abstract class, which provides a base for implementing telemetry publishers.
/// </summary> /// </summary>
public abstract class TelemetryPublisher : IDisposable public abstract class TelemetryPublisher : IDisposable, ITelemetryPublisher
{ {
/// <summary> /// <summary>
/// Raw connection string that is used to connect to the cloud service. Should be parsed if required. /// Raw connection string that is used to connect to the cloud service. Should be parsed if required.
@ -41,6 +40,19 @@ namespace NucuCar.Telemetry.Abstractions
RegisteredTelemeters = new List<ITelemeter>(10); 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> /// <summary>
/// Method that sends all data from the (<see cref="RegisteredTelemeters"/>) to the cloud. /// Method that sends all data from the (<see cref="RegisteredTelemeters"/>) to the cloud.
/// </summary> /// </summary>
@ -81,18 +93,6 @@ namespace NucuCar.Telemetry.Abstractions
return true; 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> /// <summary>
/// Iterates through the registered telemeters and returns the telemetry data as dictionary. /// Iterates through the registered telemeters and returns the telemetry data as dictionary.
/// It also adds metadata information such as: source and timestamp. /// 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="telemetrySource">String that is used to identify the source of the telemetry data.</param>
/// <param name="logger">An <see cref="ILogger"/> logger instance. </param> /// <param name="logger">An <see cref="ILogger"/> logger instance. </param>
/// <returns>A <see cref="TelemetryPublisher"/> instance.</returns> /// <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) string telemetrySource, ILogger logger)
{ {
Guard.ArgumentNotNullOrWhiteSpace(nameof(connectionString), connectionString); 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="type">The type of the publisher. See <see cref="TelemetryPublisherType"/> </param>
/// <param name="connectionString">The device connection string for the selected publisher.</param> /// <param name="connectionString">The device connection string for the selected publisher.</param>
/// <returns>A <see cref="TelemetryPublisher"/> instance.</returns> /// <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); Guard.ArgumentNotNullOrWhiteSpace(nameof(connectionString), connectionString);
var opts = new TelemetryPublisherOptions() var opts = new TelemetryPublisherOptions()
@ -44,7 +44,7 @@ namespace NucuCar.Telemetry
return SpawnPublisher(type, opts); return SpawnPublisher(type, opts);
} }
private static TelemetryPublisher SpawnPublisher(string type, TelemetryPublisherOptions opts) private static ITelemetryPublisher SpawnPublisher(string type, TelemetryPublisherOptions opts)
{ {
return type switch return type switch
{ {

View file

@ -1,24 +1,25 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NucuCar.Telemetry.Abstractions; using NucuCar.Telemetry.Abstractions;
// ReSharper disable ClassWithVirtualMembersNeverInherited.Global // ReSharper disable ClassWithVirtualMembersNeverInherited.Global
namespace NucuCar.Telemetry namespace NucuCar.Telemetry
{ {
public class Telemetry public class TelemetryPublisherProxy : ITelemetryPublisher
{ {
public TelemetryPublisher Publisher { get; set; } private ITelemetryPublisher Publisher { get; set; }
/// <summary> /// <summary>
/// Class used together with the DI, holds a Publisher instance that's being create by options from /// Class used together with the DI, holds a Publisher instance that's being create by options from
/// TelemetryConfig. /// TelemetryConfig.
/// </summary> /// </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) if (options.Value.ServiceEnabled)
{ {
@ -30,5 +31,20 @@ namespace NucuCar.Telemetry
Publisher = null; 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 int _interval;
private readonly bool _serviceEnabled; private readonly bool _serviceEnabled;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly TelemetryPublisher _telemetryPublisher; private readonly ITelemetryPublisher _telemetryPublisher;
public TelemetryWorker(ILogger<TelemetryWorker> logger, IOptions<TelemetryConfig> options, public TelemetryWorker(ILogger<TelemetryWorker> logger, IOptions<TelemetryConfig> options,
Telemetry telemetry) ITelemetryPublisher telemetryPublisherProxy)
{ {
_logger = logger; _logger = logger;
_interval = options.Value.PublishInterval; _interval = options.Value.PublishInterval;
_serviceEnabled = options.Value.ServiceEnabled; _serviceEnabled = options.Value.ServiceEnabled;
_telemetryPublisher = telemetry.Publisher; _telemetryPublisher = telemetryPublisherProxy;
} }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) 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<ILogger<Bme680Worker>> _mockLogger;
private readonly Mock<IOptions<Bme680Config>> _mockOptions; 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<TestBme680Sensor> _mockTestBme680Sensor;
private readonly Mock<ISensor<Bme680Sensor>> _mockBme680ISensor; private readonly Mock<ISensor<Bme680Sensor>> _mockBme680ISensor;
private readonly CancellationTokenSource _cts; private readonly CancellationTokenSource _cts;
@ -28,7 +28,7 @@ namespace NucuCar.UnitTests.NucuCar.Sensors.Tests
_cts = new CancellationTokenSource(); _cts = new CancellationTokenSource();
_mockLogger = new Mock<ILogger<Bme680Worker>>(); _mockLogger = new Mock<ILogger<Bme680Worker>>();
_mockOptions = new Mock<IOptions<Bme680Config>>(); _mockOptions = new Mock<IOptions<Bme680Config>>();
_mockSensorTelemetry = new Mock<global::NucuCar.Telemetry.Telemetry>(); _mockSensorTelemetry = new Mock<global::NucuCar.Telemetry.TelemetryPublisherProxy>();
_mockTestBme680Sensor = new Mock<TestBme680Sensor>(); _mockTestBme680Sensor = new Mock<TestBme680Sensor>();
_mockBme680ISensor = new Mock<ISensor<Bme680Sensor>>(); _mockBme680ISensor = new Mock<ISensor<Bme680Sensor>>();