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; namespace AsbCloudInfrastructure.Services.SAUB; class TelemetryNewDataSaubDto : TelemetryDataSaubDto { public new DateTimeOffset DateTime { get; set; } } public class TelemetryDataSaubService : TelemetryDataBaseService, ITelemetryDataSaubService { private readonly ITelemetryUserService telemetryUserService; public TelemetryDataSaubService( IAsbCloudDbContext db, ITelemetryService telemetryService, ITelemetryUserService telemetryUserService, ITelemetryDataCache telemetryDataCache) : base(db, telemetryService, telemetryDataCache) { this.telemetryUserService = telemetryUserService; } public async Task> 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() .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> GetMinAndMaxWellDepths(IEnumerable idsTelemetries, DateTimeOffset geDate, DateTimeOffset leDate, CancellationToken token) { var geDateUtc = geDate.ToUniversalTime(); var leDateUtc = leDate.ToUniversalTime(); var query = db.Set() .Where(t => idsTelemetries.Contains(t.IdTelemetry)) .Where(t => t.DateTime >= geDateUtc) .Where(t => t.DateTime <= leDateUtc) .GroupBy(t => t.IdTelemetry); var result = await query .ToDictionaryAsync(t => t.Key, t => ( t.MinBy(x => x.WellDepth)!.WellDepth, t.MaxBy(x => x.WellDepth)!.WellDepth )); return result; } public async Task> 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() .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(); 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(); 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 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(); serializer.Serialize(data, entryStream); } outStream.Seek(0, SeekOrigin.Begin); return outStream; } }