DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs

193 lines
7.6 KiB
C#

using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.Csv;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
namespace AsbCloudInfrastructure.Services.SAUB;
class TelemetryNewDataSaubDto : TelemetryDataSaubDto
{
public new DateTimeOffset DateTime { get; set; }
}
public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSaubDto, TelemetryDataSaub>, ITelemetryDataSaubService
{
private readonly ITelemetryUserService telemetryUserService;
public TelemetryDataSaubService(
IAsbCloudDbContext db,
ITelemetryService telemetryService,
ITelemetryUserService telemetryUserService,
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
: base(db, telemetryService, telemetryDataCache)
{
this.telemetryUserService = telemetryUserService;
}
public async Task<IEnumerable<TelemetryDataSaubDto>> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token)
{
var offset = telemetryService.GetTimezone(idTelemetry).Offset;
var geDateUtc = geDate.ToUniversalTime();
var leDateUtc = leDate.ToUniversalTime();
var query = db.Set<TelemetryDataSaub>()
.Where(t => t.IdTelemetry == idTelemetry)
.Where(t => t.DateTime >= geDateUtc)
.Where(t => t.DateTime <= leDateUtc);
if (isBitOnBottom)
query = query.Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001);
query = query
.OrderBy(t => t.DateTime)
.Take(take);
var entities = await query.ToArrayAsync(token);
var dtos = entities.Select(e => Convert(e, offset.TotalHours));
return dtos;
}
public async Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token)
{
var timezone = telemetryService.GetTimezone(idTelemetry);
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
int[] modes = new int[] { 0, 1, 3 };
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(1.5));
var query = db.Set<TelemetryDataSaub>()
.Where(t => t.IdTelemetry == idTelemetry)
.Where(t => t.BlockPosition > 0.0001)
.Where(t => t.WellDepth > 0.0001)
.Where(t => modes.Contains(t.Mode))
.Where(t => t.WellDepth - t.BitDepth < 0.01)
.GroupBy(t => new
{
t.DateTime.Hour,
WellDepthX10 = Math.Truncate(t.WellDepth * 10),
t.Mode,
t.IdFeedRegulator
})
.Select(g => new TelemetryDataSaubStatDto
{
Count = g.Count(),
IdMode = g.Key.Mode,
IdFeedRegulator = g.Key.IdFeedRegulator,
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
WellDepthMin = g.Min(t => t.WellDepth),
WellDepthMax = g.Max(t => t.WellDepth),
Pressure = g.Average(t => t.Pressure),
PressureSp = g.Average(t => t.PressureSp!.Value),
PressureIdle = g.Average(t => t.PressureIdle!.Value),
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
PressureDelta = g.Average(t => t.Pressure - t.PressureIdle!.Value),
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
AxialLoad = g.Average(t => t.AxialLoad),
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
RotorTorque = g.Average(t => t.RotorTorque),
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
})
.Where(s => s.WellDepthMin != s.WellDepthMax)
.Where(s => s.Count > 3)
.OrderBy(t => t.DateMin);
return await query.ToArrayAsync(token);
}
protected override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)
{
var entity = src.Adapt<TelemetryDataSaub>();
var telemetryUser = telemetryUserService
.GetUsers(src.IdTelemetry, u => (u.Name == src.User || u.Surname == src.User))
.FirstOrDefault();
entity.IdUser = telemetryUser?.Id;
entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset);
return entity;
}
protected override TelemetryDataSaubDto Convert(TelemetryDataSaub src, double timezoneOffset)
{
var dto = src.Adapt<TelemetryDataSaubDto>();
var telemetryUser = telemetryUserService.GetOrDefault(src.IdTelemetry, src.IdUser ?? int.MinValue);
dto.User = telemetryUser?.MakeDisplayName();
dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset);
dto.BitDepth = src.BitDepth <= src.WellDepth
? src.BitDepth
: src.WellDepth;
return dto;
}
public async Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
{
double intervalSec = (endDate - beginDate).TotalSeconds;
if (intervalSec > 60 * 60 * 24 * 3)
throw new ArgumentInvalidException(nameof(endDate), "Слишком большой диапазон");
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина id:{idWell} не содержит телеметрии");
var approxPointsCount = intervalSec switch
{
< 2048 => 2048,
< 8_192 => 4_096,
< 131_072 => 16_384,
_ => 32_768
};
var data = await GetByWellAsync(idWell, beginDate, intervalSec, approxPointsCount, token);
var fileName = $"DataSaub idWell{idWell}";
if (telemetry.Info is not null)
fileName += $" {telemetry.Info?.Cluster}, {telemetry.Info?.Well}";
fileName += $" {beginDate:yyyy-MM-DDTHH-mm} - {endDate:yyyy-MM-DDTHH-mm}.csv";
var outStream = new MemoryStream();
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var entryFile = archive.CreateEntry(fileName, CompressionLevel.Optimal);
using var entryStream = entryFile.Open();
var serializer = new CsvSerializer<TelemetryDataSaubDto>();
serializer.Serialize(data, entryStream);
}
outStream.Seek(0, SeekOrigin.Begin);
return outStream;
}
protected override IQueryable<TelemetryDataSaub> BuildQuery(int idTelemetry, TelemetryDataRequest request)
{
var query = base.BuildQuery(idTelemetry, request);
if (request.GeBlockPosition.HasValue)
query = query.Where(e => e.BlockPosition >= request.GeBlockPosition);
if (request.LeBlockPosition.HasValue)
query = query.Where(e => e.BlockPosition <= request.LeBlockPosition);
return query;
}
}