Skip to content

Commit

Permalink
improvements from private repo
Browse files Browse the repository at this point in the history
  • Loading branch information
cplnathan authored and cplnathan committed Oct 15, 2023
1 parent e1e6499 commit 60541d8
Show file tree
Hide file tree
Showing 18 changed files with 419 additions and 294 deletions.
7 changes: 4 additions & 3 deletions GoogleHelper/GoogleHelper.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Flurl" Version="3.0.7" />
<PackageReference Include="Flurl.Http" Version="4.0.0-pre3" />
<PackageReference Include="Flurl" Version="4.0.0-pre4" />
<PackageReference Include="Flurl.Http" Version="4.0.0-pre4" />
<PackageReference Include="jose-jwt" Version="4.1.0" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
</ItemGroup>
Expand Down
28 changes: 5 additions & 23 deletions GoogleHelper/Json/IntentResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@ public class QueryPayload : ResponsePayload
public class ExecutePayload : ResponsePayload
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string errorCode { get; set; }
public string? errorCode { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string debugString { get; set; }
public string? debugString { get; set; }

public List<ExecuteDeviceData> commands { get; set; }
}

// Important for polymorphism
[JsonDerivedType(typeof(LockDeviceData))]
[JsonDerivedType(typeof(ThermostatDeviceData))]
public class QueryDeviceData
{
public string status { get; set; }
Expand All @@ -64,19 +63,6 @@ public class LockDeviceData : QueryDeviceData
public string descriptiveCapacityRemaining { get; set; }
}

public class ThermostatDeviceData : QueryDeviceData
{
public string thermostatMode { get; set; }
public decimal thermostatTemperatureSetpoint { get; set; }
public decimal thermostatTemperatureAmbient { get; set; }
}

public class ValueUnit
{
public int rawValue { get; set; }
public string unit { get; set; }
}

[JsonDerivedType(typeof(ExecuteDeviceDataSuccess))]
[JsonDerivedType(typeof(ExecuteDeviceDataError))]
public class ExecuteDeviceData
Expand All @@ -95,14 +81,10 @@ public class ExecuteDeviceDataError : ExecuteDeviceData
{
public ExecuteDeviceDataError() { }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string errorCode { get; set; }
public string errorCodeReason { get; set; }
}

public class Color
{
public string name { get; set; }
public int spectrumRGB { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string errorCodeReason { get; set; }
}

}
8 changes: 4 additions & 4 deletions GoogleHelper/Services/BaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace GoogleHelper.Services
{
public interface IDeviceService
{
public Task<TResponse> QueryAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId)
public Task<TResponse> QueryAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId, CancellationToken token)
where TResponse : QueryDeviceData, new();
public Task<TResponse> ExecuteAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId, string requestId, JsonObject data, CancellationToken token)
where TResponse : ExecuteDeviceData, new();
Expand Down Expand Up @@ -38,15 +38,15 @@ public BaseDeviceService()

public List<string> ModelIdentifiers => this.DeviceModel.ModelIdentifiers;

public abstract Task<TResponse> QueryAsyncImplementation<TResponse>(TContext session, TModel deviceModel, string deviceId) where TResponse : QueryDeviceData, new();
public abstract Task<TResponse> QueryAsyncImplementation<TResponse>(TContext session, TModel deviceModel, string deviceId, CancellationToken token) where TResponse : QueryDeviceData, new();

public abstract Task<TResponse> ExecuteAsyncImplementation<TResponse>(TContext session, TModel deviceModel, string deviceId, string requestId, JsonObject data, CancellationToken token) where TResponse : ExecuteDeviceData, new();

public abstract Task<bool> FetchAsyncImplementation(TContext session, TModel deviceModel, string deviceId, bool forceFetch = false);

public async Task<TResponse> QueryAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId) where TResponse : QueryDeviceData, new()
public async Task<TResponse> QueryAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId, CancellationToken token) where TResponse : QueryDeviceData, new()
{
return await this.QueryAsyncImplementation<TResponse>((TContext)session, (TModel)deviceModel, deviceId);
return await this.QueryAsyncImplementation<TResponse>((TContext)session, (TModel)deviceModel, deviceId, token);
}

public async Task<TResponse> ExecuteAsync<TResponse>(BaseContext session, BaseDeviceModel deviceModel, string deviceId, string requestId, JsonObject data, CancellationToken token) where TResponse : ExecuteDeviceData, new()
Expand Down
39 changes: 20 additions & 19 deletions GoogleHelper/Services/GoogleService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Nathan Ford. All rights reserved. Class1.cs

using Flurl;
using Flurl.Http;
using GoogleHelper.Context;
using GoogleHelper.Json;
Expand Down Expand Up @@ -55,14 +56,14 @@ private string BuildSignedJWT(string privateKey, string privateKeyId, string cli
return token;
}

public async Task ProvideFollowUp(string privateKey, string privateKeyId, string clientEmail, string agentUserId, string requestId, string deviceId, string deviceAction, JsonObject data)
public async Task ProvideFollowUp(string privateKey, string privateKeyId, string clientEmail, string agentUserId, string requestId, string deviceId, string deviceAction, JsonObject data, CancellationToken token)
{
string token = this.BuildSignedJWT(privateKey, privateKeyId, clientEmail, agentUserId);
string authToken = this.BuildSignedJWT(privateKey, privateKeyId, clientEmail, agentUserId);

try
{
IFlurlResponse unused = await "https://homegraph.googleapis.com/v1/devices:reportStateAndNotification"
.WithOAuthBearerToken(token)
.WithOAuthBearerToken(authToken)
.PostJsonAsync(new HomegraphResponse()
{
agentUserId = agentUserId,
Expand All @@ -85,22 +86,22 @@ public async Task ProvideFollowUp(string privateKey, string privateKeyId, string
}
}
}
}, cancellationToken: CancellationToken.None);
}, cancellationToken: token);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

public async Task ProvideObjectDetection(string privateKey, string privateKeyId, string clientEmail, string agentUserId, string deviceId, string objectName)
public async Task ProvideObjectDetection(string privateKey, string privateKeyId, string clientEmail, string agentUserId, string deviceId, string objectName, CancellationToken token)
{
string token = this.BuildSignedJWT(privateKey, privateKeyId, clientEmail, agentUserId);
string authToken = this.BuildSignedJWT(privateKey, privateKeyId, clientEmail, agentUserId);

try
{
IFlurlResponse unused = await "https://homegraph.googleapis.com/v1/devices:reportStateAndNotification"
.WithOAuthBearerToken(token)
.WithOAuthBearerToken(authToken)
.PostJsonAsync(new HomegraphResponse()
{
agentUserId = agentUserId,
Expand Down Expand Up @@ -134,19 +135,19 @@ public async Task ProvideObjectDetection(string privateKey, string privateKeyId,
}
}
}
}, cancellationToken: CancellationToken.None);
}, cancellationToken: token);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

public async Task<GoogleIntentResponse?> HandleGoogleResponse(TContext context, GoogleIntentRequest request, IEnumerable<IDeviceService> supportedDevices, string sessionId, CancellationToken token)
public async Task<GoogleIntentResponse> HandleGoogleResponse(TContext? context, GoogleIntentRequest request, IEnumerable<IDeviceService> supportedDevices, string sessionId, CancellationToken token)
{
if (context is null)
{
return null;
throw new InvalidOperationException("Invalid context provided to Google handler.");
}

GoogleIntentResponse response = new(request);
Expand Down Expand Up @@ -174,7 +175,7 @@ public async Task ProvideObjectDetection(string privateKey, string privateKeyId,
{
IEnumerable<IGrouping<IDeviceService, KeyValuePair<string, BaseDeviceModel>>> groupedServiceModels = this.GroupedSupportedDevices(context, supportedDevices, action.payload?.devices);

Dictionary<string, Task<QueryDeviceData>> deviceQueryTasks = groupedServiceModels.SelectMany(gp => gp.Select(device => (device.Key, gp.Key.QueryAsync<QueryDeviceData>(context, device.Value, device.Key))))
Dictionary<string, Task<QueryDeviceData>> deviceQueryTasks = groupedServiceModels.SelectMany(gp => gp.Select(device => (device.Key, gp.Key.QueryAsync<QueryDeviceData>(context, device.Value, device.Key, token))))
.ToDictionary(item => item.Key, item => item.Item2);

IEnumerable<(string First, QueryDeviceData Second)> deviceQueryResults = deviceQueryTasks.Keys.Zip(await Task.WhenAll(deviceQueryTasks.Values));
Expand All @@ -196,30 +197,30 @@ public async Task ProvideObjectDetection(string privateKey, string privateKeyId,
case "EXECUTE":
{
List<ExecuteDeviceData> executedCommands = new();
string errorCode = null;
string debugMessage = null;
string? errorCode = null;
string? debugMessage = null;

try
{
foreach (Command? command in action.payload?.commands ?? Array.Empty<Command>())
{
IEnumerable<IGrouping<IDeviceService, KeyValuePair<string, BaseDeviceModel>>> groupedServiceModels = this.GroupedSupportedDevices(context, supportedDevices, command?.devices);

foreach (Execution execution in command.execution)
foreach (Execution execution in command?.execution ?? Enumerable.Empty<Execution>())
{
List<string> updatedIds = new();

string parsedCommand = execution.command.Split("action.devices.commands.")[1];
// string parsedCommand = execution.command.Split("action.devices.commands.")[1];

Dictionary<string, Task<ExecuteDeviceData>> deviceExecuteTasks = groupedServiceModels.SelectMany(gp => gp.Select(device => (device.Key, gp.Key.ExecuteAsync<ExecuteDeviceData>(context, device.Value, device.Key, request.requestId/*parsedCommand*/, execution._params, token))))
.ToDictionary(item => item.Key, item => item.Item2);

IEnumerable<(string First, ExecuteDeviceData Second)> deviceExecuteResults = deviceExecuteTasks.Keys.Zip(await Task.WhenAll(deviceExecuteTasks.Values));
IEnumerable<(string deviceKey, ExecuteDeviceData deviceData)> deviceExecuteResults = deviceExecuteTasks.Keys.Zip(await Task.WhenAll(deviceExecuteTasks.Values));

foreach ((string First, ExecuteDeviceData Second) in deviceExecuteResults)
foreach ((string deviceKey, ExecuteDeviceData deviceData) in deviceExecuteResults)
{
ExecuteDeviceData state = Second;
state.ids = new List<string>() { First };
ExecuteDeviceData state = deviceData;
state.ids = new List<string>() { deviceKey };

executedCommands.Add(state);
}
Expand Down
30 changes: 28 additions & 2 deletions SurePet2Google.Blazor/Server/Context/HttpContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Flurl;
using Flurl.Http;
using Flurl.Http.Configuration;
using Microsoft.Extensions.Http;
Expand All @@ -6,7 +7,7 @@

namespace SurePet2Google.Blazor.Server.Context
{
public class GlobalHttpContext : DefaultHttpClientFactory
public class GlobalHttpContext : FlurlClientFactoryBase
{
public override HttpMessageHandler CreateMessageHandler()
{
Expand All @@ -20,7 +21,21 @@ public static IAsyncPolicy<HttpResponseMessage> BuildRetryPolicy()
{
var retryPolicy =
Policy
.Handle<HttpRequestException>((exception) => new List<HttpStatusCode>() { HttpStatusCode.TooManyRequests, HttpStatusCode.BadRequest }.Contains(exception.StatusCode ?? HttpStatusCode.BadRequest))
.Handle<Exception>((exception) =>
{
int? statusCode = -1;

if (exception is FlurlHttpException flurlException)
{
statusCode = flurlException.StatusCode;
}
else if (exception is HttpRequestException httpException)
{
statusCode = (int?)httpException.StatusCode;
}

return new List<int>() { (int)HttpStatusCode.TooManyRequests, (int)HttpStatusCode.BadRequest, (int)HttpStatusCode.GatewayTimeout }.Contains(statusCode ?? (int)HttpStatusCode.BadRequest);
})
.WaitAndRetryAsync(5, retryAttempt =>
{
var nextAttemptIn = TimeSpan.FromSeconds(Math.Pow(2, retryAttempt));
Expand All @@ -30,5 +45,16 @@ public static IAsyncPolicy<HttpResponseMessage> BuildRetryPolicy()

return retryPolicy;
}

protected override IFlurlClient Create(Url url)
{
var client = base.Create(url);
return client;
}

protected override string GetCacheKey(Url url)
{
return "StaticCache";
}
}
}
Loading

0 comments on commit 60541d8

Please sign in to comment.