From 7ed1b77457f5e41ec5f7ba8e102f13f69380608d Mon Sep 17 00:00:00 2001 From: Rory& Date: Tue, 3 Jun 2025 23:38:36 +0200 Subject: Implement budget handling --- testFrontend/SafeNSound.FakeUser/MonitorService.cs | 7 ++- testFrontend/SafeNSound.FakeUser/Program.cs | 2 +- .../SafeNSound.FakeUser/RandomAlarmService.cs | 38 -------------- testFrontend/SafeNSound.FakeUser/UserService.cs | 59 ++++++++++++++++++++++ testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs | 21 +++----- testFrontend/SafeNSound.Sdk/WrappedHttpClient.cs | 4 +- testFrontend/SafeNSound.sln.DotSettings.user | 1 + 7 files changed, 77 insertions(+), 55 deletions(-) delete mode 100644 testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs create mode 100644 testFrontend/SafeNSound.FakeUser/UserService.cs (limited to 'testFrontend') diff --git a/testFrontend/SafeNSound.FakeUser/MonitorService.cs b/testFrontend/SafeNSound.FakeUser/MonitorService.cs index b1da7e6..83c9c29 100644 --- a/testFrontend/SafeNSound.FakeUser/MonitorService.cs +++ b/testFrontend/SafeNSound.FakeUser/MonitorService.cs @@ -94,7 +94,12 @@ public class MonitorService(ILogger logger, UserStore userStore) } var userId = Random.Shared.GetItems(monitoredUsers, 1).First(); var budget = Random.Shared.NextDouble(); - await user.Client!.AddBudget(userId, budget); + await user.Client!.GetBudget(userId); + await user.Client!.AddBudget(userId, new() { + Amount = budget, + Reason = "Random budget assignment", + Venue = "FakeUser" + }); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); } catch (Exception ex) { diff --git a/testFrontend/SafeNSound.FakeUser/Program.cs b/testFrontend/SafeNSound.FakeUser/Program.cs index 7c3eaff..0852e6f 100644 --- a/testFrontend/SafeNSound.FakeUser/Program.cs +++ b/testFrontend/SafeNSound.FakeUser/Program.cs @@ -15,7 +15,7 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); -builder.Services.AddHostedService(); +builder.Services.AddHostedService(); builder.Services.AddHostedService(); // WrappedHttpClient.LogRequests = false; diff --git a/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs b/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs deleted file mode 100644 index a2e133f..0000000 --- a/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace SafeNSound.FakeUser; - -public class RandomAlarmService(UserStore userStore) : IHostedService { - private Task? _listenerTask; - private readonly CancellationTokenSource _cts = new(); - - public async Task StartAsync(CancellationToken cancellationToken) { - _listenerTask = Run(_cts.Token); - } - - private static readonly string[] validReasons = ["fall", "toilet"]; - - private async Task Run(CancellationToken cancellationToken) { - while (!cancellationToken.IsCancellationRequested) { - try { - var user = userStore.GetRandomUser(); - var currentAlarm = await user.Client!.GetAlarm(); - if (currentAlarm is null) { - await user.Client!.SetAlarm(new Sdk.AlarmDto { - Reason = Random.Shared.GetItems(validReasons, 1).First() - }); - } - else { - await user.Client!.DeleteAlarm(); - } - } - catch (Exception ex) { - Console.WriteLine($"Error setting/deleting alarm: {ex.Message}"); - } - - await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken); - } - } - - public async Task StopAsync(CancellationToken cancellationToken) { - await _cts.CancelAsync(); - } -} \ No newline at end of file diff --git a/testFrontend/SafeNSound.FakeUser/UserService.cs b/testFrontend/SafeNSound.FakeUser/UserService.cs new file mode 100644 index 0000000..e717458 --- /dev/null +++ b/testFrontend/SafeNSound.FakeUser/UserService.cs @@ -0,0 +1,59 @@ +namespace SafeNSound.FakeUser; + +public class UserService(ILogger logger, UserStore userStore) : IHostedService { + private Task _alarmTask, _spendBudgetTask; + private readonly CancellationTokenSource _cts = new(); + + public async Task StartAsync(CancellationToken cancellationToken) { + _alarmTask = ManageAlarms(_cts.Token); + _spendBudgetTask = AssignBudget(_cts.Token); + } + + private static readonly string[] validReasons = ["fall", "toilet"]; + + private async Task ManageAlarms(CancellationToken cancellationToken) { + while (!cancellationToken.IsCancellationRequested) { + try { + var user = userStore.GetRandomUser(); + var currentAlarm = await user.Client!.GetAlarm(); + if (currentAlarm is null) { + await user.Client!.SetAlarm(new Sdk.AlarmDto { + Reason = Random.Shared.GetItems(validReasons, 1).First() + }); + } + else { + await user.Client!.DeleteAlarm(); + } + } + catch (Exception ex) { + logger.LogError(ex, "Error setting/deleting alarm"); + } + + await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken); + } + } + + private async Task AssignBudget(CancellationToken cancellationToken) { + while (!cancellationToken.IsCancellationRequested) { + try { + var user = userStore.GetRandomUser(); + var budget = await user.Client!.GetBudget(); + await user.Client!.SpendBudget(new() { + Amount = Math.Min(budget.Amount, Random.Shared.NextDouble()), + Reason = "Random budget spending", + Venue = "The Store" + }); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } + catch (Exception ex) { + logger.LogError(ex, "Error spending budget"); + } + } + } + + public async Task StopAsync(CancellationToken cancellationToken) { + await _cts.CancelAsync(); + await _alarmTask; + await _spendBudgetTask; + } +} \ No newline at end of file diff --git a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs index 4376d3f..e1564db 100644 --- a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs +++ b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs @@ -119,15 +119,20 @@ public class SafeNSoundClient(SafeNSoundConfiguration config, string accessToken res.EnsureSuccessStatusCode(); } - public async Task AddBudget(string userId, BudgetWithReason budget) { + public async Task AddBudget(string userId, BudgetHistoryEntry budget) { var res = await HttpClient.PatchAsJsonAsync($"/user/{userId}/budget", budget); res.EnsureSuccessStatusCode(); } + + public async Task SpendBudget(BudgetHistoryEntry budget) { + var res = await HttpClient.PatchAsJsonAsync($"/budget/@me", budget); + res.EnsureSuccessStatusCode(); + } public async Task GetBudget(string userId = "@me") { var res = await HttpClient.GetAsync( userId == "@me" - ? $"/budget" + ? $"/budget/@me" : $"/user/{userId}/budget" ); res.EnsureSuccessStatusCode(); @@ -157,16 +162,6 @@ public class DeviceDto { public DateTime LastSeen { get; set; } } -public class Budget { - [JsonPropertyName("budget")] - public double Amount { get; set; } -} - -public class BudgetWithReason : Budget { - [JsonPropertyName("reason")] - public string? Reason { get; set; } -} - public class BudgetWithHistory { [JsonPropertyName("budget")] public double Amount { get; set; } @@ -186,5 +181,5 @@ public class BudgetHistoryEntry { public string Reason { get; set; } [JsonPropertyName("createdAt")] - public DateTime CreatedAt { get; set; } + public DateTime? CreatedAt { get; set; } } \ No newline at end of file diff --git a/testFrontend/SafeNSound.Sdk/WrappedHttpClient.cs b/testFrontend/SafeNSound.Sdk/WrappedHttpClient.cs index aa785cd..49bd212 100644 --- a/testFrontend/SafeNSound.Sdk/WrappedHttpClient.cs +++ b/testFrontend/SafeNSound.Sdk/WrappedHttpClient.cs @@ -337,7 +337,7 @@ public class WrappedHttpClient { var request = new HttpRequestMessage(HttpMethod.Delete, url) { - Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json") + Content = new StringContent(JsonSerializer.Serialize(payload, GetJsonSerializerOptions()), Encoding.UTF8, "application/json") }; return await SendAsync(request); } @@ -345,7 +345,7 @@ public class WrappedHttpClient public async Task PatchAsJsonAsync(string url, T payload) { var request = new HttpRequestMessage(HttpMethod.Patch, url) { - Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json") + Content = new StringContent(JsonSerializer.Serialize(payload, GetJsonSerializerOptions()), Encoding.UTF8, "application/json") }; return await SendAsync(request); } diff --git a/testFrontend/SafeNSound.sln.DotSettings.user b/testFrontend/SafeNSound.sln.DotSettings.user index 43e3164..1235bc1 100644 --- a/testFrontend/SafeNSound.sln.DotSettings.user +++ b/testFrontend/SafeNSound.sln.DotSettings.user @@ -1,6 +1,7 @@  ForceIncluded ForceIncluded + ForceIncluded ForceIncluded True True -- cgit 1.5.1