From d2eee41ed6764f1dcb97847fd942f78e209f7993 Mon Sep 17 00:00:00 2001 From: vasich Date: Thu, 11 Jul 2024 21:27:07 +0700 Subject: [PATCH] device client implemented --- .../API/DeviceEndpoints.cs | 18 +++++ .../API/SkillsEndpoints.cs | 3 +- .../Yuna.Website.Server/Model/Prop.cs | 1 + .../Yuna.Website.Server/Model/PropType.cs | 8 +++ .../Services/DeviceService/DeviceService.cs | 72 ++++++++++++++++++- .../Services/DeviceService/IDeviceService.cs | 1 + .../Repositories/Device/DeviceRepository.cs | 8 ++- .../Repositories/Prop/PropRepository.cs | 20 ++++-- 8 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 Yuna.Website/Yuna.Website.Server/Model/PropType.cs diff --git a/Yuna.Website/Yuna.Website.Server/API/DeviceEndpoints.cs b/Yuna.Website/Yuna.Website.Server/API/DeviceEndpoints.cs index f34d5e1..bc867c6 100644 --- a/Yuna.Website/Yuna.Website.Server/API/DeviceEndpoints.cs +++ b/Yuna.Website/Yuna.Website.Server/API/DeviceEndpoints.cs @@ -23,6 +23,11 @@ namespace Yuna.Website.Server.API app.MapGet("/api/device", GetAll) .WithTags("device"); + app.MapGet("/api/device/{deviceId:long}/fetch", FetchData) + .WithTags("device") + .Produces(404) + .Produces(200); + app.MapPut("/api/device/{deviceId:long}", AddSkillsToDevice) .WithTags("device"); } @@ -93,5 +98,18 @@ namespace Yuna.Website.Server.API if (result is null) return Results.NotFound("device"); return Results.Ok(result); } + + [Authorize] + public async Task FetchData(long deviceId, IDeviceService deviceService) + { + var device = await deviceService.GetById(deviceId); + if (device is null) return Results.NotFound("device"); + + + var result = await deviceService.FetchPropsData(device); + if (result is null) return Results.NotFound("props"); + + return Results.Ok(result); + } } } diff --git a/Yuna.Website/Yuna.Website.Server/API/SkillsEndpoints.cs b/Yuna.Website/Yuna.Website.Server/API/SkillsEndpoints.cs index 7cac740..c6e265a 100644 --- a/Yuna.Website/Yuna.Website.Server/API/SkillsEndpoints.cs +++ b/Yuna.Website/Yuna.Website.Server/API/SkillsEndpoints.cs @@ -51,7 +51,8 @@ namespace Yuna.Website.Server.API { JsonValueName = request.JsonValueName, MeasureName = request.MeasureName ?? "", - Name = request.Name + Name = request.Name, + Type = request.type.Equals("float") ? PropType.Float : PropType.Boolean }; var result = await skillService.Create(prop); diff --git a/Yuna.Website/Yuna.Website.Server/Model/Prop.cs b/Yuna.Website/Yuna.Website.Server/Model/Prop.cs index 6966272..3ef66a5 100644 --- a/Yuna.Website/Yuna.Website.Server/Model/Prop.cs +++ b/Yuna.Website/Yuna.Website.Server/Model/Prop.cs @@ -3,6 +3,7 @@ public class Prop { public long Id { get; set; } + public PropType Type { get; set; } public string Name { get; set; } = null!; public string MeasureName { get; set; } = null!; public string JsonValueName { get; set; } = null!; diff --git a/Yuna.Website/Yuna.Website.Server/Model/PropType.cs b/Yuna.Website/Yuna.Website.Server/Model/PropType.cs new file mode 100644 index 0000000..8120795 --- /dev/null +++ b/Yuna.Website/Yuna.Website.Server/Model/PropType.cs @@ -0,0 +1,8 @@ +namespace Yuna.Website.Server.Model +{ + public enum PropType + { + Float = 0, + Boolean = 1, + } +} diff --git a/Yuna.Website/Yuna.Website.Server/Services/DeviceService/DeviceService.cs b/Yuna.Website/Yuna.Website.Server/Services/DeviceService/DeviceService.cs index 1e7f058..9bae85c 100644 --- a/Yuna.Website/Yuna.Website.Server/Services/DeviceService/DeviceService.cs +++ b/Yuna.Website/Yuna.Website.Server/Services/DeviceService/DeviceService.cs @@ -4,6 +4,8 @@ using Yuna.Website.Server.Model; using Yuna.Website.Server.Services.DeviceSkillService; using Yuna.Website.Server.Storage.Repositories.Device; +using Microsoft.IdentityModel.Tokens; +using System.Text.Json; namespace Yuna.Website.Server.Services.DeviceService { @@ -11,10 +13,19 @@ namespace Yuna.Website.Server.Services.DeviceService { private readonly IPropService _propService; private readonly IDeviceRepository _deviceRepository; - public DeviceService(IPropService propService, IDeviceRepository repository) + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + public DeviceService( + IPropService propService, + IDeviceRepository repository, + IHttpClientFactory factory, + ILogger logger) { _propService = propService; _deviceRepository = repository; + _httpClientFactory = factory; + _logger = logger; + } public async Task AddProps(IReadOnlyList props, long deviceId) @@ -28,6 +39,65 @@ namespace Yuna.Website.Server.Services.DeviceService return device; } + public async Task?> FetchPropsData(Device device) + { + var result = new Dictionary(); + + if (device.Props.IsNullOrEmpty()) return result; + + var client = _httpClientFactory.CreateClient(device.DeviceUrl); + try + { + _logger.LogTrace("Trying to get data\n " + + "from device: {Id}\n" + + "via url: {DeviceUrl}", device.Id, device.DeviceUrl); + + var response = await client.GetAsync(device.DeviceUrl); + + _logger.LogTrace("Got response\n " + + "from device: {Id}\n" + + "via url: {DeviceUrl}", device.Id, device.DeviceUrl); + + var strContent = await response.Content.ReadAsStringAsync(); + + result = ParseDeviceJson(device.Props, strContent); + } + + catch (Exception ex) + { + _logger.LogError("Fail: {Message}", ex.Message); + return null; + } + + return result; + } + + private Dictionary ParseDeviceJson(IEnumerable props, string jsonStr) + { + var result = new Dictionary(); + + using JsonDocument responseJson = JsonDocument.Parse(jsonStr); + + foreach (var prop in props) + { + var propExists = responseJson.RootElement.TryGetProperty(prop.JsonValueName, out var propValue); + + if (!propExists) throw new Exception($"Unable to find jsonValue {prop.JsonValueName}, aborting"); + + if(propValue.TryGetDouble(out var value)) + { + result.Add(prop.Id, value.ToString()); + continue; + } + + result.Add(prop.Id, propValue.GetBoolean().ToString()!); + + _logger.LogTrace("Obtained value for {JsonValueName}", prop.JsonValueName); + } + + return result; + } + public async Task Create(Device device) { var result = await _deviceRepository.Create(device); diff --git a/Yuna.Website/Yuna.Website.Server/Services/DeviceService/IDeviceService.cs b/Yuna.Website/Yuna.Website.Server/Services/DeviceService/IDeviceService.cs index a05731a..448fccf 100644 --- a/Yuna.Website/Yuna.Website.Server/Services/DeviceService/IDeviceService.cs +++ b/Yuna.Website/Yuna.Website.Server/Services/DeviceService/IDeviceService.cs @@ -10,5 +10,6 @@ namespace Yuna.Website.Server.Services.DeviceService //public Task Update(User user); public Task Delete(long id); public Task AddProps(IReadOnlyList props, long deviceId); + public Task?> FetchPropsData(Device device); } } diff --git a/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Device/DeviceRepository.cs b/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Device/DeviceRepository.cs index bd3d412..8a00190 100644 --- a/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Device/DeviceRepository.cs +++ b/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Device/DeviceRepository.cs @@ -48,10 +48,12 @@ namespace Yuna.Website.Server.Storage.Repositories.Device d.""Id"" as {nameof(Model.Device.Id)}, d.""Name"" as {nameof(Model.Device.Name)}, d.""Description"" as {nameof(Model.Device.Description)}, + d.""DeviceUrl"" as {nameof(Model.Device.DeviceUrl)}, p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, - p.""MeasureName"" as {nameof(Model.Prop.MeasureName)} + p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Devices"" d LEFT JOIN ""Yuna_Props_In_Devices"" pd ON d.""Id"" = pd.""DeviceId"" LEFT JOIN ""Yuna_Props"" p ON pd.""PropId"" = p.""Id"" @@ -84,10 +86,12 @@ namespace Yuna.Website.Server.Storage.Repositories.Device d.""Id"" as {nameof(Model.Device.Id)}, d.""Name"" as {nameof(Model.Device.Name)}, d.""Description"" as {nameof(Model.Device.Description)}, + d.""DeviceUrl"" as {nameof(Model.Device.DeviceUrl)}, p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, - p.""MeasureName"" as {nameof(Model.Prop.MeasureName)} + p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Devices"" d LEFT JOIN ""Yuna_Props_In_Devices"" pd ON d.""Id"" = pd.""DeviceId"" LEFT JOIN ""Yuna_Props"" p ON pd.""PropId"" = p.""Id"""; diff --git a/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Prop/PropRepository.cs b/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Prop/PropRepository.cs index 9f3df7b..7e896e8 100644 --- a/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Prop/PropRepository.cs +++ b/Yuna.Website/Yuna.Website.Server/Storage/Repositories/Prop/PropRepository.cs @@ -15,9 +15,13 @@ namespace Yuna.Website.Server.Storage.Repositories.Prop { var query = $@"INSERT INTO ""Yuna_Props"" - (""Name"", ""MeasureName"", ""JsonValueName"") + (""Name"", ""MeasureName"", ""JsonValueName"", ""Type"" ) VALUES - (@{nameof(Model.Prop.Name)}, @{nameof(Model.Prop.MeasureName)}, @{nameof(Model.Prop.JsonValueName)}) + ( + @{nameof(Model.Prop.Name)}, + @{nameof(Model.Prop.MeasureName)}, + @{nameof(Model.Prop.JsonValueName)}, + @{nameof(Model.Prop.Type)}) RETURNING *"; var result = await _context.Connection.QuerySingleAsync(query, value); @@ -36,7 +40,8 @@ namespace Yuna.Website.Server.Storage.Repositories.Prop p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, - p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)} + p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Props"" p WHERE p.""Id"" = {id} LIMIT 1"; @@ -53,7 +58,8 @@ namespace Yuna.Website.Server.Storage.Repositories.Prop p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, - p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)} + p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Props"" p WHERE p.""Id"" IN ({idList})"; @@ -69,7 +75,8 @@ namespace Yuna.Website.Server.Storage.Repositories.Prop p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, - p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)} + p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Props"" p WHERE LOWER(p.""Name"") = '{value.ToLower()}' LIMIT 1"; @@ -85,7 +92,8 @@ namespace Yuna.Website.Server.Storage.Repositories.Prop p.""Id"" as {nameof(Model.Prop.Id)}, p.""Name"" as {nameof(Model.Prop.Name)}, p.""MeasureName"" as {nameof(Model.Prop.MeasureName)}, - p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)} + p.""JsonValueName"" as {nameof(Model.Prop.JsonValueName)}, + p.""Type"" as {nameof(Model.Prop.Type)} FROM ""Yuna_Props"" p"; var result = await _context.Connection.QueryAsync(query);