2020-02-08 17:47:44 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2020-02-16 13:45:41 +00:00
|
|
|
using System.Net.Http;
|
|
|
|
using System.Text;
|
2020-02-08 17:47:44 +00:00
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Microsoft.Extensions.Logging;
|
2020-02-16 13:45:41 +00:00
|
|
|
using Newtonsoft.Json;
|
2020-02-08 17:47:44 +00:00
|
|
|
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
|
2020-02-16 13:49:31 +00:00
|
|
|
/// or Firebase > Project Settings > Service Accounts (Authentication is not implemented!)
|
2020-02-08 17:47:44 +00:00
|
|
|
/// <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
|
|
|
|
{
|
2020-02-16 13:45:41 +00:00
|
|
|
private readonly HttpClient _httpClient;
|
2020-02-08 17:47:44 +00:00
|
|
|
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!");
|
|
|
|
}
|
|
|
|
|
2020-02-16 13:45:41 +00:00
|
|
|
if (!options.TryGetValue("CollectionName", out var firestoreCollection))
|
2020-02-08 17:47:44 +00:00
|
|
|
{
|
|
|
|
Logger?.LogCritical(
|
|
|
|
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
|
|
|
|
$"Missing CollectionName!");
|
|
|
|
}
|
|
|
|
|
2020-02-16 13:45:41 +00:00
|
|
|
_timeout = int.Parse(options.GetValueOrDefault("Timeout", "10000"));
|
2020-02-08 17:47:44 +00:00
|
|
|
|
2020-02-16 13:45:41 +00:00
|
|
|
var requestUrl = $"https://firestore.googleapis.com/v1/projects/{firestoreProjectId}/" +
|
|
|
|
$"databases/(default)/documents/{firestoreCollection}/";
|
|
|
|
_httpClient = new HttpClient();
|
|
|
|
_httpClient.BaseAddress = new Uri(requestUrl);
|
2020-02-08 17:47:44 +00:00
|
|
|
Logger?.LogInformation($"Initialized {nameof(TelemetryPublisherFirestore)}");
|
|
|
|
}
|
|
|
|
|
|
|
|
public override async Task PublishAsync(CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
if (cancellationToken.IsCancellationRequested)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-02-16 13:45:41 +00:00
|
|
|
|
2020-02-08 17:47:44 +00:00
|
|
|
var cts = new CancellationTokenSource();
|
|
|
|
cts.CancelAfter(_timeout);
|
|
|
|
try
|
|
|
|
{
|
2020-02-16 13:45:41 +00:00
|
|
|
var data = FirebaseRestTranslator.Translate(null, GetTelemetry());
|
|
|
|
var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
|
|
|
|
await _httpClient.PostAsync("", content, cts.Token);
|
2020-02-08 17:47:44 +00:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2020-02-16 13:45:41 +00:00
|
|
|
}
|