Files
parr_api/PARR.API/Controllers/V1/Statistics/StatRobotStateController.cs

193 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FluentValidation;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
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.Services.Interfaces;
using PARR.API.Settings;
using PARR.Constants;
using PARR.DAL.InfluxDbServices;
using PARR.DAL.Settings;
namespace PARR.API.Controllers.V1.Statistics
{
/// <summary>
/// Статистика доступности роботов
/// </summary>
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
public class StatRobotStateController : BaseApiController
{
private readonly IInfluxDbService influxDbService;
private readonly IValidator<RobotStateRequest> validator;
private readonly InfluxDbSettings influxDbSettings;
private readonly MonitoringSettings monitoringSettings;
private readonly IClientService clientService;
public StatRobotStateController(
IInfluxDbService influxDbService,
IValidator<RobotStateRequest> validator,
InfluxDbSettings influxDbSettings,
MonitoringSettings monitoringSettings,
IClientService clientService
)
{
this.influxDbService = influxDbService;
this.validator = validator;
this.influxDbSettings = influxDbSettings;
this.monitoringSettings = monitoringSettings;
this.clientService = clientService;
}
/// <summary>
/// Доступность робота
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.StatRobotState.Get)]
public async Task<IActionResult> 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<ErrorModel> { new ErrorModel { Message = $"Ошибка при получении статистики. Неверно указаны настройки мониторинга." } }));
// var inaccessibilityTime = TimeSpan.Parse("00:03:00");
var inaccessibilityTime = robotSettings.InaccessibilityTime;
var result = await influxDbService.QueryAsync(async handler =>
{
//var flux = "from(bucket:\"robots\") " +
// "|> range(start: 0) " +
// "|> filter(fn: (r) => " +
// "r._measurement == \"altitude\" and " +
// "r._value > 3500)";
var query = $"from(bucket:\"{influxDbSettings.Robots!.Bucket}\") " +
//$"|> range(start: -3h) " +
$"|> range(start: {startAt}) " +
$"|> filter(fn: (r) => " +
$"r._measurement == \"robots\" " +
$"and r.robot == \"{robot.ToString()}\"" +
$")";
var tables = await handler.QueryAsync(query, influxDbSettings.Organization);
return tables.SelectMany(table =>
table.Records.Select(record => new StatRobotStateResponse
{
Date = (DateTimeOffset)record.GetTimeInDateTime(),
IsUp = int.Parse(record.GetValue()?.ToString() ?? "0"),
Ip = record.GetValueByKey("ip")?.ToString()
})
);
}, influxDbSettings.Robots!.Token);
if (result == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при получении статистики" } }));
var listWithInaccessTime = CalcInaccessTime(result.ToList(), inaccessibilityTime);
return Ok(new Response<List<StatRobotStateResponse>>(listWithInaccessTime, true));
}
/// <summary>
/// Статистика доступности роботов. Передать инф-у о доступности
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.StatRobotState.Send)]
public async Task<IActionResult> Send([FromBody] RobotStateRequest request)
{
var resultValidate = await validator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
var result = influxDbService.Write(write =>
{
var point = PointData.Measurement("robots")
.Tag("robot", request.Robot.ToString())
.Tag("ip", clientService.GetClientIp()?.ToString())
//.Field("robot", (int)request.Robot)
.Field("isUp", 1)
.Timestamp(DateTime.UtcNow, WritePrecision.Ns);
write.WritePoint(point, bucket: influxDbSettings.Robots!.Bucket, org: influxDbSettings.Organization);
}, influxDbSettings.Robots!.Token);
if (!result)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при отправке данных" } }));
return Ok(new Response<string>("", true));
}
/// <summary>
/// Рассчитывает время когда робот был недоступен
/// </summary>
/// <param name="data"></param>
/// <param name="inaccessibilityTime"></param>
/// <returns></returns>
private List<StatRobotStateResponse> CalcInaccessTime(List<StatRobotStateResponse> data, TimeSpan inaccessibilityTime)
{
var inaccessTimeList = new List<StatRobotStateResponse>();
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();
}
}
}