Получение данных от ГТИ

1. Добавлен новый Dto
2. Обновлён репозиторий
3. Обновление API
This commit is contained in:
Степанов Дмитрий 2024-04-04 07:41:00 +03:00
parent 8c9bce8d18
commit c4bb5f9040
8 changed files with 480 additions and 2 deletions

View File

@ -0,0 +1,214 @@
namespace AsbCloudApp.Data.GTR;
public class GtrWitsDto
{
/// <summary>
/// Вес на крюке
/// </summary>
public float? HKLA { get; set; }
/// <summary>
/// Высота крюка
/// </summary>
public float? BLKPOS { get; set; }
/// <summary>
/// Нагрузка на долото
/// </summary>
public float? WOBA { get; set; }
/// <summary>
/// Момент на роторе/ВСП
/// </summary>
public float? TORQA { get; set; }
/// <summary>
/// Давление на входе (на стояке)
/// </summary>
public float? SPPA { get; set; }
/// <summary>
/// Обороты ротора/ВСП
/// </summary>
public float? RPMA { get; set; }
/// <summary>
/// Механическая скорость
/// </summary>
public float? ROPA { get; set; }
/// <summary>
/// Скорость инструмента вверх
/// </summary>
public float? RSUX { get; set; }
/// <summary>
/// Скорость инструмента вниз
/// </summary>
public float? RSDX { get; set; }
/// <summary>
/// Расход на входе
/// </summary>
public float? MFIA { get; set; }
/// <summary>
/// Расход на выходе
/// </summary>
public float? MFOA { get; set; }
/// <summary>
/// Температура на входе
/// </summary>
public float? MTIA { get; set; }
/// <summary>
/// Температура на выходе
/// </summary>
public float? MTOA { get; set; }
/// <summary>
/// Ходы насоса №1
/// </summary>
public float? SPM1 { get; set; }
/// <summary>
/// Ходы насоса №2
/// </summary>
public float? SPM2 { get; set; }
/// <summary>
/// Ходы насоса №3
/// </summary>
public float? SPM3 { get; set; }
/// <summary>
/// Общий объем бурового раствора на поверхности
/// </summary>
public float? TVOLACT { get; set; }
/// <summary>
/// Объем бурового раствора в доливной емкости №1
/// </summary>
public float? TTVOL1 { get; set; }
/// <summary>
/// Объем бурового раствора в доливной емкости №2
/// </summary>
public float? TTVOL2 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №1
/// </summary>
public float? TVOL01 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №2
/// </summary>
public float? TVOL02 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №3
/// </summary>
public float? TVOL03 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №4
/// </summary>
public float? TVOL04 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №5
/// </summary>
public float? TVOL05 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №6
/// </summary>
public float? TVOL06 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №7
/// </summary>
public float? TVOL07 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №8
/// </summary>
public float? TVOL08 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №9
/// </summary>
public float? TVOL09 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №10
/// </summary>
public float? TVOL10 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №11
/// </summary>
public float? TVOL11 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №12
/// </summary>
public float? TVOL12 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №13
/// </summary>
public float? TVOL13 { get; set; }
/// <summary>
/// Объем бурового раствора в емкости №14
/// </summary>
public float? TVOL14 { get; set; }
/// <summary>
/// Плотность (удельный вес) бурового раствора на выходе
/// </summary>
public float? MDOA { get; set; }
/// <summary>
/// Плотность (удельный вес) бурового раствора на входе
/// </summary>
public float? MDIA { get; set; }
/// <summary>
/// Процентное содержание метана
/// </summary>
public float? METHANE { get; set; }
/// <summary>
/// Процентное содержание этана
/// </summary>
public float? ETHANE { get; set; }
/// <summary>
/// Процентное содержание пропана
/// </summary>
public float? PROPANE { get; set; }
/// <summary>
/// Процентное содержание бутана
/// </summary>
public float? IBUTANE { get; set; }
/// <summary>
/// Процентное содержание пентана
/// </summary>
public float? NBUTANE { get; set; }
/// <summary>
/// Процентное содержание углеводородов
/// </summary>
public float? HydrocarbonPercentage => METHANE + ETHANE + PROPANE + IBUTANE + NBUTANE;
/// <summary>
/// Процентное содержание газов
/// </summary>
public float? GASA { get; set; }
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Repositories namespace AsbCloudApp.Repositories
{ {
@ -19,6 +20,14 @@ namespace AsbCloudApp.Repositories
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task SaveDataAsync(int idTelemetry, IEnumerable<WitsRecordDto> dtos, CancellationToken token); Task SaveDataAsync(int idTelemetry, IEnumerable<WitsRecordDto> dtos, CancellationToken token);
/// <summary>
/// получить данные ГТИ
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<GtrWitsDto>> GetAsync(GtrRequest request, CancellationToken token);
/// <summary> /// <summary>
/// получить данные для клиента /// получить данные для клиента
@ -29,6 +38,7 @@ namespace AsbCloudApp.Repositories
/// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param> /// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
[Obsolete]
Task<IEnumerable<WitsRecordDto>> GetAsync(int idWell, Task<IEnumerable<WitsRecordDto>> GetAsync(int idWell,
DateTime? dateBegin, double intervalSec = 600d, DateTime? dateBegin, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default); int approxPointsCount = 1024, CancellationToken token = default);
@ -39,6 +49,7 @@ namespace AsbCloudApp.Repositories
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <param name="idRecord"></param> /// <param name="idRecord"></param>
/// <returns></returns> /// <returns></returns>
[Obsolete]
IEnumerable<WitsItemRecordDto> GetLastDataByRecordId(int idWell, int idRecord); IEnumerable<WitsItemRecordDto> GetLastDataByRecordId(int idWell, int idRecord);
/// <summary> /// <summary>
@ -46,6 +57,7 @@ namespace AsbCloudApp.Repositories
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <returns></returns> /// <returns></returns>
[Obsolete]
IEnumerable<WitsItemRecordDto> GetLastData(int idWell); IEnumerable<WitsItemRecordDto> GetLastData(int idWell);
} }
} }

View File

@ -5,7 +5,7 @@ namespace AsbCloudApp.Requests;
/// <summary> /// <summary>
/// Параметры запроса для получения загруженных данных ГТИ по скважине /// Параметры запроса для получения загруженных данных ГТИ по скважине
/// </summary> /// </summary>
public class GtrWithGetDataRequest public class GtrRequestBase
{ {
/// <summary> /// <summary>
/// Дата начала выборки.По умолчанию: текущее время - IntervalSec /// Дата начала выборки.По умолчанию: текущее время - IntervalSec
@ -20,5 +20,22 @@ public class GtrWithGetDataRequest
/// <summary> /// <summary>
/// Желаемое количество точек. Если в выборке точек будет больше, то выборка будет прорежена. /// Желаемое количество точек. Если в выборке точек будет больше, то выборка будет прорежена.
/// </summary> /// </summary>
[Obsolete]
public int ApproxPointsCount { get; set; } = 1024; public int ApproxPointsCount { get; set; } = 1024;
}
/// <summary>
/// Параметры запроса для получения загруженных данных ГТИ по скважине
/// </summary>
public class GtrRequest : GtrRequestBase
{
public GtrRequest(int idWell, GtrRequestBase request)
{
IdWell = idWell;
Begin = request.Begin;
IntervalSec = request.IntervalSec;
ApproxPointsCount = request.ApproxPointsCount;
}
public int IdWell { get; set; }
} }

View File

@ -12,11 +12,58 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
using Mapster;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository
{ {
public class GtrWitsRepository : IGtrRepository public class GtrWitsRepository : IGtrRepository
{ {
private static IDictionary<(int, int), string> WitsParameters = new Dictionary<(int, int), string>
{
{ (1, 14), nameof(GtrWitsDto.HKLA) },
{ (1, 12), nameof(GtrWitsDto.BLKPOS) },
{ (1, 16), nameof(GtrWitsDto.WOBA) },
{ (1, 18), nameof(GtrWitsDto.TORQA) },
{ (1, 21), nameof(GtrWitsDto.SPPA) },
{ (2, 15), nameof(GtrWitsDto.RPMA) },
{ (1, 13), nameof(GtrWitsDto.ROPA) },
{ (3, 16), nameof(GtrWitsDto.RSUX) },
{ (3, 17), nameof(GtrWitsDto.RSDX) },
{ (1, 30), nameof(GtrWitsDto.MFIA) },
{ (1, 29), nameof(GtrWitsDto.MFOA)},
{ (1, 34), nameof(GtrWitsDto.MTIA) },
{ (1, 33), nameof(GtrWitsDto.MTOA) },
{ (1, 23), nameof(GtrWitsDto.SPM1) },
{ (1, 24), nameof(GtrWitsDto.SPM2) },
{ (1, 25), nameof(GtrWitsDto.SPM3) },
{ (1, 26), nameof(GtrWitsDto.TVOLACT) },
{ (11, 29), nameof(GtrWitsDto.TTVOL1) },
{ (11, 30), nameof(GtrWitsDto.TTVOL2) },
{ (11, 15), nameof(GtrWitsDto.TVOL01) },
{ (11, 16), nameof(GtrWitsDto.TVOL02) },
{ (11, 17), nameof(GtrWitsDto.TVOL03) },
{ (11, 18), nameof(GtrWitsDto.TVOL04) },
{ (11, 19), nameof(GtrWitsDto.TVOL05) },
{ (11, 20), nameof(GtrWitsDto.TVOL06) },
{ (11, 21), nameof(GtrWitsDto.TVOL07) },
{ (11, 22), nameof(GtrWitsDto.TVOL08) },
{ (11, 23), nameof(GtrWitsDto.TVOL09) },
{ (11, 24), nameof(GtrWitsDto.TVOL10) },
{ (11, 25), nameof(GtrWitsDto.TVOL11) },
{ (11, 26), nameof(GtrWitsDto.TVOL12) },
{ (11, 27), nameof(GtrWitsDto.TVOL13) },
{ (11, 28), nameof(GtrWitsDto.TVOL14) },
{ (1, 31), nameof(GtrWitsDto.MDOA) },
{ (1, 32), nameof(GtrWitsDto.MDIA) },
{ (12, 12), nameof(GtrWitsDto.METHANE) },
{ (12, 13), nameof(GtrWitsDto.ETHANE) },
{ (12, 14), nameof(GtrWitsDto.PROPANE) },
{ (12, 15), nameof(GtrWitsDto.IBUTANE) },
{ (12, 16), nameof(GtrWitsDto.NBUTANE) },
{ (1, 40), nameof(GtrWitsDto.GASA) },
};
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private static ConcurrentDictionary<int, ConcurrentDictionary<(int, int), WitsItemRecordDto>> cache = new(); private static ConcurrentDictionary<int, ConcurrentDictionary<(int, int), WitsItemRecordDto>> cache = new();
@ -28,6 +75,48 @@ namespace AsbCloudInfrastructure.Repository
this.db = db; this.db = db;
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
} }
public async Task<IEnumerable<GtrWitsDto>> GetAsync(GtrRequest request, CancellationToken token)
{
var interval = TimeSpan.FromSeconds(10);
var query = BuildQuery<WitsItemFloat, float>(request);
var entities = await query.AsNoTracking().ToArrayAsync(token);
var dtos = entities
.GroupBy(e => e.DateTime.Ticks / interval.Ticks)
.Select(Convert);
return dtos;
}
private static GtrWitsDto Convert(IEnumerable<WitsItemFloat> scr)
{
var values = scr.GroupBy(e => (e.IdRecord, e.IdItem))
.ToDictionary(g => WitsParameters[g.Key], g => g.LastOrDefault()?.Value);
var dto = values.Adapt<GtrWitsDto>();
return dto;
}
private IQueryable<TEntity> BuildQuery<TEntity, TType>(GtrRequest request)
where TEntity : WitsItemBase<TType>
where TType : notnull
{
var query = db.Set<TEntity>().OrderBy(e => e.DateTime)
.Where(e => e.Telemetry != null &&
e.Telemetry.Well != null &&
e.Telemetry.Well.Id == request.IdWell)
.Where(e => e.DateTime >= DateTime.UtcNow.AddSeconds(-request.IntervalSec));
if (request.Begin.HasValue)
{
var dateBeginUtc = request.Begin.Value.ToUniversalTime();
query = query.Where(e => e.DateTime >= dateBeginUtc);
}
return query;
}
public async Task<IEnumerable<WitsRecordDto>> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default) public async Task<IEnumerable<WitsRecordDto>> GetAsync(int idWell, DateTime? dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
{ {

View File

@ -0,0 +1,13 @@
using AsbCloudApp.Data.GTR;
using AsbCloudApp.Requests;
using Refit;
namespace AsbCloudWebApi.IntegrationTests.Clients;
public interface IGtrWitsClient
{
private const string BaseRoute = "/api/well/{idWell}/gtrWits";
[Get(BaseRoute)]
Task<IApiResponse<IEnumerable<GtrWitsDto>>> GetAllAsync(int idWell, [Query] GtrRequestBase request);
}

View File

@ -0,0 +1,68 @@
using System.Net;
using AsbCloudApp.Requests;
using AsbCloudDb.Model.GTR;
using AsbCloudWebApi.IntegrationTests.Clients;
using Xunit;
namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class GtrControllerTests : BaseIntegrationTest
{
private readonly IGtrWitsClient client;
public GtrControllerTests(WebAppFactoryFixture factory)
: base(factory)
{
client = factory.GetAuthorizedHttpClient<IGtrWitsClient>(string.Empty);
}
[Fact]
public async Task GetAll_returns_success()
{
//arrange
var well = dbContext.Wells.First();
var witsItems = CreateWitsItems(well.IdTelemetry!.Value);
dbContext.WitsItemFloat.AddRange(witsItems);
await dbContext.SaveChangesAsync();
var request = new GtrRequestBase();
//act
var response = await client.GetAllAsync(well.Id, request);
//assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(response.Content);
Assert.True(response.Content.Any());
}
private static IEnumerable<WitsItemFloat> CreateWitsItems(int idTelemetry) =>
new[]
{
new WitsItemFloat
{
IdRecord = 1,
IdItem = 14,
Value = 4,
IdTelemetry = idTelemetry,
DateTime = DateTimeOffset.UtcNow
},
new WitsItemFloat
{
IdRecord = 1,
IdItem = 14,
Value = 5,
IdTelemetry = idTelemetry,
DateTime = DateTimeOffset.UtcNow
},
new WitsItemFloat
{
IdRecord = 1,
IdItem = 12,
Value = 5,
IdTelemetry = idTelemetry,
DateTime = DateTimeOffset.UtcNow.AddSeconds(10)
}
};
}

View File

@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data.GTR;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers;
[ApiController]
[Route("api/well/{idWell}/[controller]")]
[Authorize]
public class GtrWitsController : ControllerBase
{
private readonly IWellService wellService;
private readonly IGtrRepository gtrRepository;
public GtrWitsController(IWellService wellService,
IGtrRepository gtrRepository)
{
this.wellService = wellService;
this.gtrRepository = gtrRepository;
}
/// <summary>
/// Получить значение от ГТИ
/// </summary>
/// <param name="idWell"></param>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
[Permission]
[ProducesResponseType(typeof(IEnumerable<GtrWitsDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAllAsync(int idWell, [FromQuery] GtrRequestBase request, CancellationToken token)
{
await AssertUserHasAccessToWellAsync(idWell, token);
var requestToRepository = new GtrRequest(idWell, request);
var dtos = await gtrRepository.GetAsync(requestToRepository, token);
return Ok(dtos);
}
private async Task AssertUserHasAccessToWellAsync(int idWell, CancellationToken token)
{
var idUser = User.GetUserId();
var idCompany = User.GetCompanyId();
if (!idUser.HasValue)
throw new ForbidException("Нет доступа к скважине");
if (!idCompany.HasValue)
throw new ForbidException("Нет доступа к скважине");
if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value, idWell, token))
throw new ForbidException("Нет доступа к скважине");
}
}

View File

@ -46,7 +46,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
/// <returns></returns> /// <returns></returns>
[HttpGet("{idWell}")] [HttpGet("{idWell}")]
public async Task<ActionResult<IEnumerable<WitsRecordDto>>> GetDataAsync([Required] int idWell, public async Task<ActionResult<IEnumerable<WitsRecordDto>>> GetDataAsync([Required] int idWell,
[FromQuery] GtrWithGetDataRequest request, [FromQuery] GtrRequest request,
CancellationToken token) CancellationToken token)
{ {
int? idCompany = User.GetCompanyId(); int? idCompany = User.GetCompanyId();