From b8462253b37de3febfd1e341f10512a0c1b19d61 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Mon, 23 Oct 2023 18:06:57 +0500 Subject: [PATCH 1/5] =?UTF-8?q?WellboreService=20=D0=BD=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0.=20=D0=9D=D0=B5?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D1=82=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudApp/Data/WellboreDto.cs | 2 +- AsbCloudApp/Requests/WellboreRequest.cs | 14 -- AsbCloudApp/Services/ITelemetryDataService.cs | 1 - AsbCloudApp/Services/IWellboreService.cs | 24 +-- .../Services/SAUB/TelemetryDataCache.cs | 17 +- .../Services/WellboreService.cs | 160 +++++++++++------- .../Controllers/WellboreController.cs | 69 ++------ 7 files changed, 137 insertions(+), 150 deletions(-) delete mode 100644 AsbCloudApp/Requests/WellboreRequest.cs diff --git a/AsbCloudApp/Data/WellboreDto.cs b/AsbCloudApp/Data/WellboreDto.cs index c153b14f..68c5695b 100644 --- a/AsbCloudApp/Data/WellboreDto.cs +++ b/AsbCloudApp/Data/WellboreDto.cs @@ -10,7 +10,7 @@ public class WellboreDto /// /// Скважина /// - public WellWithTimezoneDto Well { get; set; } = null!; + public WellDto Well { get; set; } = null!; /// /// Идентификатор diff --git a/AsbCloudApp/Requests/WellboreRequest.cs b/AsbCloudApp/Requests/WellboreRequest.cs deleted file mode 100644 index 32b4cbe2..00000000 --- a/AsbCloudApp/Requests/WellboreRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace AsbCloudApp.Requests; - -/// -/// Параметры запроса для ствола скважины -/// -public class WellboreRequest : RequestBase -{ - /// - /// Пары идентификаторов скважины и секции - /// - public IEnumerable<(int idWell, int? idSection)> Ids { get; set; } = null!; -} \ No newline at end of file diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index 58eeeb70..154986b4 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -42,7 +42,6 @@ namespace AsbCloudApp.Services /// /// /// - /// /// DatesRangeDto? GetRange(int idWell, DateTimeOffset start, DateTimeOffset end); diff --git a/AsbCloudApp/Services/IWellboreService.cs b/AsbCloudApp/Services/IWellboreService.cs index f42485ae..0b577ba5 100644 --- a/AsbCloudApp/Services/IWellboreService.cs +++ b/AsbCloudApp/Services/IWellboreService.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; -using AsbCloudApp.Requests; namespace AsbCloudApp.Services; @@ -11,20 +10,11 @@ namespace AsbCloudApp.Services; /// public interface IWellboreService { - /// - /// Получение ствола скважины - /// - /// - /// - /// - /// - Task GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken); - - /// - /// Получение стволов скважин - /// - /// - /// - /// - Task> GetWellboresAsync(WellboreRequest request, CancellationToken cancellationToken); + /// + /// Получение стволов скважин + /// + /// + /// + /// + Task> GetWellboresAsync(IEnumerable idsWells, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index b579c876..531ab8d9 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -20,7 +20,7 @@ namespace AsbCloudInfrastructure.Services.SAUB { class TelemetryDataCacheItem { - public TDto? FirstByDate { get; init; } + public TDto FirstByDate { get; init; } = default!; public CyclycArray LastData { get; init; } = null!; public double TimezoneHours { get; init; } = 5; } @@ -127,7 +127,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return items; } - public TDto? GetLastOrDefault(int idTelemetry) + public virtual TDto? GetLastOrDefault(int idTelemetry) { if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return default; @@ -150,6 +150,19 @@ namespace AsbCloudInfrastructure.Services.SAUB return new DatesRangeDto { From = from.Value, To = to }; } + public (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; + + if (!cacheItem.LastData.Any()) + return null; + + var last = cacheItem.LastData[^1]; + var first = cacheItem.FirstByDate; + return (first, last); + } + private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) where TEntity : class, AsbCloudDb.Model.ITelemetryData { diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 396243d6..9fd4080d 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -1,91 +1,135 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data; +using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudDb.Model; -using Mapster; +using AsbCloudInfrastructure.Services.SAUB; namespace AsbCloudInfrastructure.Services; public class WellboreService : IWellboreService { + const string WellboreNameFormat = " {0}"; private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; + private readonly TelemetryDataCache telemetryDataCache; - public WellboreService(IWellService wellService, IWellOperationRepository wellOperationRepository) + public WellboreService( + IWellService wellService, + IWellOperationRepository wellOperationRepository, + TelemetryDataCache telemetryDataCache) { this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; - } - - public async Task GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken) - { - var request = new WellboreRequest - { - Ids = new (int, int?)[] { (idWell, idSection) }, - Take = 1, - }; - var data = await GetWellboresAsync(request, cancellationToken); - return data.FirstOrDefault(); + this.telemetryDataCache = telemetryDataCache; } - public async Task> GetWellboresAsync(WellboreRequest request, + public async Task> GetWellboresAsync(IEnumerable idsWells, CancellationToken token) { - var wellbores = new List(request.Ids.Count()); - var skip = request.Skip ?? 0; - var take = request.Take ?? 10; + var wellRequest = new WellRequest { Ids = idsWells }; + var wells = await wellService.GetAsync(wellRequest, token); - var sections = wellOperationRepository.GetSectionTypes() - .ToDictionary(w => w.Id, w => w); + var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token); + var groupedSections = rowSections + .GroupBy(s => s.IdWell); - var ids = request.Ids.GroupBy(i => i.idWell, i => i.idSection); + var wellbores = wells + .SelectMany(well => { + var wellSections = groupedSections.FirstOrDefault(group => group.Key == well.Id); + if (wellSections is not null) + return MakeWellboreBySections(wellSections, well); + else + return MakeWellboreDefault(well); + }) + .OrderBy(w => w.Well.Id) + .ThenBy(w => w.Id); - var idsWells = request.Ids.Select(i => i.idWell); + return wellbores; + } - var allSections = await wellOperationRepository.GetSectionsAsync(idsWells, token); + private IEnumerable MakeWellboreDefault(WellDto well) + { + var wellbore = new WellboreDto { + Id = 1, + Name = string.Format(WellboreNameFormat, 1), + Well = well, + }; - foreach (var id in ids) + if(well.IdTelemetry is not null) { - var well = await wellService.GetOrDefaultAsync(id.Key, token); + var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value); + if (dataCache is not null) + { + wellbore.DateStart = dataCache.Value.First.DateTime; + wellbore.DepthStart = dataCache.Value.First.WellDepth!.Value; - if (well is null) - continue; - - var wellTimezoneOffset = TimeSpan.FromHours(well.Timezone.Hours); - - var wellFactSections = allSections - .Where(section => section.IdWell == id.Key) - .Where(section => section.IdType == WellOperation.IdOperationTypeFact); - - var idsSections = id - .Where(i => i.HasValue) - .Select(i => i!.Value); - - if (idsSections.Any()) - wellFactSections = wellFactSections - .Where(section => idsSections.Contains(section.IdWellSectionType)); - - var wellWellbores = wellFactSections.Select(section => new WellboreDto { - Id = section.IdWellSectionType, - Name = sections[section.IdWellSectionType].Caption, - Well = well.Adapt(), - DateStart = section.DateStart.ToOffset(wellTimezoneOffset), - DateEnd = section.DateEnd.ToOffset(wellTimezoneOffset), - DepthStart = section.DepthStart, - DepthEnd = section.DepthEnd, - }); - - wellbores.AddRange(wellWellbores); + wellbore.DateEnd = dataCache.Value.Last.DateTime; + wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value; + } } - return wellbores - .OrderBy(w => w.Well.Id).ThenBy(w => w.Id) - .Skip(skip).Take(take); - } + return new[] { wellbore }; + } + + private IEnumerable MakeWellboreBySections(IEnumerable sections, WellDto well) + { + var orderedSections = sections.OrderBy(s => s.DateStart); + var wellbores = new List(); + int wellboreId = 1; + + SectionByOperationsDto? preSection = null; + WellboreDto? wellbore = null; + + foreach (var section in orderedSections) + { + if (wellbore is null || wellbore.DepthEnd > section.DepthStart) + { + wellbore = new WellboreDto + { + Name = string.Format(WellboreNameFormat, wellboreId), + Id = wellboreId, + Well = well, + + DateStart = section.DateStart, + DateEnd = section.DateEnd, + DepthStart = section.DepthStart, + DepthEnd = section.DepthEnd, + }; + + wellbores.Add(wellbore); + wellboreId++; + + } + else + { + wellbore.DepthEnd = section.DepthEnd; + wellbore.DateEnd = section.DateEnd; + } + + preSection = section; + } + + if (wellbore is not null) + { + if (well.IdTelemetry is not null) + { + var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value); + if (dataCache is not null) + { + wellbore.DateStart = dataCache.Value.First.DateTime; + wellbore.DepthStart = dataCache.Value.First.WellDepth!.Value; + + wellbore.DateEnd = dataCache.Value.Last.DateTime; + wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value; + } + } + } + + return wellbores; + } } \ No newline at end of file diff --git a/AsbCloudWebApi/Controllers/WellboreController.cs b/AsbCloudWebApi/Controllers/WellboreController.cs index ba3a27cb..8b0a94bf 100644 --- a/AsbCloudWebApi/Controllers/WellboreController.cs +++ b/AsbCloudWebApi/Controllers/WellboreController.cs @@ -9,6 +9,7 @@ using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Org.BouncyCastle.Asn1.Ocsp; namespace AsbCloudWebApi.Controllers; @@ -26,66 +27,20 @@ public class WellboreController : ControllerBase { this.wellboreService = wellboreService; } - - /// - /// Получение ствола скважины - /// - /// Id скважины - /// Id типа секции скважины - /// - /// - [HttpGet("{idWell:int}/{idSection:int}")] - [ProducesResponseType(typeof(WellboreDto), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status204NoContent)] - public async Task GetAsync(int idWell, int idSection, CancellationToken cancellationToken) - { - var wellbore = await wellboreService.GetWellboreAsync(idWell, idSection, cancellationToken); - - if (wellbore is null) - return NoContent(); - - return Ok(wellbore); - } - - /// - /// Получение списка стволов скважин - /// - /// Пары идентификаторов скважины и секции - /// Опциональный параметр. Количество пропускаемых записей - /// Опциональный параметр. Количество получаемых записей - /// - /// - [HttpGet] + /// + /// Получение списка стволов скважин + /// + /// Идентификаторы скважин + /// + /// + [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task GetAllAsync([FromQuery] IEnumerable ids, - int? skip, - int? take, + public async Task GetAllAsync([FromQuery] IEnumerable idsWells, CancellationToken cancellationToken) - { - var request = new WellboreRequest - { - Ids = ids.Select(id => ParseId(id)), - Skip = skip, - Take = take - }; + { + var result = await wellboreService.GetWellboresAsync(idsWells, cancellationToken); - return Ok(await wellboreService.GetWellboresAsync(request, cancellationToken)); + return Ok(result); } - - private static (int, int?) ParseId(string id) - { - var idPair = id.Split(','); - if (!int.TryParse(idPair[0], out var idWell)) - throw new ArgumentInvalidException(nameof(id), $"Не удалось получить Id скважины \"{idPair[0]}\""); - - if (idPair.Length > 1) - { - if (int.TryParse(idPair[1], out int idWellSectionType)) - return (idWell, idWellSectionType); - else - throw new ArgumentInvalidException(nameof(id), $"Не удалось получить Id ствола \"{idPair[1]}\""); - } - return (idWell, null); - } } \ No newline at end of file From 8079b0b1c362dfbc7535567476ee1a50b9c962fc Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Tue, 24 Oct 2023 09:23:07 +0500 Subject: [PATCH 2/5] =?UTF-8?q?=D0=98=D0=B7=D0=B2=D0=BB=D0=B5=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D0=B8=D0=B7=20TelemetryDataCache=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/ITelemetryDataCache.cs | 62 +++++++++++++++++++ AsbCloudInfrastructure/DependencyInjection.cs | 4 +- .../Services/SAUB/TelemetryDataBaseService.cs | 5 +- .../Services/SAUB/TelemetryDataCache.cs | 36 ++++++----- .../Services/SAUB/TelemetryDataSaubService.cs | 3 +- .../Services/SAUB/TelemetryDataSpinService.cs | 3 +- .../Services/SAUB/TelemetryService.cs | 6 +- .../Services/WellInfoService.cs | 10 +-- .../OperationsStatService.cs | 7 ++- AsbCloudInfrastructure/Startup.cs | 5 +- 10 files changed, 106 insertions(+), 35 deletions(-) create mode 100644 AsbCloudApp/Repositories/ITelemetryDataCache.cs diff --git a/AsbCloudApp/Repositories/ITelemetryDataCache.cs b/AsbCloudApp/Repositories/ITelemetryDataCache.cs new file mode 100644 index 00000000..0bc73275 --- /dev/null +++ b/AsbCloudApp/Repositories/ITelemetryDataCache.cs @@ -0,0 +1,62 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Requests; +using System; +using System.Collections.Generic; + +namespace AsbCloudApp.Repositories +{ + /// + /// Хранилище кеша + /// + /// + public interface ITelemetryDataCache where TDto : ITelemetryData + { + /// + /// добавить в кеш чанк записей по телеметрии + /// + /// + /// + void AddRange(int idTelemetry, IEnumerable range); + + /// + /// вернуть последнюю записть + /// + /// + /// + TDto? GetLastOrDefault(int idTelemetry); + + /// + /// Получить кешированые записи + /// + /// + /// + /// + /// приблизительное кол-во возвращаемых записей после их прореживания + /// + IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600, int approxPointsCount = 1024); + + /// + /// Получить кешированые записи + /// + /// + /// + /// + IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request); + + /// + /// Получить диапазон дат телеметрии. + /// Дата первой записи телеметрии храниться отдельно и запоняется при инициализации + /// + /// + /// + DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry); + + /// + /// Получение первой и последней записи телеметрии. + /// Первая запись телеметрии храниться отдельно и запоняется при инициализации + /// + /// + /// + (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry); + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 85caf0b2..33d81cba 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -159,8 +159,8 @@ namespace AsbCloudInfrastructure services.AddScoped(provider => provider.GetRequiredService()); services.AddSingleton(new WitsInfoService()); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider)); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 32fc88a2..649f03de 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; @@ -18,12 +19,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { protected readonly IAsbCloudDbContext db; protected readonly ITelemetryService telemetryService; - protected readonly TelemetryDataCache telemetryDataCache; + protected readonly ITelemetryDataCache telemetryDataCache; public TelemetryDataBaseService( IAsbCloudDbContext db, ITelemetryService telemetryService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) { this.db = db; this.telemetryService = telemetryService; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 531ab8d9..055d742c 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -12,11 +12,11 @@ using AsbCloudInfrastructure.Background; using System.Threading; using AsbCloudApp.Data; using AsbCloudApp.Requests; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure.Services.SAUB { - public class TelemetryDataCache - where TDto : AsbCloudApp.Data.ITelemetryData + public class TelemetryDataCache : ITelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData { class TelemetryDataCacheItem { @@ -48,7 +48,8 @@ namespace AsbCloudInfrastructure.Services.SAUB instance = new TelemetryDataCache(); var worker = provider.GetRequiredService(); var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; - var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => { + var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => + { var db = provider.GetRequiredService(); await instance.InitializeCacheFromDBAsync(db, onProgress, token); }); @@ -85,13 +86,13 @@ namespace AsbCloudInfrastructure.Services.SAUB } else { - cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() - { + cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() + { FirstByDate = newItems.ElementAt(0), - LastData = new CyclycArray(activeWellCapacity) + LastData = new CyclycArray(activeWellCapacity) }); } - + cacheItem.LastData.AddRange(newItems); } @@ -107,14 +108,14 @@ namespace AsbCloudInfrastructure.Services.SAUB /// public IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) { - if(!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return null; var cacheLastData = cacheItem.LastData; if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin) return null; - + var dateEnd = dateBegin.AddSeconds(intervalSec); var items = cacheLastData .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); @@ -141,7 +142,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return null; var from = cacheItem.FirstByDate?.DateTime; - if(!cacheItem.LastData.Any()) + if (!cacheItem.LastData.Any()) return null; var to = cacheItem.LastData[^1].DateTime; @@ -190,10 +191,10 @@ namespace AsbCloudInfrastructure.Services.SAUB var idTelemetry = well.IdTelemetry!.Value; var hoursOffset = well.Timezone.Hours; - - onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count); + + onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); - if(cacheItem is not null) + if (cacheItem is not null) caches.TryAdd(idTelemetry, cacheItem); } @@ -225,7 +226,8 @@ namespace AsbCloudInfrastructure.Services.SAUB var dtos = entities .AsEnumerable() .Reverse() - .Select(entity => { + .Select(entity => + { var dto = entity.Adapt(); dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); return dto; @@ -247,12 +249,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return null; - + IEnumerable data = cacheItem.LastData; if (!data.Any()) return null; - + if (request.GeDate.HasValue) { var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); @@ -272,7 +274,7 @@ namespace AsbCloudInfrastructure.Services.SAUB var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); data = data.Where(d => d.DateTime >= request.LeDate); } - + if (request.Divider > 1) data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index afe89528..b9ce8d6c 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -1,6 +1,7 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; @@ -26,7 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB IAsbCloudDbContext db, ITelemetryService telemetryService, ITelemetryUserService telemetryUserService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) : base(db, telemetryService, telemetryDataCache) { this.telemetryUserService = telemetryUserService; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs index 78119d6b..dab1e851 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; @@ -11,7 +12,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryDataSpinService( IAsbCloudDbContext db, ITelemetryService telemetryService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) : base(db, telemetryService, telemetryDataCache) { } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs index 7aa4f6c5..a084e687 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; @@ -18,7 +19,8 @@ namespace AsbCloudInfrastructure.Services.SAUB { private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; - private readonly TelemetryDataCache dataSaubCache; + //TODO: методы использующие ITelemetryDataCache, скорее всего, тут не нужны + private readonly ITelemetryDataCache dataSaubCache; private readonly ITimezoneService timezoneService; public ITimezoneService TimeZoneService => timezoneService; @@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryService( IAsbCloudDbContext db, IMemoryCache memoryCache, - TelemetryDataCache dataSaubCache, + ITelemetryDataCache dataSaubCache, ITimezoneService timezoneService) { this.db = db; diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs index 70c6afdd..60693eeb 100644 --- a/AsbCloudInfrastructure/Services/WellInfoService.cs +++ b/AsbCloudInfrastructure/Services/WellInfoService.cs @@ -36,7 +36,7 @@ public class WellInfoService var operationsStatService = services.GetRequiredService(); var processMapPlanWellDrillingRepository = services.GetRequiredService>(); var subsystemOperationTimeService = services.GetRequiredService(); - var telemetryDataSaubCache = services.GetRequiredService>(); + var telemetryDataSaubCache = services.GetRequiredService>(); var messageHub = services.GetRequiredService>(); var wells = await wellService.GetAllAsync(token); @@ -180,16 +180,16 @@ public class WellInfoService public IEnumerable IdsCompanies { get; set; } = null!; } - private readonly TelemetryDataCache telemetryDataSaubCache; - private readonly TelemetryDataCache telemetryDataSpinCache; + private readonly ITelemetryDataCache telemetryDataSaubCache; + private readonly ITelemetryDataCache telemetryDataSpinCache; private readonly IWitsRecordRepository witsRecord7Repository; private readonly IWitsRecordRepository witsRecord1Repository; private readonly IGtrRepository gtrRepository; private static IEnumerable WellMapInfo = Enumerable.Empty(); public WellInfoService( - TelemetryDataCache telemetryDataSaubCache, - TelemetryDataCache telemetryDataSpinCache, + ITelemetryDataCache telemetryDataSaubCache, + ITelemetryDataCache telemetryDataSpinCache, IWitsRecordRepository witsRecord7Repository, IWitsRecordRepository witsRecord1Repository, IGtrRepository gtrRepository) diff --git a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs index 004ce863..a93dc50b 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.SAUB; using AsbCloudInfrastructure.Services.SAUB; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure.Services.WellOperationService; @@ -19,10 +20,10 @@ public class OperationsStatService : IOperationsStatService private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; - private readonly TelemetryDataCache telemetryDataCache; + private readonly ITelemetryDataCache telemetryDataCache; - public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, - TelemetryDataCache telemetryDataCache) + public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, + ITelemetryDataCache telemetryDataCache) { this.db = db; this.memoryCache = memoryCache; diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs index 240c8892..cef6745b 100644 --- a/AsbCloudInfrastructure/Startup.cs +++ b/AsbCloudInfrastructure/Startup.cs @@ -15,6 +15,7 @@ using AsbCloudInfrastructure.Services.Subsystems; using System.Linq; using DocumentFormat.OpenXml.InkML; using AsbCloudDb; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure { @@ -29,8 +30,8 @@ namespace AsbCloudInfrastructure context.Database.EnshureCreatedAndMigrated(); // TODO: Сделать инициализацию кеша телеметрии более явной. - _ = provider.GetRequiredService>(); - _ = provider.GetRequiredService>(); + _ = provider.GetRequiredService>(); + _ = provider.GetRequiredService>(); var backgroundWorker = provider.GetRequiredService(); backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30)); From bf9895667d3af2a830d2fe0bf50cf1c8fc890627 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Tue, 24 Oct 2023 09:23:07 +0500 Subject: [PATCH 3/5] =?UTF-8?q?=D0=98=D0=B7=D0=B2=D0=BB=D0=B5=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D0=B8=D0=B7=20TelemetryDataCache=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/ITelemetryDataCache.cs | 62 +++++++++++++++++++ AsbCloudInfrastructure/DependencyInjection.cs | 4 +- .../Services/SAUB/TelemetryDataBaseService.cs | 5 +- .../Services/SAUB/TelemetryDataCache.cs | 36 ++++++----- .../Services/SAUB/TelemetryDataSaubService.cs | 3 +- .../Services/SAUB/TelemetryDataSpinService.cs | 3 +- .../Services/SAUB/TelemetryService.cs | 6 +- .../Services/WellInfoService.cs | 10 +-- .../OperationsStatService.cs | 7 ++- .../Services/WellboreService.cs | 4 +- AsbCloudInfrastructure/Startup.cs | 5 +- 11 files changed, 108 insertions(+), 37 deletions(-) create mode 100644 AsbCloudApp/Repositories/ITelemetryDataCache.cs diff --git a/AsbCloudApp/Repositories/ITelemetryDataCache.cs b/AsbCloudApp/Repositories/ITelemetryDataCache.cs new file mode 100644 index 00000000..0bc73275 --- /dev/null +++ b/AsbCloudApp/Repositories/ITelemetryDataCache.cs @@ -0,0 +1,62 @@ +using AsbCloudApp.Data; +using AsbCloudApp.Requests; +using System; +using System.Collections.Generic; + +namespace AsbCloudApp.Repositories +{ + /// + /// Хранилище кеша + /// + /// + public interface ITelemetryDataCache where TDto : ITelemetryData + { + /// + /// добавить в кеш чанк записей по телеметрии + /// + /// + /// + void AddRange(int idTelemetry, IEnumerable range); + + /// + /// вернуть последнюю записть + /// + /// + /// + TDto? GetLastOrDefault(int idTelemetry); + + /// + /// Получить кешированые записи + /// + /// + /// + /// + /// приблизительное кол-во возвращаемых записей после их прореживания + /// + IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600, int approxPointsCount = 1024); + + /// + /// Получить кешированые записи + /// + /// + /// + /// + IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request); + + /// + /// Получить диапазон дат телеметрии. + /// Дата первой записи телеметрии храниться отдельно и запоняется при инициализации + /// + /// + /// + DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry); + + /// + /// Получение первой и последней записи телеметрии. + /// Первая запись телеметрии храниться отдельно и запоняется при инициализации + /// + /// + /// + (TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry); + } +} \ No newline at end of file diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 85caf0b2..33d81cba 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -159,8 +159,8 @@ namespace AsbCloudInfrastructure services.AddScoped(provider => provider.GetRequiredService()); services.AddSingleton(new WitsInfoService()); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); - services.AddSingleton(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider)); + services.AddSingleton>(provider => TelemetryDataCache.GetInstance(provider)); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 32fc88a2..649f03de 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; @@ -18,12 +19,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { protected readonly IAsbCloudDbContext db; protected readonly ITelemetryService telemetryService; - protected readonly TelemetryDataCache telemetryDataCache; + protected readonly ITelemetryDataCache telemetryDataCache; public TelemetryDataBaseService( IAsbCloudDbContext db, ITelemetryService telemetryService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) { this.db = db; this.telemetryService = telemetryService; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 531ab8d9..055d742c 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -12,11 +12,11 @@ using AsbCloudInfrastructure.Background; using System.Threading; using AsbCloudApp.Data; using AsbCloudApp.Requests; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure.Services.SAUB { - public class TelemetryDataCache - where TDto : AsbCloudApp.Data.ITelemetryData + public class TelemetryDataCache : ITelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData { class TelemetryDataCacheItem { @@ -48,7 +48,8 @@ namespace AsbCloudInfrastructure.Services.SAUB instance = new TelemetryDataCache(); var worker = provider.GetRequiredService(); var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}"; - var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => { + var work = Work.CreateByDelegate(workId, async (workId, provider, onProgress, token) => + { var db = provider.GetRequiredService(); await instance.InitializeCacheFromDBAsync(db, onProgress, token); }); @@ -85,13 +86,13 @@ namespace AsbCloudInfrastructure.Services.SAUB } else { - cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() - { + cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() + { FirstByDate = newItems.ElementAt(0), - LastData = new CyclycArray(activeWellCapacity) + LastData = new CyclycArray(activeWellCapacity) }); } - + cacheItem.LastData.AddRange(newItems); } @@ -107,14 +108,14 @@ namespace AsbCloudInfrastructure.Services.SAUB /// public IEnumerable? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) { - if(!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return null; var cacheLastData = cacheItem.LastData; if (!cacheLastData.Any() || cacheLastData[0].DateTime > dateBegin) return null; - + var dateEnd = dateBegin.AddSeconds(intervalSec); var items = cacheLastData .Where(i => i.DateTime >= dateBegin && i.DateTime <= dateEnd); @@ -141,7 +142,7 @@ namespace AsbCloudInfrastructure.Services.SAUB return null; var from = cacheItem.FirstByDate?.DateTime; - if(!cacheItem.LastData.Any()) + if (!cacheItem.LastData.Any()) return null; var to = cacheItem.LastData[^1].DateTime; @@ -190,10 +191,10 @@ namespace AsbCloudInfrastructure.Services.SAUB var idTelemetry = well.IdTelemetry!.Value; var hoursOffset = well.Timezone.Hours; - - onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count); + + onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++ / count); var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); - if(cacheItem is not null) + if (cacheItem is not null) caches.TryAdd(idTelemetry, cacheItem); } @@ -225,7 +226,8 @@ namespace AsbCloudInfrastructure.Services.SAUB var dtos = entities .AsEnumerable() .Reverse() - .Select(entity => { + .Select(entity => + { var dto = entity.Adapt(); dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); return dto; @@ -247,12 +249,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) return null; - + IEnumerable data = cacheItem.LastData; if (!data.Any()) return null; - + if (request.GeDate.HasValue) { var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); @@ -272,7 +274,7 @@ namespace AsbCloudInfrastructure.Services.SAUB var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); data = data.Where(d => d.DateTime >= request.LeDate); } - + if (request.Divider > 1) data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index afe89528..b9ce8d6c 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -1,6 +1,7 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; using AsbCloudApp.Exceptions; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; @@ -26,7 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB IAsbCloudDbContext db, ITelemetryService telemetryService, ITelemetryUserService telemetryUserService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) : base(db, telemetryService, telemetryDataCache) { this.telemetryUserService = telemetryUserService; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs index 78119d6b..dab1e851 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; @@ -11,7 +12,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryDataSpinService( IAsbCloudDbContext db, ITelemetryService telemetryService, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) : base(db, telemetryService, telemetryDataCache) { } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs index 7aa4f6c5..a084e687 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs @@ -1,5 +1,6 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; @@ -18,7 +19,8 @@ namespace AsbCloudInfrastructure.Services.SAUB { private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; - private readonly TelemetryDataCache dataSaubCache; + //TODO: методы использующие ITelemetryDataCache, скорее всего, тут не нужны + private readonly ITelemetryDataCache dataSaubCache; private readonly ITimezoneService timezoneService; public ITimezoneService TimeZoneService => timezoneService; @@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryService( IAsbCloudDbContext db, IMemoryCache memoryCache, - TelemetryDataCache dataSaubCache, + ITelemetryDataCache dataSaubCache, ITimezoneService timezoneService) { this.db = db; diff --git a/AsbCloudInfrastructure/Services/WellInfoService.cs b/AsbCloudInfrastructure/Services/WellInfoService.cs index 70c6afdd..60693eeb 100644 --- a/AsbCloudInfrastructure/Services/WellInfoService.cs +++ b/AsbCloudInfrastructure/Services/WellInfoService.cs @@ -36,7 +36,7 @@ public class WellInfoService var operationsStatService = services.GetRequiredService(); var processMapPlanWellDrillingRepository = services.GetRequiredService>(); var subsystemOperationTimeService = services.GetRequiredService(); - var telemetryDataSaubCache = services.GetRequiredService>(); + var telemetryDataSaubCache = services.GetRequiredService>(); var messageHub = services.GetRequiredService>(); var wells = await wellService.GetAllAsync(token); @@ -180,16 +180,16 @@ public class WellInfoService public IEnumerable IdsCompanies { get; set; } = null!; } - private readonly TelemetryDataCache telemetryDataSaubCache; - private readonly TelemetryDataCache telemetryDataSpinCache; + private readonly ITelemetryDataCache telemetryDataSaubCache; + private readonly ITelemetryDataCache telemetryDataSpinCache; private readonly IWitsRecordRepository witsRecord7Repository; private readonly IWitsRecordRepository witsRecord1Repository; private readonly IGtrRepository gtrRepository; private static IEnumerable WellMapInfo = Enumerable.Empty(); public WellInfoService( - TelemetryDataCache telemetryDataSaubCache, - TelemetryDataCache telemetryDataSpinCache, + ITelemetryDataCache telemetryDataSaubCache, + ITelemetryDataCache telemetryDataSpinCache, IWitsRecordRepository witsRecord7Repository, IWitsRecordRepository witsRecord1Repository, IGtrRepository gtrRepository) diff --git a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs index 004ce863..a93dc50b 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/OperationsStatService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.SAUB; using AsbCloudInfrastructure.Services.SAUB; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure.Services.WellOperationService; @@ -19,10 +20,10 @@ public class OperationsStatService : IOperationsStatService private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; - private readonly TelemetryDataCache telemetryDataCache; + private readonly ITelemetryDataCache telemetryDataCache; - public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, - TelemetryDataCache telemetryDataCache) + public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, + ITelemetryDataCache telemetryDataCache) { this.db = db; this.memoryCache = memoryCache; diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 9fd4080d..9d38683e 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -16,12 +16,12 @@ public class WellboreService : IWellboreService const string WellboreNameFormat = " {0}"; private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; - private readonly TelemetryDataCache telemetryDataCache; + private readonly ITelemetryDataCache telemetryDataCache; public WellboreService( IWellService wellService, IWellOperationRepository wellOperationRepository, - TelemetryDataCache telemetryDataCache) + ITelemetryDataCache telemetryDataCache) { this.wellService = wellService; this.wellOperationRepository = wellOperationRepository; diff --git a/AsbCloudInfrastructure/Startup.cs b/AsbCloudInfrastructure/Startup.cs index 240c8892..cef6745b 100644 --- a/AsbCloudInfrastructure/Startup.cs +++ b/AsbCloudInfrastructure/Startup.cs @@ -15,6 +15,7 @@ using AsbCloudInfrastructure.Services.Subsystems; using System.Linq; using DocumentFormat.OpenXml.InkML; using AsbCloudDb; +using AsbCloudApp.Repositories; namespace AsbCloudInfrastructure { @@ -29,8 +30,8 @@ namespace AsbCloudInfrastructure context.Database.EnshureCreatedAndMigrated(); // TODO: Сделать инициализацию кеша телеметрии более явной. - _ = provider.GetRequiredService>(); - _ = provider.GetRequiredService>(); + _ = provider.GetRequiredService>(); + _ = provider.GetRequiredService>(); var backgroundWorker = provider.GetRequiredService(); backgroundWorker.WorkStore.AddPeriodic(TimeSpan.FromMinutes(30)); From 18b26478897631de5e674a871b41834d01fe695a Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Tue, 24 Oct 2023 10:42:31 +0500 Subject: [PATCH 4/5] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20WellboreService?= =?UTF-8?q?Test.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/WellboreService.cs | 6 +- .../ServicesTests/WellboreServiceTest.cs | 203 ++++++++++++++++-- 2 files changed, 192 insertions(+), 17 deletions(-) diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 9d38683e..a0073128 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -58,7 +58,8 @@ public class WellboreService : IWellboreService Id = 1, Name = string.Format(WellboreNameFormat, 1), Well = well, - }; + }; + //if(well.) if(well.IdTelemetry is not null) { @@ -121,9 +122,6 @@ public class WellboreService : IWellboreService var dataCache = telemetryDataCache.GetOrDefaultFirstLast(well.IdTelemetry.Value); if (dataCache is not null) { - wellbore.DateStart = dataCache.Value.First.DateTime; - wellbore.DepthStart = dataCache.Value.First.WellDepth!.Value; - wellbore.DateEnd = dataCache.Value.Last.DateTime; wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value; } diff --git a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs index 77f94b84..985a7e6f 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs @@ -3,14 +3,11 @@ using AsbCloudApp.Data.SAUB; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; -using AsbCloudInfrastructure.Repository; -using AsbCloudInfrastructure.Services.SAUB; +using AsbCloudInfrastructure.Services; using NSubstitute; -using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -19,25 +16,205 @@ namespace AsbCloudWebApi.Tests.ServicesTests { public class WellboreServiceTest { + private IWellService wellService; + private IWellOperationRepository wellOperationRepository; + private ITelemetryDataCache telemetryDataCache; + private WellboreService wellboreService; + + private WellDto well1 = new WellDto + { + Id = 1, + IdState = 1, + IdTelemetry = 1, + LastTelemetryDate = DateTime.Now, + Caption = "well 1" + }; + + private WellDto well2 = new WellDto + { + Id = 2, + IdState = 1, + IdTelemetry = 100, + LastTelemetryDate = DateTime.Now, + Caption = "well 2" + }; public WellboreServiceTest() { - var wellService = Substitute.For(); - wellService.GetAsync(Arg.Any(), Arg.Any()) - .Returns(Enumerable.Empty()); + wellService = Substitute.For(); - var wellOperationRepository = Substitute.For(); - wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any()) - .Returns(Enumerable.Empty()); + wellOperationRepository = Substitute.For(); + + telemetryDataCache = Substitute.For>(); - var telemetryDataCache = Substitute.For>(); - telemetryDataCache.GetOrDefaultFirstLast(Arg.Any()); + wellboreService = new WellboreService(wellService, wellOperationRepository, telemetryDataCache); } [Fact] - public async Task GetWellboresAsync() + public async Task GetWellboresAsync_returns_empty_collection() { + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + Assert.NotNull(result); + Assert.False(result.Any()); + } + + [Fact] + public async Task GetWellboresAsync_returns_one_bore_by_well_only() + { + wellService.GetAsync(Arg.Any(), Arg.Any()) + .Returns(new WellDto[] { well1 }); + + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + + Assert.Single(result); + var wellbore0 = result.ElementAt(0); + Assert.Equal(well1.Caption, wellbore0.Well.Caption); + Assert.Equal(well1.Id, wellbore0.Well.Id); + + Assert.Equal("Ствол 1", wellbore0.Name); + Assert.Equal(1, wellbore0.Id); + + Assert.Equal(default, wellbore0.DateStart); + Assert.Equal(default, wellbore0.DateEnd); + Assert.Equal(default, wellbore0.DepthStart); + Assert.Equal(default, wellbore0.DepthEnd); + } + + [Fact] + public async Task GetWellboresAsync_returns_two_bore_by_two_wells_only() + { + wellService.GetAsync(Arg.Any(), Arg.Any()) + .Returns(new WellDto[] { well1, well2 }); + + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + + Assert.Equal(2, result.Count()); + } + + [Fact] + public async Task GetWellboresAsync_returns_two_bore_by_well_with_sections() + { + wellService.GetAsync(Arg.Any(), Arg.Any()) + .Returns(new WellDto[] { well1 }); + + var section0 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 01), DateEnd = new DateTime(2023, 01, 02), DepthStart = 000, DepthEnd = 100 }; + var section1 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 02), DateEnd = new DateTime(2023, 01, 03), DepthStart = 100, DepthEnd = 300 }; + var section2 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 210 }; + var section3 = new SectionByOperationsDto() + { IdWell = int.MaxValue, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 220 }; + + wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any()) + .Returns(new SectionByOperationsDto[]{section0, section1, section2, section3 }); + + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + + Assert.Equal(2, result.Count()); + var wellbore0 = result.ElementAt(0); + Assert.Equal(well1.Caption, wellbore0.Well.Caption); + Assert.Equal(well1.Id, wellbore0.Well.Id); + + Assert.Equal("Ствол 1", wellbore0.Name); + Assert.Equal(1, wellbore0.Id); + + Assert.Equal(section0.DateStart, wellbore0.DateStart); + Assert.Equal(section0.DepthStart, wellbore0.DepthStart); + Assert.Equal(section1.DateEnd, wellbore0.DateEnd); + Assert.Equal(section1.DepthEnd, wellbore0.DepthEnd); + + var wellbore1 = result.ElementAt(1); + Assert.Equal(well1.Caption, wellbore1.Well.Caption); + Assert.Equal(well1.Id, wellbore1.Well.Id); + + Assert.Equal("Ствол 2", wellbore1.Name); + Assert.Equal(2, wellbore1.Id); + + Assert.Equal(section2.DateStart, wellbore1.DateStart); + Assert.Equal(section2.DepthStart, wellbore1.DepthStart); + Assert.Equal(section2.DateEnd, wellbore1.DateEnd); + Assert.Equal(section2.DepthEnd, wellbore1.DepthEnd); + } + + + [Fact] + public async Task GetWellboresAsync_returns_one_bore_by_well_with_telemetry() + { + wellService.GetAsync(Arg.Any(), Arg.Any()) + .Returns(new WellDto[] { well1 }); + + var firstCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2000, 01, 01), WellDepth = 0, }; + var lastCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2023, 01, 05), WellDepth = 321, }; + + telemetryDataCache.GetOrDefaultFirstLast(Arg.Any()) + .Returns((firstCacheItem, lastCacheItem)); + + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + + Assert.Single(result); + var wellbore0 = result.ElementAt(0); + Assert.Equal(well1.Caption, wellbore0.Well.Caption); + Assert.Equal(well1.Id, wellbore0.Well.Id); + + Assert.Equal("Ствол 1", wellbore0.Name); + Assert.Equal(1, wellbore0.Id); + + Assert.Equal(firstCacheItem.DateTime, wellbore0.DateStart); + Assert.Equal(firstCacheItem.WellDepth!.Value, wellbore0.DepthStart); + Assert.Equal(lastCacheItem.DateTime, wellbore0.DateEnd); + Assert.Equal(lastCacheItem.WellDepth!.Value, wellbore0.DepthEnd); + } + + [Fact] + public async Task GetWellboresAsync_returns_two_bore_by_well_with_all() + { + wellService.GetAsync(Arg.Any(), Arg.Any()) + .Returns(new WellDto[] { well1 }); + + var section0 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 01), DateEnd = new DateTime(2023, 01, 02), DepthStart = 000, DepthEnd = 100 }; + var section1 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 02), DateEnd = new DateTime(2023, 01, 03), DepthStart = 100, DepthEnd = 300 }; + var section2 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 210 }; + + wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any()) + .Returns(new SectionByOperationsDto[] { section0, section1, section2}); + + var firstCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2000, 01, 01), WellDepth = 0, }; + var lastCacheItem = new TelemetryDataSaubDto { DateTime = new DateTime(2023, 01, 05), WellDepth = 321, }; + + telemetryDataCache.GetOrDefaultFirstLast(Arg.Any()) + .Returns((firstCacheItem, lastCacheItem)); + + var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); + + Assert.Equal(2, result.Count()); + var wellbore0 = result.ElementAt(0); + Assert.Equal(well1.Caption, wellbore0.Well.Caption); + Assert.Equal(well1.Id, wellbore0.Well.Id); + + Assert.Equal("Ствол 1", wellbore0.Name); + Assert.Equal(1, wellbore0.Id); + + Assert.Equal(section0.DateStart, wellbore0.DateStart); + Assert.Equal(section0.DepthStart, wellbore0.DepthStart); + Assert.Equal(section1.DateEnd, wellbore0.DateEnd); + Assert.Equal(section1.DepthEnd, wellbore0.DepthEnd); + + var wellbore1 = result.ElementAt(1); + Assert.Equal(well1.Caption, wellbore1.Well.Caption); + Assert.Equal(well1.Id, wellbore1.Well.Id); + + Assert.Equal("Ствол 2", wellbore1.Name); + Assert.Equal(2, wellbore1.Id); + + Assert.Equal(section2.DateStart, wellbore1.DateStart); + Assert.Equal(section2.DepthStart, wellbore1.DepthStart); + Assert.Equal(lastCacheItem.DateTime, wellbore1.DateEnd); + Assert.Equal(lastCacheItem.WellDepth!.Value, wellbore1.DepthEnd); } } } From 399393fd555ae2ab28b82ac7391d79ee0535b729 Mon Sep 17 00:00:00 2001 From: ngfrolov Date: Tue, 24 Oct 2023 11:15:27 +0500 Subject: [PATCH 5/5] =?UTF-8?q?fix=20WellboreService;=20=D0=BF=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=81=D0=B5=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B5=20=D1=83=D1=87=D0=B8=D1=82=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D1=8E=D1=82=D1=81=D1=8F.=20WellboreServiceTest=20Add=20t?= =?UTF-8?q?estCase;=20Add=20Auth.http;=20Fix=20wellbore.http;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsbCloudInfrastructure/Services/WellboreService.cs | 1 + .../ServicesTests/WellboreServiceTest.cs | 4 +++- AsbCloudWebApi/Rest/Auth.http | 12 ++++++++++++ AsbCloudWebApi/Rest/wellbore.http | 8 +++----- 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 AsbCloudWebApi/Rest/Auth.http diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index a0073128..4417dd49 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -36,6 +36,7 @@ public class WellboreService : IWellboreService var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token); var groupedSections = rowSections + .Where(section => section.IdType == 1) .GroupBy(s => s.IdWell); var wellbores = wells diff --git a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs index 985a7e6f..1a802054 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/WellboreServiceTest.cs @@ -106,9 +106,11 @@ namespace AsbCloudWebApi.Tests.ServicesTests { IdWell = well1.Id, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 210 }; var section3 = new SectionByOperationsDto() { IdWell = int.MaxValue, IdWellSectionType = 0, IdType = 1, DateStart = new DateTime(2023, 01, 03), DateEnd = new DateTime(2023, 01, 04), DepthStart = 200, DepthEnd = 220 }; + var section4 = new SectionByOperationsDto() + { IdWell = well1.Id, IdWellSectionType = 0, IdType = 0, DateStart = new DateTime(2023, 01, 05), DateEnd = new DateTime(2023, 01, 06), DepthStart = 150, DepthEnd = 220 }; wellOperationRepository.GetSectionsAsync(Arg.Any>(), Arg.Any()) - .Returns(new SectionByOperationsDto[]{section0, section1, section2, section3 }); + .Returns(new SectionByOperationsDto[]{section0, section1, section2, section3, section4, }); var result = await wellboreService.GetWellboresAsync(new[] { 1 }, CancellationToken.None); diff --git a/AsbCloudWebApi/Rest/Auth.http b/AsbCloudWebApi/Rest/Auth.http new file mode 100644 index 00000000..36097c0e --- /dev/null +++ b/AsbCloudWebApi/Rest/Auth.http @@ -0,0 +1,12 @@ +@baseUrl = http://127.0.0.1:5000 +@contentType = application/json + +## Auth +POST {{baseUrl}}/auth/login +Content-Type: {{contentType}} +accept: */* + +{ + "login": "dev", + "password": "Rp7gsNMk" +} \ No newline at end of file diff --git a/AsbCloudWebApi/Rest/wellbore.http b/AsbCloudWebApi/Rest/wellbore.http index 9a7918ac..e00c6687 100644 --- a/AsbCloudWebApi/Rest/wellbore.http +++ b/AsbCloudWebApi/Rest/wellbore.http @@ -1,15 +1,13 @@ @baseUrl = http://127.0.0.1:5000 @contentType = application/json -@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE +@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2OTgxMjY1MTUsImV4cCI6MTcyOTY4NDExNSwiaXNzIjoiYSIsImF1ZCI6ImEifQ.3Lq256cYtHnKlGWChPhZv2rUJPjbJEHU-18xdyJlYDE -@uid = 20210101_000000000 -@idCluster = 1 -@idWell = 1 +@idWell = 2 # https://marketplace.visualstudio.com/items?itemName=humao.rest-client ### -GET {{baseUrl}}/api/well/wellbore?ids=1,2 +GET {{baseUrl}}/api/wellbore?idsWells=1 Content-Type: {{contentType}} accept: */* Authorization: {{auth}}