NUC-27: Implement Firebase firestore telemetry publisher
This commit is contained in:
parent
c78fef2ea0
commit
3f8edbe608
8 changed files with 95 additions and 5 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,4 +2,5 @@ bin/
|
|||
obj/
|
||||
/packages/
|
||||
.idea/
|
||||
.vs
|
||||
.vs
|
||||
NucuCar.Sensors/firebaseConfig.json
|
|
@ -16,6 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Cloud.Firestore" Version="1.1.0" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
|
||||
<PackageReference Include="Grpc" Version="2.25.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.25.0" />
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace NucuCar.Domain.Telemetry
|
|||
var metadata = new Dictionary<string, object>
|
||||
{
|
||||
["source"] = TelemetrySource ?? nameof(TelemetryPublisher),
|
||||
["timestamp"] = DateTime.Now,
|
||||
["timestamp"] = DateTime.UtcNow,
|
||||
["data"] = data.ToArray()
|
||||
};
|
||||
return metadata;
|
||||
|
|
|
@ -8,6 +8,13 @@ using Newtonsoft.Json;
|
|||
|
||||
namespace NucuCar.Domain.Telemetry
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs an instance of <see cref="TelemetryPublisherAzure"/>. It is used to publish telemetry to Microsoft
|
||||
/// Azure IotHub
|
||||
/// <remarks>
|
||||
/// The connection string can be found in your Azure IotHub.
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public class TelemetryPublisherAzure : TelemetryPublisher
|
||||
{
|
||||
protected readonly DeviceClient DeviceClient;
|
||||
|
|
|
@ -11,7 +11,7 @@ using NucuCar.Domain.Utilities;
|
|||
namespace NucuCar.Domain.Telemetry
|
||||
{
|
||||
/// <summary>
|
||||
/// The TelemetryPublisherDisk is used to publish telemetry data to a file residing on the disk.
|
||||
/// The TelemetryPublisherDisk is used to publish telemetry data to a file on the disk.
|
||||
/// </summary>
|
||||
public class TelemetryPublisherDisk : TelemetryPublisher
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace NucuCar.Domain.Telemetry
|
|||
/// Constructs an instance of <see cref="TelemetryPublisherDisk"/>.
|
||||
/// <remarks>
|
||||
/// The connection string must contain the following options:
|
||||
/// Filename (required) - The path of the filename in which to log telemetry data.
|
||||
/// Filename (optional) - The path of the filename in which to log telemetry data.
|
||||
/// FileExtension (optional) - The extension of the filename. Default csv
|
||||
/// Separator (optional) - The separator of the messages. Default ,
|
||||
/// BufferSize (optional) - The buffer size for the async writer. Default: 4096
|
||||
|
@ -32,7 +32,7 @@ namespace NucuCar.Domain.Telemetry
|
|||
public TelemetryPublisherDisk(TelemetryPublisherBuilderOptions opts) : base(opts)
|
||||
{
|
||||
var connectionStringParams = ConnectionStringParser.Parse(opts.ConnectionString);
|
||||
var fileName = connectionStringParams.GetValueOrDefault("FileName");
|
||||
var fileName = connectionStringParams.GetValueOrDefault("FileName", "telemetry");
|
||||
var fileExtension = connectionStringParams.GetValueOrDefault("FileExtension", "csv");
|
||||
var bufferSize = connectionStringParams.GetValueOrDefault("BufferSize", "4096");
|
||||
_separator = connectionStringParams.GetValueOrDefault("Separator", ",");
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace NucuCar.Domain.Telemetry
|
|||
{
|
||||
TelemetryPublisherType.Azure => (TelemetryPublisher) new TelemetryPublisherAzure(opts),
|
||||
TelemetryPublisherType.Disk => new TelemetryPublisherDisk(opts),
|
||||
TelemetryPublisherType.Firestore => new TelemetryPublisherFirestore(opts),
|
||||
_ => throw new ArgumentException($"Invalid TelemetryPublisher type: {type}.")
|
||||
};
|
||||
}
|
||||
|
|
79
NucuCar.Domain/Telemetry/TelemetryPublisherFirestore.cs
Normal file
79
NucuCar.Domain/Telemetry/TelemetryPublisherFirestore.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Cloud.Firestore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NucuCar.Domain.Utilities;
|
||||
|
||||
namespace NucuCar.Domain.Telemetry
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used to publish the telemetry data to Google's Cloud Firestore.
|
||||
/// Requires the environment variable: GOOGLE_APPLICATION_CREDENTIALS to be set.
|
||||
/// See: https://cloud.google.com/docs/authentication/getting-started
|
||||
/// or Firebase > Project Settings > Service Accounts
|
||||
/// <remarks>
|
||||
/// The connection string has the following parameters:
|
||||
/// ProjectId (required) — The string for the Firestore project id.
|
||||
/// CollectionName (required) — The string for the Firestore collection name.
|
||||
/// Timeout (optional) — The number in milliseconds in which to timeout if publishing fails. Default: 10000
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public class TelemetryPublisherFirestore : TelemetryPublisher
|
||||
{
|
||||
private readonly FirestoreDb _database;
|
||||
private readonly string _firestoreCollection;
|
||||
private readonly int _timeout;
|
||||
|
||||
public TelemetryPublisherFirestore(TelemetryPublisherBuilderOptions opts) : base(opts)
|
||||
{
|
||||
var options = ConnectionStringParser.Parse(opts.ConnectionString);
|
||||
if (!options.TryGetValue("ProjectId", out var firestoreProjectId))
|
||||
{
|
||||
Logger?.LogCritical(
|
||||
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
|
||||
$"Missing ProjectId!");
|
||||
}
|
||||
|
||||
if (!options.TryGetValue("CollectionName", out _firestoreCollection))
|
||||
{
|
||||
Logger?.LogCritical(
|
||||
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
|
||||
$"Missing CollectionName!");
|
||||
}
|
||||
_timeout = int.Parse(options.GetValueOrDefault("Timeout", "10000"));
|
||||
|
||||
|
||||
_database = FirestoreDb.Create(firestoreProjectId);
|
||||
Logger?.LogInformation($"Initialized {nameof(TelemetryPublisherFirestore)}");
|
||||
}
|
||||
|
||||
public override async Task PublishAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var docRef = _database.Collection(_firestoreCollection).Document();
|
||||
var data = GetTelemetry();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(_timeout);
|
||||
try
|
||||
{
|
||||
await docRef.SetAsync(data, cancellationToken: cts.Token);
|
||||
Logger?.LogInformation("Published data to Firestore!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.LogError($"Failed to publish telemetry data!\n{e.GetType().FullName}: {e.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,5 +8,6 @@ namespace NucuCar.Domain.Telemetry
|
|||
{
|
||||
public const string Azure = "Azure";
|
||||
public const string Disk = "Disk";
|
||||
public const string Firestore = "Firestore";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue