From 9dde13ceaef2ce70e58bb84a47ad7fba9796e6a7 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Wed, 29 May 2024 11:09:31 +1000 Subject: [PATCH] =?UTF-8?q?feat(api):=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0=D1=82=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=20=D1=80=D0=BE=D0=B1=D0=BE=D1=82=D0=BE=D0=B2?= =?UTF-8?q?,=20StatRobotStateController=20->=20Get?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../V1/Requests/Queries/RobotStateGetQuery.cs | 9 +- .../Statistics/StatRobotStateResponse.cs | 9 ++ .../V1/Statistics/StatRobotStateController.cs | 100 +++++++++++++++--- PARR.API/Installers/SettingsInstaller.cs | 6 ++ PARR.API/Settings/MonitoringSettings.cs | 14 +++ PARR.API/appsettings.json | 20 ++++ 6 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 PARR.API/Contracts/V1/Responses/Statistics/StatRobotStateResponse.cs create mode 100644 PARR.API/Settings/MonitoringSettings.cs diff --git a/PARR.API/Contracts/V1/Requests/Queries/RobotStateGetQuery.cs b/PARR.API/Contracts/V1/Requests/Queries/RobotStateGetQuery.cs index 963e70b2..f107ac8f 100644 --- a/PARR.API/Contracts/V1/Requests/Queries/RobotStateGetQuery.cs +++ b/PARR.API/Contracts/V1/Requests/Queries/RobotStateGetQuery.cs @@ -2,7 +2,12 @@ { public class RobotStateGetQuery { - public DateTimeOffset? DateStart { get; set; } - public DateTimeOffset? DateEnd { get; set; } + //public DateTimeOffset? DateStart { get; set; } + //public DateTimeOffset? DateEnd { get; set; } + + /// + /// Начало данных (-3d, -2h, -15m). По умолчанию -2h + /// + public string? StartAt { get; set; } } } diff --git a/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStateResponse.cs b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStateResponse.cs new file mode 100644 index 00000000..7695dacf --- /dev/null +++ b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStateResponse.cs @@ -0,0 +1,9 @@ +namespace PARR.API.Contracts.V1.Responses.Statistics +{ + public class StatRobotStateResponse + { + public DateTimeOffset Date { get; set; } + + public int IsUp { get; set; } + } +} diff --git a/PARR.API/Controllers/V1/Statistics/StatRobotStateController.cs b/PARR.API/Controllers/V1/Statistics/StatRobotStateController.cs index 60453e2e..561e8b63 100644 --- a/PARR.API/Controllers/V1/Statistics/StatRobotStateController.cs +++ b/PARR.API/Controllers/V1/Statistics/StatRobotStateController.cs @@ -7,7 +7,9 @@ using PARR.API.Contracts.V1; using PARR.API.Contracts.V1.Requests; using PARR.API.Contracts.V1.Requests.Queries; using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Contracts.V1.Responses.Statistics; using PARR.API.Controllers.V1.Base; +using PARR.API.Settings; using PARR.Constants; using PARR.DAL.InfluxDbServices; using PARR.DAL.Settings; @@ -23,16 +25,19 @@ namespace PARR.API.Controllers.V1.Statistics private readonly IInfluxDbService influxDbService; private readonly IValidator validator; private readonly InfluxDbSettings influxDbSettings; + private readonly MonitoringSettings monitoringSettings; public StatRobotStateController( IInfluxDbService influxDbService, IValidator validator, - InfluxDbSettings influxDbSettings + InfluxDbSettings influxDbSettings, + MonitoringSettings monitoringSettings ) { this.influxDbService = influxDbService; this.validator = validator; this.influxDbSettings = influxDbSettings; + this.monitoringSettings = monitoringSettings; } @@ -43,6 +48,15 @@ namespace PARR.API.Controllers.V1.Statistics [HttpGet(ApiRoutes.StatRobotState.Get)] public async Task Get([FromRoute] RobotsAllEnum robot, [FromQuery] RobotStateGetQuery query) { + var startAt = string.IsNullOrEmpty(query.StartAt) ? "-2h" : query.StartAt; + + var robotSettings = monitoringSettings.Robots.FirstOrDefault(t => t.Name == robot.ToString()); + if (robotSettings == null) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при получении статистики. Неверно указаны настройки мониторинга." } })); + + // var inaccessibilityTime = TimeSpan.Parse("00:03:00"); + var inaccessibilityTime = robotSettings.InaccessibilityTime; + var result = await influxDbService.QueryAsync(async handler => { @@ -53,7 +67,8 @@ namespace PARR.API.Controllers.V1.Statistics // "r._value > 3500)"; var query = $"from(bucket:\"{influxDbSettings.Robots!.Bucket}\") " + - $"|> range(start: -3h) " + + //$"|> range(start: -3h) " + + $"|> range(start: {startAt}) " + $"|> filter(fn: (r) => " + $"r._measurement == \"robots\" " + $"and r.robot == \"{robot.ToString()}\"" + @@ -62,28 +77,25 @@ namespace PARR.API.Controllers.V1.Statistics var tables = await handler.QueryAsync(query, influxDbSettings.Organization); - - //return tables.SelectMany(table => - // table.Records.Select(record => - // new AltitudeModel - // { - // Time = record.GetTime().ToString(), - // Altitude = int.Parse(record.GetValue()?.ToString() ?? "0") - // })); - - - return ""; + return tables.SelectMany(table => + table.Records.Select(record => new StatRobotStateResponse + { + Date = (DateTimeOffset)record.GetTimeInDateTime(), + IsUp = int.Parse(record.GetValue()?.ToString() ?? "0") + }) + ); }, influxDbSettings.Robots!.Token); if (result == null) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при получении статистики" } })); + var listWithInaccessTime = CalcInaccessTime(result.ToList(), inaccessibilityTime); - return Ok(); + + return Ok(new Response>(listWithInaccessTime, true)); } - /// /// Статистика доступности роботов. Передать инф-у о доступности /// @@ -112,5 +124,63 @@ namespace PARR.API.Controllers.V1.Statistics return Ok(new Response("", true)); } + + + /// + /// Рассчитывает время когда робот был недоступен + /// + /// + /// + /// + private List CalcInaccessTime(List data, TimeSpan inaccessibilityTime) + { + + var inaccessTimeList = new List(); + + DateTimeOffset? lastTime = null; + foreach (var item in data.OrderBy(t => t.Date)) + { + if (!lastTime.HasValue) + { + lastTime = item.Date; + continue; + } + + lastTime = lastTime.Value.Add(inaccessibilityTime); + while (lastTime < item.Date) + { + //есть время когда робот был недоступен, добаляем в список недоступности + inaccessTimeList.Add(new StatRobotStateResponse { Date = lastTime.Value, IsUp = 0 }); + lastTime = lastTime.Value.Add(inaccessibilityTime); + } + + // робот был доступен, все ок + lastTime = item.Date; + } + + + //if (lastTime == null) + //{ + // // не было вообще никакой статистики, считаем что он недоступен + // inaccessTimeList.Add(new StatRobotStateResponse { Date = DateTimeOffset.UtcNow, IsUp = 0 }); + //} + + // Проверяем, вдруг с последней даты активности до сейчас прошло уже много времени и он не доступен + if (lastTime.HasValue) + { + lastTime = lastTime.Value.Add(inaccessibilityTime); + while (lastTime.Value < DateTimeOffset.UtcNow) + { + inaccessTimeList.Add(new StatRobotStateResponse { Date = lastTime.Value, IsUp = 0 }); + lastTime = lastTime.Value.Add(inaccessibilityTime); + } + } + + + + data.AddRange(inaccessTimeList); + + return data.OrderBy(t => t.Date).ToList(); + } } } diff --git a/PARR.API/Installers/SettingsInstaller.cs b/PARR.API/Installers/SettingsInstaller.cs index 933cda6b..4ea53e8f 100644 --- a/PARR.API/Installers/SettingsInstaller.cs +++ b/PARR.API/Installers/SettingsInstaller.cs @@ -13,10 +13,16 @@ namespace PARR.API.Installers configuration.GetSection(nameof(MqSettings)).Bind(mqSettings); services.AddSingleton(mqSettings); + var userCacheSettings = new UserCacheSettings(); configuration.GetSection(nameof(UserCacheSettings)).Bind(userCacheSettings); services.AddSingleton(userCacheSettings); + + var monitoringSettings = new MonitoringSettings(); + configuration.GetSection(nameof(MonitoringSettings)).Bind(monitoringSettings); + services.AddSingleton(monitoringSettings); + //TODO: add other } } diff --git a/PARR.API/Settings/MonitoringSettings.cs b/PARR.API/Settings/MonitoringSettings.cs new file mode 100644 index 00000000..2070fcca --- /dev/null +++ b/PARR.API/Settings/MonitoringSettings.cs @@ -0,0 +1,14 @@ +namespace PARR.API.Settings +{ + public class MonitoringSettings + { + public List Robots { get; set; } = new List(); + } + + public class MonitoringRobotSettings + { + public required string Name { get; set; } + + public TimeSpan InaccessibilityTime { get; set; } + } +} diff --git a/PARR.API/appsettings.json b/PARR.API/appsettings.json index d20a9840..31ed1be8 100644 --- a/PARR.API/appsettings.json +++ b/PARR.API/appsettings.json @@ -68,5 +68,25 @@ "Bucket": "logons", "Token": "hjhOqZMAOm3UsAJURcROBvNqCRdR1Tp3jGYTdzduLXC4uSVrysjvEzLtM-n8jotdwuD7y0rxa2FzzOZKRGzKLg==" } + }, + "MonitoringSettings": { + "Robots": [ + { + "Name": "TemplateOrder", + "InaccessibilityTime": "00:03:00" + }, + { + "Name": "ScheduleOrder", + "InaccessibilityTime": "00:03:00" + }, + { + "Name": "TemplatesExport", + "InaccessibilityTime": "01:20:00" + }, + { + "Name": "ScheduleExport", + "InaccessibilityTime": "01:20:00" + } + ] } }