NUC-31: Finish working implementation for FirebaseRestTranslator
This commit is contained in:
parent
24e0630421
commit
ff492258a8
4 changed files with 50 additions and 23 deletions
|
@ -16,7 +16,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Cloud.Firestore" Version="1.1.0" />
|
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
|
||||||
<PackageReference Include="Grpc" Version="2.25.0" />
|
<PackageReference Include="Grpc" Version="2.25.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.25.0" />
|
<PackageReference Include="Grpc.Tools" Version="2.25.0" />
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Google.Cloud.Firestore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NucuCar.Domain.Utilities;
|
using NucuCar.Domain.Utilities;
|
||||||
|
|
||||||
namespace NucuCar.Domain.Telemetry
|
namespace NucuCar.Domain.Telemetry
|
||||||
|
@ -22,8 +24,7 @@ namespace NucuCar.Domain.Telemetry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelemetryPublisherFirestore : TelemetryPublisher
|
public class TelemetryPublisherFirestore : TelemetryPublisher
|
||||||
{
|
{
|
||||||
private readonly FirestoreDb _database;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly string _firestoreCollection;
|
|
||||||
private readonly int _timeout;
|
private readonly int _timeout;
|
||||||
|
|
||||||
public TelemetryPublisherFirestore(TelemetryPublisherBuilderOptions opts) : base(opts)
|
public TelemetryPublisherFirestore(TelemetryPublisherBuilderOptions opts) : base(opts)
|
||||||
|
@ -36,16 +37,19 @@ namespace NucuCar.Domain.Telemetry
|
||||||
$"Missing ProjectId!");
|
$"Missing ProjectId!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.TryGetValue("CollectionName", out _firestoreCollection))
|
if (!options.TryGetValue("CollectionName", out var firestoreCollection))
|
||||||
{
|
{
|
||||||
Logger?.LogCritical(
|
Logger?.LogCritical(
|
||||||
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
|
$"Can't start {nameof(TelemetryPublisherFirestore)}! Malformed connection string! " +
|
||||||
$"Missing CollectionName!");
|
$"Missing CollectionName!");
|
||||||
}
|
}
|
||||||
|
|
||||||
_timeout = int.Parse(options.GetValueOrDefault("Timeout", "10000"));
|
_timeout = int.Parse(options.GetValueOrDefault("Timeout", "10000"));
|
||||||
|
|
||||||
|
var requestUrl = $"https://firestore.googleapis.com/v1/projects/{firestoreProjectId}/" +
|
||||||
_database = FirestoreDb.Create(firestoreProjectId);
|
$"databases/(default)/documents/{firestoreCollection}/";
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
_httpClient.BaseAddress = new Uri(requestUrl);
|
||||||
Logger?.LogInformation($"Initialized {nameof(TelemetryPublisherFirestore)}");
|
Logger?.LogInformation($"Initialized {nameof(TelemetryPublisherFirestore)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,13 +60,13 @@ namespace NucuCar.Domain.Telemetry
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var docRef = _database.Collection(_firestoreCollection).Document();
|
|
||||||
var data = GetTelemetry();
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfter(_timeout);
|
cts.CancelAfter(_timeout);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await docRef.SetAsync(data, cancellationToken: cts.Token);
|
var data = FirebaseRestTranslator.Translate(null, GetTelemetry());
|
||||||
|
var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
|
||||||
|
await _httpClient.PostAsync("", content, cts.Token);
|
||||||
Logger?.LogInformation("Published data to Firestore!");
|
Logger?.LogInformation("Published data to Firestore!");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -16,7 +16,11 @@ namespace NucuCar.Domain.Utilities
|
||||||
private static Dictionary<string, object> BuildRoot(string name, Dictionary<string, object> dict)
|
private static Dictionary<string, object> BuildRoot(string name, Dictionary<string, object> dict)
|
||||||
{
|
{
|
||||||
var root = new Dictionary<string, object>();
|
var root = new Dictionary<string, object>();
|
||||||
root["name"] = name;
|
if (name != null)
|
||||||
|
{
|
||||||
|
root["name"] = name;
|
||||||
|
}
|
||||||
|
|
||||||
root["fields"] = new Dictionary<string, object>();
|
root["fields"] = new Dictionary<string, object>();
|
||||||
// iterate through fields and build leaf
|
// iterate through fields and build leaf
|
||||||
foreach (var entry in dict)
|
foreach (var entry in dict)
|
||||||
|
@ -24,6 +28,7 @@ namespace NucuCar.Domain.Utilities
|
||||||
var fields = (Dictionary<string, object>) root["fields"];
|
var fields = (Dictionary<string, object>) root["fields"];
|
||||||
fields[entry.Key] = BuildNode(entry.Value);
|
fields[entry.Key] = BuildNode(entry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +38,6 @@ namespace NucuCar.Domain.Utilities
|
||||||
{
|
{
|
||||||
case string v:
|
case string v:
|
||||||
{
|
{
|
||||||
if (DateTime.TryParse(v, out _))
|
|
||||||
{
|
|
||||||
return BuildTimestamp(v);
|
|
||||||
}
|
|
||||||
return BuildString(v);
|
return BuildString(v);
|
||||||
}
|
}
|
||||||
case int v:
|
case int v:
|
||||||
|
@ -51,16 +52,31 @@ namespace NucuCar.Domain.Utilities
|
||||||
{
|
{
|
||||||
return BuildBool(v);
|
return BuildBool(v);
|
||||||
}
|
}
|
||||||
|
case DateTime v:
|
||||||
|
{
|
||||||
|
return BuildTimestamp(v);
|
||||||
|
}
|
||||||
case List<Dictionary<string, object>> v:
|
case List<Dictionary<string, object>> v:
|
||||||
{
|
{
|
||||||
return BuildArray(v);
|
return BuildArray(v);
|
||||||
}
|
}
|
||||||
|
case Dictionary<string, object>[] v:
|
||||||
|
{
|
||||||
|
return BuildArray(new List<Dictionary<string, object>>(v));
|
||||||
|
}
|
||||||
case Dictionary<string, object> v:
|
case Dictionary<string, object> v:
|
||||||
{
|
{
|
||||||
return BuildMap(v);
|
return BuildMap(v);
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (value.GetType().IsEnum)
|
||||||
|
{
|
||||||
|
return BuildInteger((int) value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException($"Can't build leaf! Unknown type for: {value}");
|
throw new ArgumentException($"Can't build leaf! Unknown type for: {value}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,26 +87,32 @@ namespace NucuCar.Domain.Utilities
|
||||||
[type] = value
|
[type] = value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, object> BuildString(string value)
|
private static Dictionary<string, object> BuildString(string value)
|
||||||
{
|
{
|
||||||
return BuildSimpleValue("stringValue", value);
|
return BuildSimpleValue("stringValue", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, object> BuildInteger(int value)
|
private static Dictionary<string, object> BuildInteger(int value)
|
||||||
{
|
{
|
||||||
return BuildSimpleValue("integerValue", value);
|
return BuildSimpleValue("integerValue", value);
|
||||||
}
|
}
|
||||||
private static Dictionary<string, object> BuildTimestamp(string value)
|
|
||||||
|
private static Dictionary<string, object> BuildTimestamp(DateTime value)
|
||||||
{
|
{
|
||||||
return BuildSimpleValue("timestampValue", value);
|
return BuildSimpleValue("timestampValue", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, object> BuildDouble(double value)
|
private static Dictionary<string, object> BuildDouble(double value)
|
||||||
{
|
{
|
||||||
return BuildSimpleValue("doubleValue", value);
|
return BuildSimpleValue("doubleValue", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, object> BuildBool(bool value)
|
private static Dictionary<string, object> BuildBool(bool value)
|
||||||
{
|
{
|
||||||
return BuildSimpleValue("booleanValue", value);
|
return BuildSimpleValue("booleanValue", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<string, object> BuildArray(List<Dictionary<string, object>> array)
|
private static Dictionary<string, object> BuildArray(List<Dictionary<string, object>> array)
|
||||||
{
|
{
|
||||||
var values = new List<Dictionary<string, object>>();
|
var values = new List<Dictionary<string, object>>();
|
||||||
|
@ -106,6 +128,7 @@ namespace NucuCar.Domain.Utilities
|
||||||
{
|
{
|
||||||
values.Add(BuildNode(entry));
|
values.Add(BuildNode(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +146,7 @@ namespace NucuCar.Domain.Utilities
|
||||||
{
|
{
|
||||||
fields[entry.Key] = BuildNode(entry.Value);
|
fields[entry.Key] = BuildNode(entry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Tests.Utilities
|
||||||
public void Test_FireBaseTranslator_Parse()
|
public void Test_FireBaseTranslator_Parse()
|
||||||
{
|
{
|
||||||
var expectedJson =
|
var expectedJson =
|
||||||
"{\"name\":\"Test\",\"fields\":{\"source\":{\"stringValue\":\"NucuCar.Sensors\"},\"timestamp\":{\"timestampValue\":\"2019-12-01T23:26:13.5537227+02:00\"},\"data\":{\"arrayValue\":{\"values\":[{\"mapValue\":{\"fields\":{\"sensor_state\":{\"integerValue\":2},\"cpu_temperature\":{\"doubleValue\":48.849998474121094},\"_id\":{\"stringValue\":\"CpuTemperature\"}}}},{\"mapValue\":{\"fields\":{\"sensor_state\":{\"integerValue\":2},\"temperature\":{\"doubleValue\":32.65},\"humidity\":{\"doubleValue\":100.0},\"pressure\":{\"doubleValue\":62228.49},\"voc\":{\"doubleValue\":0.0},\"_id\":{\"stringValue\":\"Bme680-Sensor\"}}}}]}}}}";
|
"{\"name\":\"Test\",\"fields\":{\"source\":{\"stringValue\":\"NucuCar.Sensors\"},\"timestamp\":{\"stringValue\":\"2019-12-01T23:26:13.5537227+02:00\"},\"data\":{\"arrayValue\":{\"values\":[{\"mapValue\":{\"fields\":{\"sensor_state\":{\"integerValue\":2},\"cpu_temperature\":{\"doubleValue\":48.849998474121094},\"_id\":{\"stringValue\":\"CpuTemperature\"}}}},{\"mapValue\":{\"fields\":{\"sensor_state\":{\"integerValue\":2},\"temperature\":{\"doubleValue\":32.65},\"humidity\":{\"doubleValue\":100.0},\"pressure\":{\"doubleValue\":62228.49},\"voc\":{\"doubleValue\":0.0},\"_id\":{\"stringValue\":\"Bme680-Sensor\"}}}}]}}}}";
|
||||||
var basicTelemetryData = getBasicTelemetryData();
|
var basicTelemetryData = getBasicTelemetryData();
|
||||||
var result = FirebaseRestTranslator.Translate("Test", basicTelemetryData);
|
var result = FirebaseRestTranslator.Translate("Test", basicTelemetryData);
|
||||||
var json = JsonConvert.SerializeObject(result);
|
var json = JsonConvert.SerializeObject(result);
|
||||||
|
|
Loading…
Reference in a new issue