forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/detected_operations
# Conflicts: # AsbCloudInfrastructure/DependencyInjection.cs
This commit is contained in:
commit
23e8615e8a
@ -9,8 +9,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudApp", "AsbCloudApp\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudInfrastructure", "AsbCloudInfrastructure\AsbCloudInfrastructure.csproj", "{67DBFC52-BAE4-4903-827A-AD0288C292B6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudInfrastructure", "AsbCloudInfrastructure\AsbCloudInfrastructure.csproj", "{67DBFC52-BAE4-4903-827A-AD0288C292B6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{D04A84E7-5F08-4042-8FB5-476EE49E9D22}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudDb", "AsbCloudDb\AsbCloudDb.csproj", "{40FBD29B-724B-4496-B5D9-1A5D14102456}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudDb", "AsbCloudDb\AsbCloudDb.csproj", "{40FBD29B-724B-4496-B5D9-1A5D14102456}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudWebApi.Tests", "AsbCloudWebApi.Tests\AsbCloudWebApi.Tests.csproj", "{9CF6FBB1-9AF5-45AB-A521-24F11A79B540}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudWebApi.Tests", "AsbCloudWebApi.Tests\AsbCloudWebApi.Tests.csproj", "{9CF6FBB1-9AF5-45AB-A521-24F11A79B540}"
|
||||||
@ -35,10 +33,6 @@ Global
|
|||||||
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{40FBD29B-724B-4496-B5D9-1A5D14102456}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -5,21 +5,10 @@ namespace AsbCloudApp.Data.AutogeneratedDailyReport;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Базовая информация о суточном отчёте
|
/// Базовая информация о суточном отчёте
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AutoGeneratedDailyReportInfoDto
|
public class AutoGeneratedDailyReportInfoDto : ReportInfoDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата формирования отчёта
|
/// Дата формирования отчёта
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateOnly ReportDate { get; set; }
|
public DateOnly ReportDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Название файла
|
|
||||||
/// </summary>
|
|
||||||
public string FileName { get; set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Размер файла
|
|
||||||
/// </summary>
|
|
||||||
public int FileSize { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
@ -172,7 +172,7 @@ namespace AsbCloudApp.Data
|
|||||||
if (progress.HasValue)
|
if (progress.HasValue)
|
||||||
CurrentState.Progress = progress.Value;
|
CurrentState.Progress = progress.Value;
|
||||||
|
|
||||||
Trace.TraceInformation($"{WorkNameForTrace} state: {newState}");
|
Trace.TraceInformation($"{WorkNameForTrace} state[{100*progress:#}%]: {newState}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
26
AsbCloudApp/Data/DrillTestReport/DrillTestReportDataDto.cs
Normal file
26
AsbCloudApp/Data/DrillTestReport/DrillTestReportDataDto.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.DrillTestReport
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Информация о drill test, выгружаемая в отчете
|
||||||
|
/// </summary>
|
||||||
|
public class DrillTestReportDataDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Данные для отчета
|
||||||
|
/// </summary>
|
||||||
|
public DrillTestDto Data { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заголовок отчета
|
||||||
|
/// </summary>
|
||||||
|
public string Caption { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата отчета
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Date { get; set; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
25
AsbCloudApp/Data/DrillTestReport/DrillTestReportInfoDto.cs
Normal file
25
AsbCloudApp/Data/DrillTestReport/DrillTestReportInfoDto.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.DrillTestReport
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Базовая информация о drill_test отчёте
|
||||||
|
/// </summary>
|
||||||
|
public class DrillTestReportInfoDto : ReportInfoDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор отчета
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проходка
|
||||||
|
/// </summary>
|
||||||
|
public float DrillDepth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата и время
|
||||||
|
/// </summary>
|
||||||
|
public DateTime DateTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
18
AsbCloudApp/Data/ReportInfoDto.cs
Normal file
18
AsbCloudApp/Data/ReportInfoDto.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace AsbCloudApp.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Справочная информация об отчете
|
||||||
|
/// </summary>
|
||||||
|
public class ReportInfoDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Название файла
|
||||||
|
/// </summary>
|
||||||
|
public string FileName { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Размер файла
|
||||||
|
/// </summary>
|
||||||
|
public int FileSize { get; set; } = 0;
|
||||||
|
}
|
||||||
|
}
|
37
AsbCloudApp/Data/SAUB/DrillTestDto.cs
Normal file
37
AsbCloudApp/Data/SAUB/DrillTestDto.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.SAUB
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DTO для описания записи drill_test
|
||||||
|
/// </summary>
|
||||||
|
public class DrillTestDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор drill test
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время начала drill test
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset TimeStampStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина начала drill test
|
||||||
|
/// </summary>
|
||||||
|
public float DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Связанная с drill_test телеметрия
|
||||||
|
/// </summary>
|
||||||
|
public TelemetryDto? Telemetry { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры теста
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<DrillTestParamsDto> Params { get; set; } = Enumerable.Empty<DrillTestParamsDto>();
|
||||||
|
}
|
||||||
|
}
|
38
AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs
Normal file
38
AsbCloudApp/Data/SAUB/DrillTestParamsDto.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
namespace AsbCloudApp.Data.SAUB
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры Drill Test
|
||||||
|
/// </summary>
|
||||||
|
public class DrillTestParamsDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Шаг
|
||||||
|
/// </summary>
|
||||||
|
public int Step { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Нагрузка
|
||||||
|
/// </summary>
|
||||||
|
public float? Workload { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заданная скорость
|
||||||
|
/// </summary>
|
||||||
|
public float? Speed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Скорость проходки
|
||||||
|
/// </summary>
|
||||||
|
public float? DepthSpeed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время бурения шага, сек
|
||||||
|
/// </summary>
|
||||||
|
public float? TimeDrillStep { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина бурения шага
|
||||||
|
/// </summary>
|
||||||
|
public float? DepthDrillStep { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace AsbCloudApp.Data.SAUB
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// id категории события
|
/// id категории события
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Range(1, int.MaxValue, ErrorMessage = "Id категории события не может быть отрицательным")]
|
[Range(0, int.MaxValue, ErrorMessage = "Id категории события не может быть отрицательным")]
|
||||||
public int IdCategory { get; set; }
|
public int IdCategory { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -32,7 +32,7 @@ namespace AsbCloudApp.Data.SAUB
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// тип определения наступления события
|
/// тип определения наступления события
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Range(1, int.MaxValue, ErrorMessage = "Id типа события не может быть отрицательным")]
|
[Range(0, int.MaxValue, ErrorMessage = "Id типа события не может быть отрицательным")]
|
||||||
public int EventType { get; set; }
|
public int EventType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -44,4 +44,5 @@ public class SectionByOperationsDto
|
|||||||
/// Дата после завершения последней операции операции в секции
|
/// Дата после завершения последней операции операции в секции
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset DateEnd { get; set; }
|
public DateTimeOffset DateEnd { get; set; }
|
||||||
|
public string Caption { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ public class WellboreDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Скважина
|
/// Скважина
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WellWithTimezoneDto Well { get; set; } = null!;
|
public WellDto Well { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Идентификатор
|
/// Идентификатор
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace AsbCloudApp.Exceptions
|
namespace AsbCloudApp.Exceptions
|
||||||
{
|
{
|
||||||
@ -8,9 +10,9 @@ namespace AsbCloudApp.Exceptions
|
|||||||
public class ArgumentInvalidException : Exception
|
public class ArgumentInvalidException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// название аргумента
|
/// словарь с ошибками, где ключ - имя аргумента, а значение - массив из одного сообщения
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ParamName { get; } = string.Empty;
|
public IDictionary<string, string[]> ErrorState { get; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// конструктор
|
/// конструктор
|
||||||
@ -20,7 +22,20 @@ namespace AsbCloudApp.Exceptions
|
|||||||
public ArgumentInvalidException(string paramName, string message)
|
public ArgumentInvalidException(string paramName, string message)
|
||||||
: base(message)
|
: base(message)
|
||||||
{
|
{
|
||||||
ParamName = paramName;
|
ErrorState = new Dictionary<string, string[]>() {
|
||||||
|
{ paramName, new[]{ message } }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// конструктор
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="paramsNames"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public ArgumentInvalidException(string[] paramsNames, string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
ErrorState = paramsNames.ToDictionary(paramName => paramName, item => new[] { message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
AsbCloudApp/Repositories/IDrillTestRepository.cs
Normal file
41
AsbCloudApp/Repositories/IDrillTestRepository.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Repositories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// репозиторий по работе с данными drill_test
|
||||||
|
/// </summary>
|
||||||
|
public interface IDrillTestRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные drill_test в соответствии с параметрами запроса
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry">ключ телеметрии</param>
|
||||||
|
/// <param name="request">запрос</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<DrillTestDto>> GetAllAsync(int idTelemetry, FileReportRequest request, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить запись drill_test
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry">ключ телеметрии</param>
|
||||||
|
/// <param name="id">ключ записи drill_test</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<DrillTestDto> GetAsync(int idTelemetry, int id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сохранить данные drill_test
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry">ключ телеметрии</param>
|
||||||
|
/// <param name="dto">запись drill test</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
69
AsbCloudApp/Repositories/ITelemetryDataCache.cs
Normal file
69
AsbCloudApp/Repositories/ITelemetryDataCache.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Repositories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Хранилище кеша
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TDto"></typeparam>
|
||||||
|
public interface ITelemetryDataCache<TDto> where TDto : ITelemetryData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// добавить в кеш чанк записей по телеметрии
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <param name="range"></param>
|
||||||
|
void AddRange(int idTelemetry, IEnumerable<TDto> range);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// вернуть последнюю записть
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TDto? GetLastOrDefault(int idTelemetry);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить кешированые записи
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="intervalSec"></param>
|
||||||
|
/// <param name="approxPointsCount">приблизительное кол-во возвращаемых записей после их прореживания</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600, int approxPointsCount = 1024);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить кешированые записи
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IEnumerable<TDto>? GetOrDefault(int idTelemetry, TelemetryDataRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Диапазон дат находящийся в кеше
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
DatesRangeDto? GetOrDefaultCachedaDateRange(int idTelemetry);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат телеметрии.
|
||||||
|
/// Дата первой записи телеметрии храниться отдельно и запоняется при инициализации
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
DatesRangeDto? GetOrDefaultDataDateRange(int idTelemetry);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение первой и последней записи телеметрии.
|
||||||
|
/// Первая запись телеметрии храниться отдельно и запоняется при инициализации
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idTelemetry"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
(TDto First, TDto Last)? GetOrDefaultFirstLast(int idTelemetry);
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Requests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Параметры запроса для получения авто-генерируемых суточных отчётов
|
|
||||||
/// </summary>
|
|
||||||
public class AutoGeneratedDailyReportRequest : RequestBase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Дата начала периода
|
|
||||||
/// </summary>
|
|
||||||
public DateOnly? StartDate { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Дата конца периода
|
|
||||||
/// </summary>
|
|
||||||
public DateOnly? FinishDate { get; set; }
|
|
||||||
}
|
|
19
AsbCloudApp/Requests/FileReportRequest.cs
Normal file
19
AsbCloudApp/Requests/FileReportRequest.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры запроса для получения отчетов (файлов)
|
||||||
|
/// </summary>
|
||||||
|
public class FileReportRequest : RequestBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Дата начала периода
|
||||||
|
/// </summary>
|
||||||
|
public DateOnly? GeDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата конца периода
|
||||||
|
/// </summary>
|
||||||
|
public DateOnly? LeDate { get; set; }
|
||||||
|
}
|
@ -84,7 +84,7 @@ namespace AsbCloudApp.Requests
|
|||||||
{
|
{
|
||||||
if (LtDepth < GtDepth)
|
if (LtDepth < GtDepth)
|
||||||
yield return new ValidationResult(
|
yield return new ValidationResult(
|
||||||
$"{nameof(LtDepth)} должно быть больше {nameof(GtDepth)}. ({LtDepth:O} < {GtDepth:O})",
|
$"{nameof(LtDepth)} должно быть больше {nameof(GtDepth)}. ({LtDepth} < {GtDepth})",
|
||||||
new[] { nameof(LtDepth), nameof(GtDepth) });
|
new[] { nameof(LtDepth), nameof(GtDepth) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Requests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Параметры запроса для ствола скважины
|
|
||||||
/// </summary>
|
|
||||||
public class WellboreRequest : RequestBase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Пары идентификаторов скважины и секции
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<(int idWell, int? idSection)> Ids { get; set; } = null!;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AsbCloudApp.Data.AutogeneratedDailyReport;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Services.AutoGeneratedDailyReports;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Сервис для генерации файлов авто-генерируемых суточный отчётов
|
|
||||||
/// </summary>
|
|
||||||
public interface IAutoGeneratedDailyReportMakerService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Генерация файла
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="report"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<Stream> MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken);
|
|
||||||
}
|
|
@ -21,7 +21,7 @@ public interface IAutoGeneratedDailyReportService
|
|||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
|
Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
|
||||||
AutoGeneratedDailyReportRequest request,
|
FileReportRequest request,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
35
AsbCloudApp/Services/IDrillTestReportService.cs
Normal file
35
AsbCloudApp/Services/IDrillTestReportService.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.DrillTestReport;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// сервис по работе с отчетами drill test
|
||||||
|
/// </summary>
|
||||||
|
public interface IDrillTestReportService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Список файлов drill test
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell">ключ скважины</param>
|
||||||
|
/// <param name="request">параметры запроса</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<PaginationContainer<DrillTestReportInfoDto>> GetListAsync(int idWell,
|
||||||
|
FileReportRequest request,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Генерация файла с отчётом
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell">ключ скважины</param>
|
||||||
|
/// <param name="id">ключ drill test записи</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<(string fileName, Stream stream)> GenerateAsync(int idWell, int id, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
19
AsbCloudApp/Services/IReportMakerService.cs
Normal file
19
AsbCloudApp/Services/IReportMakerService.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для генерации файлов отчётов
|
||||||
|
/// </summary>
|
||||||
|
public interface IReportMakerService<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Генерация файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="report">модель с данными для построения отчета</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Stream> MakeReportAsync(T report, CancellationToken cancellationToken);
|
||||||
|
}
|
@ -57,5 +57,13 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
|
Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление отчетов, если превышен их период хранения
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lifetime">период хранения отчетов</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,17 +26,32 @@ namespace AsbCloudApp.Services
|
|||||||
Task<IEnumerable<TDto>> GetAsync(int idWell,
|
Task<IEnumerable<TDto>> GetAsync(int idWell,
|
||||||
DateTime dateBegin = default, double intervalSec = 600d,
|
DateTime dateBegin = default, double intervalSec = 600d,
|
||||||
int approxPointsCount = 1024, CancellationToken token = default);
|
int approxPointsCount = 1024, CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные тех. процесса
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task<IEnumerable<TDto>> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token);
|
Task<IEnumerable<TDto>> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение статистики за период
|
/// Период за который есть данные по скважине в рамках временного интервала
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <param name="start"></param>
|
/// <param name="geDate"></param>
|
||||||
/// <param name="end"></param>
|
/// <param name="leDate"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token);
|
Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Период за который есть данные по скважине
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
DatesRangeDto? GetRange(int idWell);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// добавить/изменить данные тех. процесса (используется панелью)
|
/// добавить/изменить данные тех. процесса (используется панелью)
|
||||||
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Services;
|
namespace AsbCloudApp.Services;
|
||||||
|
|
||||||
@ -11,20 +10,11 @@ namespace AsbCloudApp.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWellboreService
|
public interface IWellboreService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение ствола скважины
|
/// Получение стволов скважин
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="idWell"></param>
|
/// <param name="idsWells"></param>
|
||||||
/// <param name="idSection"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <returns></returns>
|
||||||
/// <returns></returns>
|
Task<IEnumerable<WellboreDto>> GetWellboresAsync(IEnumerable<int> idsWells, CancellationToken cancellationToken);
|
||||||
Task<WellboreDto?> GetWellboreAsync(int idWell, int idSection, CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получение стволов скважин
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<WellboreDto>> GetWellboresAsync(WellboreRequest request, CancellationToken cancellationToken);
|
|
||||||
}
|
}
|
50
AsbCloudDb/EFExtentionsInnitialization.cs
Normal file
50
AsbCloudDb/EFExtentionsInnitialization.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
|
||||||
|
namespace AsbCloudDb
|
||||||
|
{
|
||||||
|
public static class EFExtentionsInnitialization
|
||||||
|
{
|
||||||
|
public static void EnshureCreatedAndMigrated(this DatabaseFacade db)
|
||||||
|
{
|
||||||
|
db.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
||||||
|
if (db.EnsureCreated())
|
||||||
|
{
|
||||||
|
db.CreateMigrationTable();
|
||||||
|
db.WriteMigrationsInfo();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
db.SetCommandTimeout(TimeSpan.FromMinutes(20));
|
||||||
|
db.Migrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CreateMigrationTable(this DatabaseFacade db)
|
||||||
|
{
|
||||||
|
var sqlCreateMigrationTable =
|
||||||
|
$"CREATE TABLE public.\"__EFMigrationsHistory\" " +
|
||||||
|
$"(\"MigrationId\" varchar(150) NOT NULL, " +
|
||||||
|
$" \"ProductVersion\" varchar(32) NOT NULL, " +
|
||||||
|
$" CONSTRAINT \"PK___EFMigrationsHistory\" PRIMARY KEY (\"MigrationId\"));";
|
||||||
|
db.ExecuteSqlRaw(sqlCreateMigrationTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteMigrationsInfo(this DatabaseFacade db)
|
||||||
|
{
|
||||||
|
var efVersion = db.GetType().Assembly.GetName().Version!;
|
||||||
|
var efVersionString = $"{efVersion.Major}.{efVersion.Minor}.{efVersion.Build}";
|
||||||
|
|
||||||
|
var migrations = db.GetPendingMigrations()
|
||||||
|
.Select(migration => $" ('{migration}', '{efVersionString}')");
|
||||||
|
|
||||||
|
var sqlAddLastMigration =
|
||||||
|
$"INSERT INTO public.\"__EFMigrationsHistory\" " +
|
||||||
|
$"(\"MigrationId\", \"ProductVersion\") " +
|
||||||
|
$"VALUES {string.Join(',', migrations)};";
|
||||||
|
db.ExecuteSqlRaw(sqlAddLastMigration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8803
AsbCloudDb/Migrations/20231017094813_Add_Drill_Test.Designer.cs
generated
Normal file
8803
AsbCloudDb/Migrations/20231017094813_Add_Drill_Test.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
46
AsbCloudDb/Migrations/20231017094813_Add_Drill_Test.cs
Normal file
46
AsbCloudDb/Migrations/20231017094813_Add_Drill_Test.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Drill_Test : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "t_drill_test",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false, comment: "Идентификатор"),
|
||||||
|
id_telemetry = table.Column<int>(type: "integer", nullable: false, comment: "Идентификатор телеметрии"),
|
||||||
|
timestamp_start = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Время начала"),
|
||||||
|
depthStart = table.Column<float>(type: "real", nullable: false, comment: "Глубина начала"),
|
||||||
|
t_drill_test_params = table.Column<string>(type: "jsonb", nullable: false, comment: "Параметры записи drill test")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_t_drill_test", x => new { x.id, x.id_telemetry });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_drill_test_t_telemetry_id_telemetry",
|
||||||
|
column: x => x.id_telemetry,
|
||||||
|
principalTable: "t_telemetry",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
},
|
||||||
|
comment: "Drill_test");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_drill_test_id_telemetry",
|
||||||
|
table: "t_drill_test",
|
||||||
|
column: "id_telemetry");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "t_drill_test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8814
AsbCloudDb/Migrations/20231101110412_Update_EntityFillerSubsystem.Designer.cs
generated
Normal file
8814
AsbCloudDb/Migrations/20231101110412_Update_EntityFillerSubsystem.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Update_EntityFillerSubsystem : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_subsystem",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 65536,
|
||||||
|
columns: new[] { "description", "name" },
|
||||||
|
values: new object[] { "Осцилляция", "Осцилляция" });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_subsystem",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 65537,
|
||||||
|
columns: new[] { "description", "name" },
|
||||||
|
values: new object[] { "Демпфер", "Демпфер" });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_subsystem",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 65536,
|
||||||
|
columns: new[] { "description", "name" },
|
||||||
|
values: new object[] { "Spin master", "Spin master" });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_subsystem",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 65537,
|
||||||
|
columns: new[] { "description", "name" },
|
||||||
|
values: new object[] { "Torque master", "Torque master" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8815
AsbCloudDb/Migrations/20231102045101_Rename_Field_IsContact_In_CompanyType.Designer.cs
generated
Normal file
8815
AsbCloudDb/Migrations/20231102045101_Rename_Field_IsContact_In_CompanyType.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Rename_Field_IsContact_In_CompanyType : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "IsContact",
|
||||||
|
table: "t_company_type",
|
||||||
|
newName: "is_contact");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "is_contact",
|
||||||
|
table: "t_company_type",
|
||||||
|
newName: "IsContact");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8857
AsbCloudDb/Migrations/20231102045600_Add_Or_Update_Data_In_CompanyType.Designer.cs
generated
Normal file
8857
AsbCloudDb/Migrations/20231102045600_Add_Or_Update_Data_In_CompanyType.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,101 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Or_Update_Data_In_CompanyType : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 1,
|
||||||
|
columns: new[] { "caption", "order" },
|
||||||
|
values: new object[] { "Недропользователь", 3 });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 2,
|
||||||
|
columns: new[] { "is_contact", "order" },
|
||||||
|
values: new object[] { true, 2 });
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 3,
|
||||||
|
columns: new[] { "is_contact", "order" },
|
||||||
|
values: new object[] { true, 0 });
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (4, 'Сервис по ГТИ', true, 6) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Сервис по ГТИ', is_contact=true, ""order""=6;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (5, 'Растворный сервис', true, 4) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Растворный сервис', is_contact=true, ""order""=4;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (6, 'Сервис по ННБ', true, 5) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Сервис по ННБ', is_contact=true, ""order""=5;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (7, 'Служба супервайзинга', true, 1) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Служба супервайзинга', is_contact=true, ""order""=1;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (9, 'Сервис по цементированию', true, 7) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Сервис по цементированию', is_contact=true, ""order""=7;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (11, 'Дизельный сервис', false, 9) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Дизельный сервис', is_contact=false, ""order""=9;");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(@"INSERT INTO public.t_company_type (id, caption, is_contact, ""order"") " +
|
||||||
|
@"VALUES (12, 'Сервис по обслуживанию верхних силовых приводов', true, 8) " +
|
||||||
|
@"ON CONFLICT (id) DO UPDATE SET caption='Сервис по обслуживанию верхних силовых приводов', is_contact=false, ""order""=8;");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 4);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 5);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 6);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 7);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 9);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 12);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "t_company_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 1,
|
||||||
|
columns: new[] { "caption", "order" },
|
||||||
|
values: new object[] { "Недрапользователь", 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8894
AsbCloudDb/Migrations/20231107091439_Add_Data_To_WellSectionType.Designer.cs
generated
Normal file
8894
AsbCloudDb/Migrations/20231107091439_Add_Data_To_WellSectionType.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Data_To_WellSectionType : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
columns: new[] { "id", "caption", "order" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ 34, "Хвостовик 6", 6.5f },
|
||||||
|
{ 35, "Хвостовик 7", 6.6f },
|
||||||
|
{ 36, "Хвостовик 8", 6.7f },
|
||||||
|
{ 37, "Хвостовик 9", 6.8f },
|
||||||
|
{ 38, "Хвостовик 10", 6.9f }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 34);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 35);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 36);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 37);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_well_section_type",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 38);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8894
AsbCloudDb/Migrations/20231110080246_UpdateTable_t_telemetry_data_Set_ImportantColumns_NotNull.Designer.cs
generated
Normal file
8894
AsbCloudDb/Migrations/20231110080246_UpdateTable_t_telemetry_data_Set_ImportantColumns_NotNull.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,224 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class UpdateTable_t_telemetry_data_Set_ImportantColumns_NotNull : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql("DELETE FROM t_telemetry_data_saub WHERE " +
|
||||||
|
"well_depth IS NULL OR " +
|
||||||
|
"rotor_torque IS NULL OR " +
|
||||||
|
"rotor_speed IS NULL OR " +
|
||||||
|
"pressure IS NULL OR " +
|
||||||
|
"mode IS NULL OR " +
|
||||||
|
"hook_weight IS NULL OR " +
|
||||||
|
"block_position IS NULL OR " +
|
||||||
|
"bit_depth IS NULL OR " +
|
||||||
|
"axial_load IS NULL;");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "well_depth",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Глубина забоя",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Глубина забоя");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "rotor_torque",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Момент на роторе",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Момент на роторе");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "rotor_speed",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Обороты ротора",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Обороты ротора");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "pressure",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Давление",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Давление");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<short>(
|
||||||
|
name: "mode",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "smallint",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: (short)0,
|
||||||
|
comment: "Режим САУБ",
|
||||||
|
oldClrType: typeof(short),
|
||||||
|
oldType: "smallint",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Режим САУБ");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "hook_weight",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Вес на крюке",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Вес на крюке");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "block_position",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Высота талевого блока",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Высота талевого блока");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "bit_depth",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Положение инструмента",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Положение инструмента");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "axial_load",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0f,
|
||||||
|
comment: "Осевая нагрузка",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldNullable: true,
|
||||||
|
oldComment: "Осевая нагрузка");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "well_depth",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Глубина забоя",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Глубина забоя");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "rotor_torque",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Момент на роторе",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Момент на роторе");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "rotor_speed",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Обороты ротора",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Обороты ротора");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "pressure",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Давление",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Давление");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<short>(
|
||||||
|
name: "mode",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "smallint",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Режим САУБ",
|
||||||
|
oldClrType: typeof(short),
|
||||||
|
oldType: "smallint",
|
||||||
|
oldComment: "Режим САУБ");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "hook_weight",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Вес на крюке",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Вес на крюке");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "block_position",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Высота талевого блока",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Высота талевого блока");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "bit_depth",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Положение инструмента",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Положение инструмента");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<float>(
|
||||||
|
name: "axial_load",
|
||||||
|
table: "t_telemetry_data_saub",
|
||||||
|
type: "real",
|
||||||
|
nullable: true,
|
||||||
|
comment: "Осевая нагрузка",
|
||||||
|
oldClrType: typeof(float),
|
||||||
|
oldType: "real",
|
||||||
|
oldComment: "Осевая нагрузка");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -120,7 +120,8 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("caption");
|
.HasColumnName("caption");
|
||||||
|
|
||||||
b.Property<bool>("IsContact")
|
b.Property<bool>("IsContact")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_contact");
|
||||||
|
|
||||||
b.Property<int>("Order")
|
b.Property<int>("Order")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
@ -134,9 +135,9 @@ namespace AsbCloudDb.Migrations
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
Caption = "Недрапользователь",
|
Caption = "Недропользователь",
|
||||||
IsContact = false,
|
IsContact = false,
|
||||||
Order = 1
|
Order = 3
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
@ -151,6 +152,48 @@ namespace AsbCloudDb.Migrations
|
|||||||
Caption = "Сервис автоматизации бурения",
|
Caption = "Сервис автоматизации бурения",
|
||||||
IsContact = false,
|
IsContact = false,
|
||||||
Order = 0
|
Order = 0
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 4,
|
||||||
|
Caption = "Сервис по ГТИ",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 6
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 5,
|
||||||
|
Caption = "Растворный сервис",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 4
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 6,
|
||||||
|
Caption = "Сервис по ННБ",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 5
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 7,
|
||||||
|
Caption = "Служба супервайзинга",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 1
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 9,
|
||||||
|
Caption = "Сервис по цементированию",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 7
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 12,
|
||||||
|
Caption = "Сервис по обслуживанию верхних силовых приводов",
|
||||||
|
IsContact = true,
|
||||||
|
Order = 7
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -413,6 +456,43 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.HasComment("части программ бурения");
|
b.HasComment("части программ бурения");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.DrillTest", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasComment("Идентификатор");
|
||||||
|
|
||||||
|
b.Property<int>("IdTelemetry")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_telemetry")
|
||||||
|
.HasComment("Идентификатор телеметрии");
|
||||||
|
|
||||||
|
b.Property<float>("DepthStart")
|
||||||
|
.HasColumnType("real")
|
||||||
|
.HasColumnName("depthStart")
|
||||||
|
.HasComment("Глубина начала");
|
||||||
|
|
||||||
|
b.Property<string>("Params")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("t_drill_test_params")
|
||||||
|
.HasComment("Параметры записи drill test");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("TimeStampStart")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("timestamp_start")
|
||||||
|
.HasComment("Время начала");
|
||||||
|
|
||||||
|
b.HasKey("Id", "IdTelemetry");
|
||||||
|
|
||||||
|
b.HasIndex("IdTelemetry");
|
||||||
|
|
||||||
|
b.ToTable("t_drill_test");
|
||||||
|
|
||||||
|
b.HasComment("Drill_test");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.Faq", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.Faq", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -4531,14 +4611,14 @@ namespace AsbCloudDb.Migrations
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 65536,
|
Id = 65536,
|
||||||
Description = "Spin master",
|
Description = "Осцилляция",
|
||||||
Name = "Spin master"
|
Name = "Осцилляция"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = 65537,
|
Id = 65537,
|
||||||
Description = "Torque master",
|
Description = "Демпфер",
|
||||||
Name = "Torque master"
|
Name = "Демпфер"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4638,7 +4718,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("date")
|
.HasColumnName("date")
|
||||||
.HasComment("'2021-10-19 18:23:54+05'");
|
.HasComment("'2021-10-19 18:23:54+05'");
|
||||||
|
|
||||||
b.Property<float?>("AxialLoad")
|
b.Property<float>("AxialLoad")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("axial_load")
|
.HasColumnName("axial_load")
|
||||||
.HasComment("Осевая нагрузка");
|
.HasComment("Осевая нагрузка");
|
||||||
@ -4653,12 +4733,12 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("axial_load_sp")
|
.HasColumnName("axial_load_sp")
|
||||||
.HasComment("Осевая нагрузка. Задание");
|
.HasComment("Осевая нагрузка. Задание");
|
||||||
|
|
||||||
b.Property<float?>("BitDepth")
|
b.Property<float>("BitDepth")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("bit_depth")
|
.HasColumnName("bit_depth")
|
||||||
.HasComment("Положение инструмента");
|
.HasComment("Положение инструмента");
|
||||||
|
|
||||||
b.Property<float?>("BlockPosition")
|
b.Property<float>("BlockPosition")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("block_position")
|
.HasColumnName("block_position")
|
||||||
.HasComment("Высота талевого блока");
|
.HasComment("Высота талевого блока");
|
||||||
@ -4713,7 +4793,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("flow_idle")
|
.HasColumnName("flow_idle")
|
||||||
.HasComment("Расход. Холостой ход");
|
.HasComment("Расход. Холостой ход");
|
||||||
|
|
||||||
b.Property<float?>("HookWeight")
|
b.Property<float>("HookWeight")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("hook_weight")
|
.HasColumnName("hook_weight")
|
||||||
.HasComment("Вес на крюке");
|
.HasComment("Вес на крюке");
|
||||||
@ -4743,7 +4823,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("id_user")
|
.HasColumnName("id_user")
|
||||||
.HasComment("Пользователь САУБ");
|
.HasComment("Пользователь САУБ");
|
||||||
|
|
||||||
b.Property<short?>("Mode")
|
b.Property<short>("Mode")
|
||||||
.HasColumnType("smallint")
|
.HasColumnType("smallint")
|
||||||
.HasColumnName("mode")
|
.HasColumnName("mode")
|
||||||
.HasComment("Режим САУБ");
|
.HasComment("Режим САУБ");
|
||||||
@ -4758,7 +4838,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("mse_state")
|
.HasColumnName("mse_state")
|
||||||
.HasComment("Текущее состояние работы MSE");
|
.HasComment("Текущее состояние работы MSE");
|
||||||
|
|
||||||
b.Property<float?>("Pressure")
|
b.Property<float>("Pressure")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("pressure")
|
.HasColumnName("pressure")
|
||||||
.HasComment("Давление");
|
.HasComment("Давление");
|
||||||
@ -4808,12 +4888,12 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("pump2_flow")
|
.HasColumnName("pump2_flow")
|
||||||
.HasComment("Расход. Буровой насос 3");
|
.HasComment("Расход. Буровой насос 3");
|
||||||
|
|
||||||
b.Property<float?>("RotorSpeed")
|
b.Property<float>("RotorSpeed")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("rotor_speed")
|
.HasColumnName("rotor_speed")
|
||||||
.HasComment("Обороты ротора");
|
.HasComment("Обороты ротора");
|
||||||
|
|
||||||
b.Property<float?>("RotorTorque")
|
b.Property<float>("RotorTorque")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("rotor_torque")
|
.HasColumnName("rotor_torque")
|
||||||
.HasComment("Момент на роторе");
|
.HasComment("Момент на роторе");
|
||||||
@ -4833,7 +4913,7 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("rotor_torque_sp")
|
.HasColumnName("rotor_torque_sp")
|
||||||
.HasComment("Момент на роторе. Задание");
|
.HasComment("Момент на роторе. Задание");
|
||||||
|
|
||||||
b.Property<float?>("WellDepth")
|
b.Property<float>("WellDepth")
|
||||||
.HasColumnType("real")
|
.HasColumnType("real")
|
||||||
.HasColumnName("well_depth")
|
.HasColumnName("well_depth")
|
||||||
.HasComment("Глубина забоя");
|
.HasComment("Глубина забоя");
|
||||||
@ -7022,6 +7102,36 @@ namespace AsbCloudDb.Migrations
|
|||||||
Id = 33,
|
Id = 33,
|
||||||
Caption = "Техническая колонна 3",
|
Caption = "Техническая колонна 3",
|
||||||
Order = 2.2f
|
Order = 2.2f
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 34,
|
||||||
|
Caption = "Хвостовик 6",
|
||||||
|
Order = 6.5f
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 35,
|
||||||
|
Caption = "Хвостовик 7",
|
||||||
|
Order = 6.6f
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 36,
|
||||||
|
Caption = "Хвостовик 8",
|
||||||
|
Order = 6.7f
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 37,
|
||||||
|
Caption = "Хвостовик 9",
|
||||||
|
Order = 6.8f
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 38,
|
||||||
|
Caption = "Хвостовик 10",
|
||||||
|
Order = 6.9f
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -7846,6 +7956,17 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Navigation("Well");
|
b.Navigation("Well");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.DrillTest", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("IdTelemetry")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Telemetry");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.Faq", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.Faq", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("AsbCloudDb.Model.User", "AuthorAnswer")
|
b.HasOne("AsbCloudDb.Model.User", "AuthorAnswer")
|
||||||
|
@ -84,6 +84,7 @@ namespace AsbCloudDb.Model
|
|||||||
public DbSet<ManualDirectory> ManualDirectories => Set<ManualDirectory>();
|
public DbSet<ManualDirectory> ManualDirectories => Set<ManualDirectory>();
|
||||||
public DbSet<Contact> Contacts => Set<Contact>();
|
public DbSet<Contact> Contacts => Set<Contact>();
|
||||||
|
|
||||||
|
public DbSet<DrillTest> DrillTests => Set<DrillTest>();
|
||||||
public AsbCloudDbContext() : base()
|
public AsbCloudDbContext() : base()
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref referenceCount);
|
Interlocked.Increment(ref referenceCount);
|
||||||
@ -103,7 +104,7 @@ namespace AsbCloudDb.Model
|
|||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
if (!optionsBuilder.IsConfigured)
|
if (!optionsBuilder.IsConfigured)
|
||||||
optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
|
optionsBuilder.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True;"
|
||||||
//, builder=>builder.EnableRetryOnFailure(2, System.TimeSpan.FromMinutes(1))
|
//, builder=>builder.EnableRetryOnFailure(2, System.TimeSpan.FromMinutes(1))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -411,6 +412,15 @@ namespace AsbCloudDb.Model
|
|||||||
.HasForeignKey(m => m.IdDirectory)
|
.HasForeignKey(m => m.IdDirectory)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DrillTest>()
|
||||||
|
.HasKey(m => new { m.Id, m.IdTelemetry });
|
||||||
|
|
||||||
|
modelBuilder.Entity<DrillTest>(entity =>
|
||||||
|
{
|
||||||
|
entity.Property(e => e.Params)
|
||||||
|
.HasJsonConversion();
|
||||||
|
});
|
||||||
|
|
||||||
DefaultData.DefaultContextData.Fill(modelBuilder);
|
DefaultData.DefaultContextData.Fill(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ namespace AsbCloudDb.Model
|
|||||||
[Column("caption")]
|
[Column("caption")]
|
||||||
[StringLength(255)]
|
[StringLength(255)]
|
||||||
public string Caption { get; set; } = null!;
|
public string Caption { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("is_contact")]
|
||||||
public bool IsContact { get; set; }
|
public bool IsContact { get; set; }
|
||||||
|
|
||||||
[Column("order")]
|
[Column("order")]
|
||||||
|
@ -3,9 +3,16 @@
|
|||||||
internal class EntityFillerCompanyType : EntityFiller<CompanyType>
|
internal class EntityFillerCompanyType : EntityFiller<CompanyType>
|
||||||
{
|
{
|
||||||
public override CompanyType[] GetData() => new CompanyType[] {
|
public override CompanyType[] GetData() => new CompanyType[] {
|
||||||
new (){ Id = 1, Caption = "Недрапользователь", Order = 1 },
|
new (){ Id = 1, Caption = "Недропользователь", IsContact = true, Order = 3 },
|
||||||
new (){ Id = 2, Caption = "Буровой подрядчик", Order = 2 },
|
new (){ Id = 2, Caption = "Буровой подрядчик", IsContact = true, Order = 2 },
|
||||||
new (){ Id = 3, Caption = "Сервис автоматизации бурения", Order = 0 }
|
new (){ Id = 3, Caption = "Сервис автоматизации бурения", IsContact = true, Order = 0 },
|
||||||
|
new (){ Id = 4, Caption = "Сервис по ГТИ", IsContact = true, Order = 6 },
|
||||||
|
new (){ Id = 5, Caption = "Растворный сервис", IsContact = true, Order = 4 },
|
||||||
|
new (){ Id = 6, Caption = "Сервис по ННБ", IsContact = true, Order = 5 },
|
||||||
|
new (){ Id = 7, Caption = "Служба супервайзинга", Order = 1 },
|
||||||
|
new (){ Id = 9, Caption = "Сервис по цементированию", IsContact = true, Order = 7 },
|
||||||
|
new (){ Id = 11, Caption = "Дизельный сервис", IsContact = false, Order = 9 },
|
||||||
|
new (){ Id = 12, Caption = "Сервис по обслуживанию верхних силовых приводов", IsContact = true, Order = 8 },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,8 @@
|
|||||||
|
|
||||||
new() { Id = 527, Name = "Manual.delete", Description = "Разрешение на удаление инструкций"},
|
new() { Id = 527, Name = "Manual.delete", Description = "Разрешение на удаление инструкций"},
|
||||||
new (){ Id = 528, Name="WellContact.delete", Description="Разрешение на удаление контакта"},
|
new (){ Id = 528, Name="WellContact.delete", Description="Разрешение на удаление контакта"},
|
||||||
|
|
||||||
|
new (){ Id = 529, Name="DrillTestReport.get", Description="Разрешение на получение отчетов drill test"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ namespace AsbCloudDb.Model.DefaultData
|
|||||||
new () {Id = 12, Name = "АПД слайд", Description = "Режим работы \"Бурение в слайде\""},
|
new () {Id = 12, Name = "АПД слайд", Description = "Режим работы \"Бурение в слайде\""},
|
||||||
new () {Id = 2, Name = "MSE", Description = "Алгоритм поиска оптимальных параметров бурения САУБ"},
|
new () {Id = 2, Name = "MSE", Description = "Алгоритм поиска оптимальных параметров бурения САУБ"},
|
||||||
//Spin master - id подсистем с 65_536 до 131_071
|
//Spin master - id подсистем с 65_536 до 131_071
|
||||||
new () {Id = 65536, Name = "Spin master", Description = "Spin master"},
|
new () {Id = 65536, Name = "Осцилляция", Description = "Осцилляция"},
|
||||||
new () {Id = 65537, Name = "Torque master", Description = "Torque master"}
|
new () {Id = 65537, Name = "Демпфер", Description = "Демпфер"}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,12 @@
|
|||||||
new (){ Id = 31, Caption = "Техническая колонна", Order = 2},
|
new (){ Id = 31, Caption = "Техническая колонна", Order = 2},
|
||||||
new (){ Id = 32, Caption = "Техническая колонна 2", Order = 2.1f},
|
new (){ Id = 32, Caption = "Техническая колонна 2", Order = 2.1f},
|
||||||
new (){ Id = 33, Caption = "Техническая колонна 3", Order = 2.2f},
|
new (){ Id = 33, Caption = "Техническая колонна 3", Order = 2.2f},
|
||||||
|
|
||||||
|
new (){ Id = 34, Caption = "Хвостовик 6", Order = 6.5f},
|
||||||
|
new (){ Id = 35, Caption = "Хвостовик 7", Order = 6.6f},
|
||||||
|
new (){ Id = 36, Caption = "Хвостовик 8", Order = 6.7f},
|
||||||
|
new (){ Id = 37, Caption = "Хвостовик 9", Order = 6.8f},
|
||||||
|
new (){ Id = 38, Caption = "Хвостовик 10", Order = 6.9f},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
AsbCloudDb/Model/DrillTest.cs
Normal file
42
AsbCloudDb/Model/DrillTest.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model
|
||||||
|
{
|
||||||
|
[Table("t_drill_test"), Comment("Drill_test")]
|
||||||
|
public class DrillTest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор drill test
|
||||||
|
/// </summary>
|
||||||
|
[Key, Column("id"), Comment("Идентификатор")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор телеметрии drill test
|
||||||
|
/// </summary>
|
||||||
|
[Key, Column("id_telemetry"), Comment("Идентификатор телеметрии")]
|
||||||
|
public int IdTelemetry { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время начала drill test
|
||||||
|
/// </summary>
|
||||||
|
[Column("timestamp_start", TypeName = "timestamp with time zone"), Comment("Время начала")]
|
||||||
|
public DateTimeOffset TimeStampStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина начала drill test
|
||||||
|
/// </summary>
|
||||||
|
[Column("depthStart"), Comment("Глубина начала")]
|
||||||
|
public float DepthStart { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdTelemetry))]
|
||||||
|
public virtual Telemetry Telemetry { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("t_drill_test_params", TypeName = "jsonb"), Comment("Параметры записи drill test")]
|
||||||
|
public virtual ICollection<DrillTestParameter> Params { get; set; } = null!;
|
||||||
|
}
|
||||||
|
}
|
42
AsbCloudDb/Model/DrillTestParameter.cs
Normal file
42
AsbCloudDb/Model/DrillTestParameter.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры записи drill test
|
||||||
|
/// </summary>
|
||||||
|
public class DrillTestParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Шаг
|
||||||
|
/// </summary>
|
||||||
|
public int Step { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Нагрузка
|
||||||
|
/// </summary>
|
||||||
|
public float? Workload { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Заданная скорость
|
||||||
|
/// </summary>
|
||||||
|
public float? Speed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Скорость проходки
|
||||||
|
/// </summary>
|
||||||
|
public float? DepthSpeed { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время бурения шага
|
||||||
|
/// </summary>
|
||||||
|
public float? TimeDrillStep { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина бурения шага
|
||||||
|
/// </summary>
|
||||||
|
public float? DepthDrillStep { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -76,6 +76,7 @@ namespace AsbCloudDb.Model
|
|||||||
DbSet<Manual> Manuals { get; }
|
DbSet<Manual> Manuals { get; }
|
||||||
DbSet<ManualDirectory> ManualDirectories { get; }
|
DbSet<ManualDirectory> ManualDirectories { get; }
|
||||||
DbSet<Contact> Contacts { get; }
|
DbSet<Contact> Contacts { get; }
|
||||||
|
DbSet<DrillTest> DrillTests { get; }
|
||||||
DatabaseFacade Database { get; }
|
DatabaseFacade Database { get; }
|
||||||
|
|
||||||
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
||||||
|
@ -18,7 +18,7 @@ namespace AsbCloudDb.Model
|
|||||||
public DateTimeOffset DateTime { get; set; }
|
public DateTimeOffset DateTime { get; set; }
|
||||||
|
|
||||||
[Column("mode"), Comment("Режим САУБ")]
|
[Column("mode"), Comment("Режим САУБ")]
|
||||||
public short? Mode { get; set; }
|
public short Mode { get; set; }
|
||||||
|
|
||||||
[Column("id_feed_regulator"), Comment("Текущий критерий бурения")]
|
[Column("id_feed_regulator"), Comment("Текущий критерий бурения")]
|
||||||
public short? IdFeedRegulator { get; set; }
|
public short? IdFeedRegulator { get; set; }
|
||||||
@ -27,13 +27,13 @@ namespace AsbCloudDb.Model
|
|||||||
public short? MseState { get; set; }
|
public short? MseState { get; set; }
|
||||||
|
|
||||||
[Column("well_depth"), Comment("Глубина забоя")]
|
[Column("well_depth"), Comment("Глубина забоя")]
|
||||||
public float? WellDepth { get; set; }
|
public float WellDepth { get; set; }
|
||||||
|
|
||||||
[Column("bit_depth"), Comment("Положение инструмента")]
|
[Column("bit_depth"), Comment("Положение инструмента")]
|
||||||
public float? BitDepth { get; set; }
|
public float BitDepth { get; set; }
|
||||||
|
|
||||||
[Column("block_position"), Comment("Высота талевого блока")]
|
[Column("block_position"), Comment("Высота талевого блока")]
|
||||||
public float? BlockPosition { get; set; }
|
public float BlockPosition { get; set; }
|
||||||
|
|
||||||
[Column("block_position_min"), Comment("Талевый блок. Мин положение")]
|
[Column("block_position_min"), Comment("Талевый блок. Мин положение")]
|
||||||
public float? BlockPositionMin { get; set; }
|
public float? BlockPositionMin { get; set; }
|
||||||
@ -57,7 +57,7 @@ namespace AsbCloudDb.Model
|
|||||||
public float? BlockSpeedSpDevelop { get; set; }
|
public float? BlockSpeedSpDevelop { get; set; }
|
||||||
|
|
||||||
[Column("pressure"), Comment("Давление")]
|
[Column("pressure"), Comment("Давление")]
|
||||||
public float? Pressure { get; set; }
|
public float Pressure { get; set; }
|
||||||
|
|
||||||
[Column("pressure_idle"), Comment("Давление. Холостой ход")]
|
[Column("pressure_idle"), Comment("Давление. Холостой ход")]
|
||||||
public float? PressureIdle { get; set; }
|
public float? PressureIdle { get; set; }
|
||||||
@ -78,7 +78,7 @@ namespace AsbCloudDb.Model
|
|||||||
public float? PressureDeltaLimitMax { get; set; }
|
public float? PressureDeltaLimitMax { get; set; }
|
||||||
|
|
||||||
[Column("axial_load"), Comment("Осевая нагрузка")]
|
[Column("axial_load"), Comment("Осевая нагрузка")]
|
||||||
public float? AxialLoad { get; set; }
|
public float AxialLoad { get; set; }
|
||||||
|
|
||||||
[Column("axial_load_sp"), Comment("Осевая нагрузка. Задание")]
|
[Column("axial_load_sp"), Comment("Осевая нагрузка. Задание")]
|
||||||
public float? AxialLoadSp { get; set; }
|
public float? AxialLoadSp { get; set; }
|
||||||
@ -87,7 +87,7 @@ namespace AsbCloudDb.Model
|
|||||||
public float? AxialLoadLimitMax { get; set; }
|
public float? AxialLoadLimitMax { get; set; }
|
||||||
|
|
||||||
[Column("hook_weight"), Comment("Вес на крюке")]
|
[Column("hook_weight"), Comment("Вес на крюке")]
|
||||||
public float? HookWeight { get; set; }
|
public float HookWeight { get; set; }
|
||||||
|
|
||||||
[Column("hook_weight_idle"), Comment("Вес на крюке. Холостой ход")]
|
[Column("hook_weight_idle"), Comment("Вес на крюке. Холостой ход")]
|
||||||
public float? HookWeightIdle { get; set; }
|
public float? HookWeightIdle { get; set; }
|
||||||
@ -99,7 +99,7 @@ namespace AsbCloudDb.Model
|
|||||||
public float? HookWeightLimitMax { get; set; }
|
public float? HookWeightLimitMax { get; set; }
|
||||||
|
|
||||||
[Column("rotor_torque"), Comment("Момент на роторе")]
|
[Column("rotor_torque"), Comment("Момент на роторе")]
|
||||||
public float? RotorTorque { get; set; }
|
public float RotorTorque { get; set; }
|
||||||
|
|
||||||
[Column("rotor_torque_idle"), Comment("Момент на роторе. Холостой ход")]
|
[Column("rotor_torque_idle"), Comment("Момент на роторе. Холостой ход")]
|
||||||
public float? RotorTorqueIdle { get; set; }
|
public float? RotorTorqueIdle { get; set; }
|
||||||
@ -111,7 +111,7 @@ namespace AsbCloudDb.Model
|
|||||||
public float? RotorTorqueLimitMax { get; set; }
|
public float? RotorTorqueLimitMax { get; set; }
|
||||||
|
|
||||||
[Column("rotor_speed"), Comment("Обороты ротора")]
|
[Column("rotor_speed"), Comment("Обороты ротора")]
|
||||||
public float? RotorSpeed { get; set; }
|
public float RotorSpeed { get; set; }
|
||||||
|
|
||||||
[Column("flow"), Comment("Расход")]
|
[Column("flow"), Comment("Расход")]
|
||||||
public float? Flow { get; set; }
|
public float? Flow { get; set; }
|
||||||
|
265
AsbCloudDb/Setup db replication.md
Normal file
265
AsbCloudDb/Setup db replication.md
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
# Репликация данных PostgreSQL
|
||||||
|
## 1. Требования
|
||||||
|
1. Primary и Replica сервера должны принадлежать одной версии postgreSQL
|
||||||
|
2. Сервера должны иметь удаленный доступ
|
||||||
|
|
||||||
|
|
||||||
|
## 2. Настройка Primary-сервера
|
||||||
|
1. Открыть postgres.conf на редактирование
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /etc/postgresql/15/main/
|
||||||
|
|
||||||
|
sudo nano postgresql.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
2. В postgres.conf найти запись listen_addresses и добавить туда ip standby-сервера
|
||||||
|
|
||||||
|
> listen_addresses = '*, <ip standby-сервера>'
|
||||||
|
|
||||||
|
3. Открыть клиент для работы с postgres
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo -u postgres psql
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Создать пользователя с атрибутом REPLICATION. <br />
|
||||||
|
P.S: В данном примере создается пользователь с логином replicator и паролем q
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'q';
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Открыть на редактирование файл pg_hba.conf
|
||||||
|
```
|
||||||
|
cd /etc/postgresql/15/main/
|
||||||
|
|
||||||
|
sudo nano pg_hba.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Вставить в pg_hba.conf запись.
|
||||||
|
Запись вставлять после комментария "Allow replication connections from localhost..." <br />
|
||||||
|
Данные для вставки записи:<br />
|
||||||
|
- replicator - имя пользователя, созданного на предыдущем шаге<br/>
|
||||||
|
- <ip подсети>, например, 192.168.0.0/24
|
||||||
|
```
|
||||||
|
host replication replicator 192.168.0.0/24 md5
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Рестарт сервера
|
||||||
|
```
|
||||||
|
sudo systemctl restart postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Настройка replica-сервера
|
||||||
|
1. Остановить сервер
|
||||||
|
```
|
||||||
|
sudo systemctl stop postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Важно! Зайти под пользователем postgres
|
||||||
|
```
|
||||||
|
sudo su - postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Сделать резервную копию содержимого /var/lib/postgresql/15/main/ в папку main_old
|
||||||
|
```
|
||||||
|
cp -R /var/lib/postgresql/15/main/ /var/lib/postgresql/15/main_old/
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Удалить папку main
|
||||||
|
```
|
||||||
|
rm -rf /var/lib/postgresql/15/main/
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Используя утилиту basebackup создать базовую резервную копию с правами владения postgres (либо любого пользователя с соответствующими разрешениями).
|
||||||
|
|
||||||
|
```
|
||||||
|
pg_basebackup -h <ip primary-сервера> -D /var/lib/postgresql/14/main/ -U replicator -P -v -R -X stream -C -S slaveslot1
|
||||||
|
|
||||||
|
где: /var/lib/postgresql/15/main/ - каталог replica-сервера
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Убедиться, что в папке main созданы файлы standby.signal и postgresql.auto.conf.
|
||||||
|
```
|
||||||
|
ls -ltrh /var/lib/postgresql/15/main/
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Запустить сервер
|
||||||
|
```
|
||||||
|
systemctl start postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Проверка настроек
|
||||||
|
1. Подсоединиться к primary-серверу
|
||||||
|
```
|
||||||
|
sudo -u postgres psql
|
||||||
|
```
|
||||||
|
|
||||||
|
2. На primary-сервере выполнить команду
|
||||||
|
```
|
||||||
|
SELECT * FROM pg_replication_slots;
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Убедиться, что в представлении отображается слот репликации с именем slotslave1
|
||||||
|
4. На standby-сервере выпонить команду
|
||||||
|
```
|
||||||
|
SELECT * FROM pg_stat_wal_receiver;
|
||||||
|
```
|
||||||
|
5. Убедиться, что появилась запись с ip primary-сервера
|
||||||
|
|
||||||
|
6. На primary - сервере проверить режим репликации. Он может быть синхронным или асинхронным. Для проверки необходимо выполнить команду
|
||||||
|
```
|
||||||
|
SELECT * FROM pg_stat_replication;
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Для включения синхронного режима необходимо выполнить следующую команду
|
||||||
|
```
|
||||||
|
ALTER SYSTEM SET synchronous_standby_names TO '*';
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Сделать рестарт primary-сервера.
|
||||||
|
|
||||||
|
9. Внести запись в любую таблицу базы данных primary-сервера
|
||||||
|
10. Убедиться, что соответствующая запись появилась в таблице базы данных standby-сервера
|
||||||
|
11. Попытаться внести запись в таблицу базы данных standby-сервера.
|
||||||
|
12. Убедиться, что операция завершилась с ошибкой
|
||||||
|
> cannot execute OPERATION in a read-only transaction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 5. Установка PgPool-II
|
||||||
|
|
||||||
|
|
||||||
|
1. Установить на primary-сервер pgpool2 и postgresql-14-pgpool2
|
||||||
|
```
|
||||||
|
apt-get -y install pgpool2 postgresql-15-pgpool2
|
||||||
|
|
||||||
|
```
|
||||||
|
2. Установить на standby-сервер только postgresql-14-pgpool2
|
||||||
|
```
|
||||||
|
apt-get -y install postgresql-15-pgpool2
|
||||||
|
```
|
||||||
|
### Далее все настройки выполнить на primary-сервере
|
||||||
|
3. Зайти на редактирование в конфигурационный файл pgpool2
|
||||||
|
```
|
||||||
|
sudo nano /etc/pgpool2/pgpool.conf
|
||||||
|
```
|
||||||
|
4. Задать параметры следующим образом:
|
||||||
|
```
|
||||||
|
backend_clustering_mode = 'streaming_replication'
|
||||||
|
listen_addresses = '*, <ip standby-сервера>'
|
||||||
|
port = 9999
|
||||||
|
___
|
||||||
|
backend_hostname0 = '<ip primary-сервера>'
|
||||||
|
backend_port0 = '<порт primary-сервера>'
|
||||||
|
backend_weight0 = 0
|
||||||
|
backend_data_directory0 = '/var/lib/postgresql/14/main'
|
||||||
|
___
|
||||||
|
backend_hostname1 = '<ip replica-сервера>'
|
||||||
|
backend_port1 = '<порт primary-сервера>'
|
||||||
|
backend_weight1 = 1
|
||||||
|
___
|
||||||
|
enable_pool_hba = on
|
||||||
|
log_statement = on
|
||||||
|
log_per_node_statement = on
|
||||||
|
pid_file_name = "pgpool.pid"
|
||||||
|
load_balance_mode = on
|
||||||
|
statement_level_load_balance = on
|
||||||
|
sr_check_period = 1
|
||||||
|
sr_check_user = '<имя пользователя>'
|
||||||
|
sr_check_password = '<пароль пользователя>'
|
||||||
|
health_check_period = 10
|
||||||
|
health_check_user = '<имя пользователя>'
|
||||||
|
health_check_password = '<пароль пользователя>'
|
||||||
|
```
|
||||||
|
5. Поскольку enable_pool_hba указан в режиме on, это значит, что Pgpool-II будет использовать pool_hba.conf для аутентификации клиента. Поэтому открываем на редактирование pool_hba.conf
|
||||||
|
```
|
||||||
|
sudo nano /etc/pgpool2/pool_hba.conf
|
||||||
|
```
|
||||||
|
6. Добавить строку
|
||||||
|
```
|
||||||
|
host all all <ip подсети> md5
|
||||||
|
```
|
||||||
|
7. Pgpool-II извлекает пароль пользователя из файла pool_passwd
|
||||||
|
```
|
||||||
|
sudo nano /etc/pgpool2/pool_passwd
|
||||||
|
```
|
||||||
|
Файл паролей представляет собой текстовый файл следующего формата:
|
||||||
|
```
|
||||||
|
пользователь1:пароль1
|
||||||
|
пользователь2:пароль2
|
||||||
|
```
|
||||||
|
Файл может содержать 3 типа паролей. Pgpool-II идентифицирует тип формата пароля по его префиксу, поэтому каждая запись пароля в pool_passwd должна иметь префикс формата пароля.
|
||||||
|
|
||||||
|
- Обычный текст : пароль в текстовом формате с использованием префикса TEXT (например, TEXTmypassword ) .
|
||||||
|
- Зашифрованный пароль AES256 : зашифрованный пароль AES256, используя префикс AES (например, AESmzVzywsN1Z5GABhSAhwLSA== ) .
|
||||||
|
- Хешированный пароль MD5 : хешированный пароль MD5, используя префикс md5 (например, md5270e98c3db83dbc0e40f98d9bfe20972 ) .
|
||||||
|
|
||||||
|
8. В примере в качестве пароля используется обычный текст (пароль q)
|
||||||
|
```
|
||||||
|
postgres:TEXTq
|
||||||
|
```
|
||||||
|
9. Запустить pgpool
|
||||||
|
```
|
||||||
|
sudo pgpool -n
|
||||||
|
```
|
||||||
|
10. Убедиться, что процесс успешно запущен и подключены 2 ноды с разными индексами. В данном примере для primary node установлен индекс 0, а для standBy ноды установден индекс 1
|
||||||
|
```
|
||||||
|
|
||||||
|
2023-09-14 06:08:08.339: main pid 3941: LOG: find_primary_node: primary node is 0
|
||||||
|
2023-09-14 06:08:08.339: main pid 3941: LOG: find_primary_node: standby node is 1
|
||||||
|
2023-09-14 06:08:08.343: pcp_main pid 3977: LOG: PCP process: 3977 started
|
||||||
|
2023-09-14 06:08:08.343: sr_check_worker pid 3978: LOG: process started
|
||||||
|
2023-09-14 06:08:08.345: health_check pid 3979: LOG: process started
|
||||||
|
2023-09-14 06:08:08.349: health_check pid 3980: LOG: process started
|
||||||
|
2023-09-14 06:08:08.559: main pid 3941: LOG: pgpool-II successfully started. version 4.3.5 (tamahomeboshi)
|
||||||
|
2023-09-14 06:08:08.662: main pid 3941: LOG: node status[0]: 1
|
||||||
|
2023-09-14 06:08:08.662: main pid 3941: LOG: node status[1]: 2
|
||||||
|
|
||||||
|
```
|
||||||
|
11. При старте pgpool возможны следующие ошибки:
|
||||||
|
- файл pgpool_status не найден / нет прав
|
||||||
|
- pgpool стартует, но ноды имеют одинаковый индекс и балансировка идет только на первую ноду (как проверить балансировку указано ниже) <br/>
|
||||||
|
|
||||||
|
Проблема решилась удалением файла pgpool_status, откуда pgpool пытался считывать статусы для нод.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /var/log/postgresql
|
||||||
|
rm -rf pgpool_status
|
||||||
|
sudo systemctl restart postgresql
|
||||||
|
sudo pgpool -n
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Тестирование балансировки PgPool-II
|
||||||
|
1. При запущенном pgpool (он должен выводить логи), открыть еще один терминал. Зайти в базу, используя Pgpool-II на 9999-порте, выполнив команду
|
||||||
|
```
|
||||||
|
psql -h <ip сервера, где установлен pgpool> -p 9999 -d postgres -U postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Выполнить команду
|
||||||
|
```
|
||||||
|
show pool_nodes;
|
||||||
|
```
|
||||||
|
3. Убедиться, что обе ноды находятся в статусе up, а балансировка установлена на standBy-сервере (load_balance_node = true)
|
||||||
|
```
|
||||||
|
node_id | hostname | port | status | pg_status | lb_weight | role | pg_role | select_cnt | load_balance_node | replication_delay | replication_state | replication_sync_state | last_status_change
|
||||||
|
---------+--------------+------+--------+-----------+-----------+---------+---------+------------+-------------------+-------------------+-------------------+------------------------+---------------------
|
||||||
|
0 | 192.168.0.71 | 5432 | up | up | 0.000000 | primary | primary | 0 | false | 0 | | | 2023-09-14 06:36:16
|
||||||
|
1 | 192.168.0.72 | 5432 | up | up | 1.000000 | standby | standby | 0 | true | 0 | | | 2023-09-14 06:36:16
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
```
|
||||||
|
4. Выполнить команды Insert / Update / Delete (в качесве примера была внесена запись в таблицу public.t_company). Убедиться, что запрос приходит на primary-сервер (нода с индексом 0).
|
||||||
|
|
||||||
|
```
|
||||||
|
2023-09-14 07:04:31.800: DBeaver 23.1.2 - Main <postgres> pid 4805: LOG: DB node id: 0 backend pid: 4814 statement: Execute: INSERT INTO public.t_company (id,caption,id_company_type)
|
||||||
|
VALUES ($1,$2,$3)
|
||||||
|
|
||||||
|
```
|
||||||
|
5. Выполинть команду Select. Убедиться, что запрос приходит на standBy-сервер (нода с индексом 1).
|
||||||
|
```
|
||||||
|
|
||||||
|
2023-09-14 07:53:19.275: DBeaver 23.1.2 - Main <postgres> pid 5069: LOG: DB node id: 1 backend pid: 2745 statement: Execute: SELECT x.* FROM public.t_company x
|
||||||
|
|
||||||
|
```
|
@ -13,6 +13,7 @@
|
|||||||
<None Remove="CommonLibs\logo_720x404.png" />
|
<None Remove="CommonLibs\logo_720x404.png" />
|
||||||
<None Remove="CommonLibs\Readme.md" />
|
<None Remove="CommonLibs\Readme.md" />
|
||||||
<None Remove="Services\DailyReport\DailyReportTemplate.xlsx" />
|
<None Remove="Services\DailyReport\DailyReportTemplate.xlsx" />
|
||||||
|
<None Remove="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
|
||||||
<None Remove="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
|
<None Remove="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
|
||||||
<None Remove="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
<None Remove="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
||||||
<None Remove="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
|
<None Remove="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
|
||||||
@ -31,6 +32,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
|
<EmbeddedResource Include="Services\DetectOperations\DetectOperations.xlsx" />
|
||||||
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\DailyReport\DailyReportTemplate.xlsx" />
|
||||||
|
<EmbeddedResource Include="Services\DrillTestReport\DrillTestReportTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
|
<EmbeddedResource Include="Services\Trajectory\PlannedTrajectoryTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\AutoGeneratedDailyReports\AutogeneratedDailyReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\AutoGeneratedDailyReports\AutogeneratedDailyReportTemplate.xlsx" />
|
||||||
|
30
AsbCloudInfrastructure/AssemblyExtensions.cs
Normal file
30
AsbCloudInfrastructure/AssemblyExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure
|
||||||
|
{
|
||||||
|
public static class AssemblyExtensions
|
||||||
|
{
|
||||||
|
public static async Task<Stream> GetTemplateCopyStreamAsync(this Assembly assembly, string templateName, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var resourceName = assembly
|
||||||
|
.GetManifestResourceNames()
|
||||||
|
.FirstOrDefault(n => n.EndsWith(templateName))!;
|
||||||
|
|
||||||
|
using var stream = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream(resourceName)!;
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
await stream.CopyToAsync(memoryStream, cancellationToken);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -11,13 +14,39 @@ namespace AsbCloudInfrastructure.Background;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class BackgroundWorker : BackgroundService
|
public class BackgroundWorker : BackgroundService
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
|
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
|
||||||
private static readonly TimeSpan minDelay = TimeSpan.FromSeconds(2);
|
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
public WorkStore WorkStore { get; } = new WorkStore();
|
/// <summary>
|
||||||
|
/// Очередь работ
|
||||||
|
/// </summary>
|
||||||
|
private Queue<Work> works = new(8);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Список периодических работ
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Work> Works => works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа выполняемая в данный момент
|
||||||
|
/// </summary>
|
||||||
public Work? CurrentWork;
|
public Work? CurrentWork;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// последние 16 завершившиеся с ошибкой
|
||||||
|
/// </summary>
|
||||||
|
public CyclycArray<Work> Felled { get; } = new(16);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// последние 16 успешно завершенных
|
||||||
|
/// </summary>
|
||||||
|
public CyclycArray<Work> Done { get; } = new(16);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка в главном цикле, никогда не должна появляться
|
||||||
|
/// </summary>
|
||||||
|
public string MainLoopLastException { get; private set; } = string.Empty;
|
||||||
|
|
||||||
public BackgroundWorker(IServiceProvider serviceProvider)
|
public BackgroundWorker(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
this.serviceProvider = serviceProvider;
|
this.serviceProvider = serviceProvider;
|
||||||
@ -25,25 +54,65 @@ public class BackgroundWorker : BackgroundService
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken token)
|
protected override async Task ExecuteAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
while (!token.IsCancellationRequested)
|
Trace.TraceInformation($"{GetType().Name} started");
|
||||||
|
while (!token.IsCancellationRequested && works.TryDequeue(out CurrentWork))
|
||||||
{
|
{
|
||||||
var work = WorkStore.GetNext();
|
try
|
||||||
if (work is null)
|
|
||||||
{
|
{
|
||||||
await Task.Delay(executePeriod, token);
|
using var scope = serviceProvider.CreateScope();
|
||||||
continue;
|
|
||||||
|
var result = await CurrentWork.Start(scope.ServiceProvider, token);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
Felled.Add(CurrentWork);
|
||||||
|
else
|
||||||
|
Done.Add(CurrentWork);
|
||||||
|
|
||||||
|
CurrentWork = null;
|
||||||
|
await Task.Delay(minDelay, token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MainLoopLastException = $"BackgroundWorker " +
|
||||||
|
$"MainLoopLastException: \r\n" +
|
||||||
|
$"date: {DateTime.Now:O}\r\n" +
|
||||||
|
$"message: {ex.Message}\r\n" +
|
||||||
|
$"inner: {ex.InnerException?.Message}\r\n" +
|
||||||
|
$"stackTrace: {ex.StackTrace}";
|
||||||
|
Trace.TraceError(MainLoopLastException);
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentWork = work;
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
|
||||||
|
|
||||||
var result = await work.Start(scope.ServiceProvider, token);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
WorkStore.Felled.Add(work);
|
|
||||||
|
|
||||||
CurrentWork = null;
|
|
||||||
await Task.Delay(minDelay, token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в очередь
|
||||||
|
/// <para>
|
||||||
|
/// work.Id может быть не уникальным,
|
||||||
|
/// при этом метод TryRemoveFromQueue удалит все работы с совпадающими id
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="work"></param>
|
||||||
|
public void Enqueue(Work work)
|
||||||
|
{
|
||||||
|
works.Enqueue(work);
|
||||||
|
if (ExecuteTask is null || ExecuteTask.IsCompleted)
|
||||||
|
StartAsync(CancellationToken.None).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление работы по ID из одноразовой очереди
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool TryRemoveFromQueue(string id)
|
||||||
|
{
|
||||||
|
var work = Works.FirstOrDefault(w => w.Id == id);
|
||||||
|
if (work is not null)
|
||||||
|
{
|
||||||
|
works = new Queue<Work>(Works.Where(w => w.Id != id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace System.Collections.Generic
|
|
||||||
{
|
|
||||||
public class OrderedList<T>: IEnumerable<T>, ICollection<T>
|
|
||||||
where T : notnull
|
|
||||||
{
|
|
||||||
private readonly List<T> list = new List<T>();
|
|
||||||
|
|
||||||
private readonly Func<T, object> keySelector;
|
|
||||||
private readonly bool isDescending = false;
|
|
||||||
|
|
||||||
private IOrderedEnumerable<T> OrdredList => isDescending
|
|
||||||
? list.OrderByDescending(keySelector)
|
|
||||||
: list.OrderBy(keySelector);
|
|
||||||
|
|
||||||
public int Count => list.Count;
|
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public OrderedList(Func<T, object> keySelector, bool isDescending = false)
|
|
||||||
{
|
|
||||||
this.keySelector = keySelector;
|
|
||||||
this.isDescending = isDescending;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(T item) => list.Add(item);
|
|
||||||
|
|
||||||
public void Clear()=> list.Clear();
|
|
||||||
|
|
||||||
public bool Contains(T item)=> list.Contains(item);
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)=> list.CopyTo(array, arrayIndex);
|
|
||||||
|
|
||||||
public bool Remove(T item)=> list.Remove(item);
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => OrdredList.GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
116
AsbCloudInfrastructure/Background/PeriodicBackgroundWorker.cs
Normal file
116
AsbCloudInfrastructure/Background/PeriodicBackgroundWorker.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Background;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для фонового выполнения периодической работы
|
||||||
|
/// </summary>
|
||||||
|
public class PeriodicBackgroundWorker : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly TimeSpan executePeriod = TimeSpan.FromSeconds(10);
|
||||||
|
private readonly TimeSpan minDelay = TimeSpan.FromSeconds(1);
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
private readonly List<WorkPeriodic> works = new(8);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Список периодических работ
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<WorkPeriodic> Works => works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа выполняемая в данный момент
|
||||||
|
/// </summary>
|
||||||
|
public Work? CurrentWork;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка в главном цикле, никогда не должна появляться
|
||||||
|
/// </summary>
|
||||||
|
public string MainLoopLastException { get; private set; } = string.Empty;
|
||||||
|
|
||||||
|
public PeriodicBackgroundWorker(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
this.serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation($"{GetType().Name} started");
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var periodicWork = GetNext();
|
||||||
|
if (periodicWork is null)
|
||||||
|
{
|
||||||
|
await Task.Delay(executePeriod, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentWork = periodicWork.Work;
|
||||||
|
|
||||||
|
using var scope = serviceProvider.CreateScope();
|
||||||
|
|
||||||
|
var result = await periodicWork.Work.Start(scope.ServiceProvider, token);
|
||||||
|
|
||||||
|
CurrentWork = null;
|
||||||
|
await Task.Delay(minDelay, token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MainLoopLastException = $"BackgroundWorker " +
|
||||||
|
$"MainLoopLastException: \r\n" +
|
||||||
|
$"date: {DateTime.Now:O}\r\n" +
|
||||||
|
$"message: {ex.Message}\r\n" +
|
||||||
|
$"inner: {ex.InnerException?.Message}\r\n" +
|
||||||
|
$"stackTrace: {ex.StackTrace}";
|
||||||
|
Trace.TraceError(MainLoopLastException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="period"></param>
|
||||||
|
public void Add<T>(TimeSpan period)
|
||||||
|
where T : Work, new()
|
||||||
|
{
|
||||||
|
var work = new T();
|
||||||
|
var periodic = new WorkPeriodic(work, period);
|
||||||
|
works.Add(periodic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="work"></param>
|
||||||
|
/// <param name="period"></param>
|
||||||
|
public void Add(Work work, TimeSpan period)
|
||||||
|
{
|
||||||
|
var periodic = new WorkPeriodic(work, period);
|
||||||
|
works.Add(periodic);
|
||||||
|
if (ExecuteTask is null || ExecuteTask.IsCompleted)
|
||||||
|
StartAsync(CancellationToken.None).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorkPeriodic? GetNext()
|
||||||
|
{
|
||||||
|
var work = works
|
||||||
|
.OrderBy(w => w.NextStart)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (work is null || work.NextStart > DateTime.Now)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -12,6 +13,8 @@ namespace AsbCloudInfrastructure.Background;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Work : BackgroundWorkDto
|
public abstract class Work : BackgroundWorkDto
|
||||||
{
|
{
|
||||||
|
private CancellationTokenSource? stoppingCts;
|
||||||
|
|
||||||
private sealed class WorkBase : Work
|
private sealed class WorkBase : Work
|
||||||
{
|
{
|
||||||
private Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; }
|
private Func<string, IServiceProvider, Action<string, double?>, CancellationToken, Task> ActionAsync { get; }
|
||||||
@ -68,8 +71,9 @@ public abstract class Work : BackgroundWorkDto
|
|||||||
SetStatusStart();
|
SetStatusStart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var task = Action(Id, services, UpdateStatus, token);
|
stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||||
await task.WaitAsync(Timeout, token);
|
var task = Action(Id, services, UpdateStatus, stoppingCts.Token);
|
||||||
|
await task.WaitAsync(Timeout, stoppingCts.Token);
|
||||||
SetStatusComplete();
|
SetStatusComplete();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,15 +83,28 @@ public abstract class Work : BackgroundWorkDto
|
|||||||
SetLastError(message);
|
SetLastError(message);
|
||||||
if (OnErrorAsync is not null)
|
if (OnErrorAsync is not null)
|
||||||
{
|
{
|
||||||
var task = Task.Run(
|
try
|
||||||
async () => await OnErrorAsync(Id, exception, token),
|
{
|
||||||
token);
|
var task = Task.Run(
|
||||||
await task.WaitAsync(OnErrorHandlerTimeout, token);
|
async () => await OnErrorAsync(Id, exception, token),
|
||||||
|
token);
|
||||||
|
await task.WaitAsync(OnErrorHandlerTimeout, token);
|
||||||
|
}
|
||||||
|
catch (Exception onErrorAsyncException)
|
||||||
|
{
|
||||||
|
var message2 = FormatExceptionMessage(onErrorAsyncException);
|
||||||
|
Trace.TraceError($"Backgroud work:\"{Id}\" OnError handler throws exception: {message2}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
stoppingCts?.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatExceptionMessage(Exception exception)
|
private static string FormatExceptionMessage(Exception exception)
|
||||||
{
|
{
|
||||||
var firstException = FirstException(exception);
|
var firstException = FirstException(exception);
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Background;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>
|
|
||||||
/// Очередь работ
|
|
||||||
/// </para>
|
|
||||||
/// Не периодические задачи будут возвращаться первыми, как самые приоритетные.
|
|
||||||
/// </summary>
|
|
||||||
public class WorkStore
|
|
||||||
{
|
|
||||||
private readonly List<WorkPeriodic> periodics = new(8);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Список периодических задач
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<WorkPeriodic> Periodics => periodics;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Работы выполняемые один раз
|
|
||||||
/// </summary>
|
|
||||||
public Queue<Work> RunOnceQueue { get; private set; } = new(8);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Завершившиеся с ошибкой
|
|
||||||
/// </summary>
|
|
||||||
public CyclycArray<Work> Felled { get; } = new(16);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="period"></param>
|
|
||||||
public void AddPeriodic<T>(TimeSpan period)
|
|
||||||
where T : Work, new()
|
|
||||||
{
|
|
||||||
var work = new T();
|
|
||||||
var periodic = new WorkPeriodic(work, period);
|
|
||||||
periodics.Add(periodic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавить фоновую работу выполняющуюся с заданным периодом
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="work"></param>
|
|
||||||
/// <param name="period"></param>
|
|
||||||
public void AddPeriodic(Work work, TimeSpan period)
|
|
||||||
{
|
|
||||||
var periodic = new WorkPeriodic(work, period);
|
|
||||||
periodics.Add(periodic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Удаление работы по ID из одноразовой очереди
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryRemoveFromRunOnceQueue(string id)
|
|
||||||
{
|
|
||||||
var work = RunOnceQueue.FirstOrDefault(w => w.Id == id);
|
|
||||||
if (work is not null)
|
|
||||||
{
|
|
||||||
RunOnceQueue = new Queue<Work>(RunOnceQueue.Where(w => w.Id != id));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>
|
|
||||||
/// Возвращает приоритетную задачу.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Если приоритетные закончились, то ищет ближайшую периодическую.
|
|
||||||
/// Если до старта ближайшей периодической работы меньше 20 сек,
|
|
||||||
/// то этой задаче устанавливается время последнего запуска в now и она возвращается.
|
|
||||||
/// Если больше 20 сек, то возвращается null.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="maxTimeToNextWork"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Work? GetNext()
|
|
||||||
{
|
|
||||||
if (RunOnceQueue.Any())
|
|
||||||
return RunOnceQueue.Dequeue();
|
|
||||||
|
|
||||||
var work = GetNextPeriodic();
|
|
||||||
if (work is null || work.NextStart > DateTime.Now)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return work.Work;
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorkPeriodic? GetNextPeriodic()
|
|
||||||
{
|
|
||||||
var work = Periodics
|
|
||||||
.OrderBy(w => w.NextStart)
|
|
||||||
.FirstOrDefault();
|
|
||||||
return work;
|
|
||||||
}
|
|
||||||
}
|
|
34
AsbCloudInfrastructure/Background/WorkToDeleteOldReports.cs
Normal file
34
AsbCloudInfrastructure/Background/WorkToDeleteOldReports.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using AsbCloudApp.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Background
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Задача по удалению загруженных отчетов
|
||||||
|
/// </summary>
|
||||||
|
public class WorkToDeleteOldReports : Work
|
||||||
|
{
|
||||||
|
public WorkToDeleteOldReports()
|
||||||
|
: base("work to delete reports older than 30 days")
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromMinutes(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление отчетов, загруженных ранее 30 дней от текущей даты
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="onProgressCallback"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
||||||
|
{
|
||||||
|
var reportService = services.GetRequiredService<IReportService>();
|
||||||
|
await reportService.DeleteAllOldReportsAsync(TimeSpan.FromDays(30), token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
AsbCloudInfrastructure/Background/readme.md
Normal file
11
AsbCloudInfrastructure/Background/readme.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# BackgroundWorker
|
||||||
|
Класс выполнения разовой фоновой работы.
|
||||||
|
Для каждой работы создается свой scope.
|
||||||
|
|
||||||
|
# NotificationBackgroundWorker
|
||||||
|
Предназначен для различных оповещений пользователей разными способами.
|
||||||
|
Фактически это дополнительный экземпляр BackgroundWorker, чтобы оповещения не ждали завершения долгих операций из стандартного BackgroundWorker.
|
||||||
|
Не должен давать большой нагрузки БД.
|
||||||
|
|
||||||
|
# PeriodicBackgroundWorker
|
||||||
|
Класс выполнения периодической фоновой работы.
|
@ -1,12 +0,0 @@
|
|||||||
# Проблемы фонового сервиса
|
|
||||||
- Нужно состояние по загрузки сервиса и очереди работ.
|
|
||||||
- Все ли задачи укладываются в таймаут,
|
|
||||||
- Сколько свободного времени остается,
|
|
||||||
- Что делает текущая задача,
|
|
||||||
- нет управления сервисом. Для исключения его влияния на другие процессы сервера.
|
|
||||||
- отключать/включать целиком
|
|
||||||
- отключать/включать отдельную периодическую задачу
|
|
||||||
|
|
||||||
# Сделать
|
|
||||||
- Разработать dto статуса задачи
|
|
||||||
- Отказаться от периодической задачи, при добавлении в хранилище задач период будет параметром метода добавления.
|
|
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.AutogeneratedDailyReport;
|
||||||
|
using AsbCloudApp.Data.DrillTestReport;
|
||||||
using AsbCloudApp.Data.Manuals;
|
using AsbCloudApp.Data.Manuals;
|
||||||
using AsbCloudApp.Data.ProcessMaps;
|
using AsbCloudApp.Data.ProcessMaps;
|
||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
@ -24,6 +26,7 @@ using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
|||||||
using AsbCloudInfrastructure.Services.DailyReport;
|
using AsbCloudInfrastructure.Services.DailyReport;
|
||||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
using AsbCloudInfrastructure.Services.DrillingProgram;
|
using AsbCloudInfrastructure.Services.DrillingProgram;
|
||||||
|
using AsbCloudInfrastructure.Services.DrillTestReport;
|
||||||
using AsbCloudInfrastructure.Services.ProcessMaps.Report;
|
using AsbCloudInfrastructure.Services.ProcessMaps.Report;
|
||||||
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
|
using AsbCloudInfrastructure.Services.ProcessMaps.WellDrilling;
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
@ -43,268 +46,273 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
public static class DependencyInjection
|
public static class DependencyInjection
|
||||||
{
|
{
|
||||||
public static IAsbCloudDbContext MakeContext(string connectionString)
|
public static IAsbCloudDbContext MakeContext(string connectionString)
|
||||||
{
|
{
|
||||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||||
.UseNpgsql(connectionString)
|
.UseNpgsql(connectionString)
|
||||||
.Options;
|
.Options;
|
||||||
var context = new AsbCloudDbContext(options);
|
var context = new AsbCloudDbContext(options);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapsterSetup()
|
public static void MapsterSetup()
|
||||||
{
|
{
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<DateTimeOffset, DateTime>()
|
.ForType<DateTimeOffset, DateTime>()
|
||||||
.MapWith((source) => source.DateTime);
|
.MapWith((source) => source.DateTime);
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<DateTime, DateTimeOffset>()
|
.ForType<DateTime, DateTimeOffset>()
|
||||||
.MapWith((source) => source == default ? new DateTime(0, DateTimeKind.Utc) : source);
|
.MapWith((source) => source == default ? new DateTime(0, DateTimeKind.Utc) : source);
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<TimeDto, TimeOnly>()
|
.ForType<TimeDto, TimeOnly>()
|
||||||
.MapWith((source) => source.MakeTimeOnly());
|
.MapWith((source) => source.MakeTimeOnly());
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<TimeOnly, TimeDto>()
|
.ForType<TimeOnly, TimeDto>()
|
||||||
.MapWith((source) => new(source));
|
.MapWith((source) => new(source));
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<TimeOnly, TimeDto>()
|
.ForType<TimeOnly, TimeDto>()
|
||||||
.MapWith((source) => new(source));
|
.MapWith((source) => new(source));
|
||||||
|
|
||||||
#pragma warning disable CS8603 // Possible null reference return.
|
#pragma warning disable CS8603 // Possible null reference return.
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<WellDto, Well>()
|
.ForType<WellDto, Well>()
|
||||||
.Ignore(dst => dst.Cluster,
|
.Ignore(dst => dst.Cluster,
|
||||||
dst => dst.RelationCompaniesWells,
|
dst => dst.RelationCompaniesWells,
|
||||||
dst => dst.Telemetry,
|
dst => dst.Telemetry,
|
||||||
dst => dst.WellComposites,
|
dst => dst.WellComposites,
|
||||||
dst => dst.WellCompositeSrcs,
|
dst => dst.WellCompositeSrcs,
|
||||||
dst => dst.WellOperations,
|
dst => dst.WellOperations,
|
||||||
dst => dst.WellType);
|
dst => dst.WellType);
|
||||||
#pragma warning restore CS8603 // Possible null reference return.
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<ClusterDto, Cluster>()
|
.ForType<ClusterDto, Cluster>()
|
||||||
.Ignore(dst => dst.Deposit,
|
.Ignore(dst => dst.Deposit,
|
||||||
dst => dst.Wells);
|
dst => dst.Wells);
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<FileCategoryDto, FileCategory>();
|
.ForType<FileCategoryDto, FileCategory>();
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<WellFinalDocumentDto, WellFinalDocument>();
|
.ForType<WellFinalDocumentDto, WellFinalDocument>();
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<NotificationDto, Notification>()
|
.ForType<NotificationDto, Notification>()
|
||||||
.Ignore(dst => dst.NotificationCategory,
|
.Ignore(dst => dst.NotificationCategory,
|
||||||
dst => dst.User);
|
dst => dst.User);
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<ProcessMapWellDrilling, ProcessMapPlanWellDrillingDto>()
|
.ForType<ProcessMapWellDrilling, ProcessMapPlanWellDrillingDto>()
|
||||||
.Map(dest => dest.AxialLoad, src => new PlanLimitDto
|
.Map(dest => dest.AxialLoad, src => new PlanLimitDto
|
||||||
{
|
{
|
||||||
LimitMax = src.AxialLoadLimitMax,
|
LimitMax = src.AxialLoadLimitMax,
|
||||||
Plan = src.AxialLoadPlan
|
Plan = src.AxialLoadPlan
|
||||||
})
|
})
|
||||||
.Map(dest => dest.Flow, src => new PlanLimitDto
|
.Map(dest => dest.Flow, src => new PlanLimitDto
|
||||||
{
|
{
|
||||||
LimitMax = src.FlowLimitMax,
|
LimitMax = src.FlowLimitMax,
|
||||||
Plan = src.FlowPlan
|
Plan = src.FlowPlan
|
||||||
})
|
})
|
||||||
.Map(dest => dest.Pressure, src => new PlanLimitDto
|
.Map(dest => dest.Pressure, src => new PlanLimitDto
|
||||||
{
|
{
|
||||||
LimitMax = src.PressureLimitMax,
|
LimitMax = src.PressureLimitMax,
|
||||||
Plan = src.PressurePlan
|
Plan = src.PressurePlan
|
||||||
})
|
})
|
||||||
.Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto
|
.Map(dest => dest.TopDriveSpeed, src => new PlanLimitDto
|
||||||
{
|
{
|
||||||
LimitMax = src.TopDriveSpeedLimitMax,
|
LimitMax = src.TopDriveSpeedLimitMax,
|
||||||
Plan = src.TopDriveSpeedPlan
|
Plan = src.TopDriveSpeedPlan
|
||||||
})
|
})
|
||||||
.Map(dest => dest.TopDriveTorque, src => new PlanLimitDto
|
.Map(dest => dest.TopDriveTorque, src => new PlanLimitDto
|
||||||
{
|
{
|
||||||
LimitMax = src.TopDriveTorqueLimitMax,
|
LimitMax = src.TopDriveTorqueLimitMax,
|
||||||
Plan = src.TopDriveTorquePlan
|
Plan = src.TopDriveTorquePlan
|
||||||
});
|
});
|
||||||
|
|
||||||
TypeAdapterConfig.GlobalSettings.Default.Config
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
.ForType<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>()
|
.ForType<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>()
|
||||||
.Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan)
|
.Map(dest => dest.AxialLoadPlan, src => src.AxialLoad.Plan)
|
||||||
.Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax)
|
.Map(dest => dest.AxialLoadLimitMax, src => src.AxialLoad.LimitMax)
|
||||||
.Map(dest => dest.FlowPlan, src => src.Flow.Plan)
|
.Map(dest => dest.FlowPlan, src => src.Flow.Plan)
|
||||||
.Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax)
|
.Map(dest => dest.FlowLimitMax, src => src.Flow.LimitMax)
|
||||||
.Map(dest => dest.PressurePlan, src => src.Pressure.Plan)
|
.Map(dest => dest.PressurePlan, src => src.Pressure.Plan)
|
||||||
.Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax)
|
.Map(dest => dest.PressureLimitMax, src => src.Pressure.LimitMax)
|
||||||
.Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan)
|
.Map(dest => dest.TopDriveSpeedPlan, src => src.TopDriveSpeed.Plan)
|
||||||
.Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax)
|
.Map(dest => dest.TopDriveSpeedLimitMax, src => src.TopDriveSpeed.LimitMax)
|
||||||
.Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan)
|
.Map(dest => dest.TopDriveTorquePlan, src => src.TopDriveTorque.Plan)
|
||||||
.Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax);
|
.Map(dest => dest.TopDriveTorqueLimitMax, src => src.TopDriveTorque.LimitMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
MapsterSetup();
|
MapsterSetup();
|
||||||
string connectionStringName = "DefaultConnection";
|
string connectionStringName = "DefaultConnection";
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
connectionStringName = "DebugConnection";
|
connectionStringName = "DebugConnection";
|
||||||
#endif
|
#endif
|
||||||
services.AddDbContext<AsbCloudDbContext>(options =>
|
services.AddDbContext<AsbCloudDbContext>(options =>
|
||||||
options.UseNpgsql(configuration.GetConnectionString(connectionStringName)));
|
options.UseNpgsql(configuration.GetConnectionString(connectionStringName)));
|
||||||
|
|
||||||
|
|
||||||
services.AddMemoryCache();
|
services.AddMemoryCache();
|
||||||
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
|
services.AddScoped<IAsbCloudDbContext>(provider => provider.GetRequiredService<AsbCloudDbContext>());
|
||||||
|
|
||||||
services.AddSingleton(new WitsInfoService());
|
services.AddSingleton(new WitsInfoService());
|
||||||
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
services.AddSingleton<ITelemetryDataCache<TelemetryDataSaubDto>>(provider =>
|
||||||
services.AddSingleton(provider => TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(provider));
|
||||||
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
services.AddSingleton<ITelemetryDataCache<TelemetryDataSpinDto>>(provider =>
|
||||||
services.AddSingleton<BackgroundWorker>();
|
TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(provider));
|
||||||
services.AddSingleton<NotificationBackgroundWorker>();
|
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
|
||||||
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
services.AddSingleton<PeriodicBackgroundWorker>();
|
||||||
|
services.AddSingleton<BackgroundWorker>();
|
||||||
|
services.AddSingleton<NotificationBackgroundWorker>();
|
||||||
|
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
|
||||||
|
|
||||||
services.AddTransient<IAuthService, AuthService>();
|
services.AddTransient<IAuthService, AuthService>();
|
||||||
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>, ProcessMapPlanRepository<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>>();
|
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>, ProcessMapPlanRepository<ProcessMapPlanWellDrillingDto, ProcessMapWellDrilling>>();
|
||||||
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellReamDto>, ProcessMapPlanRepository<ProcessMapPlanWellReamDto, ProcessMapWellReam>>();
|
services.AddTransient<IProcessMapPlanRepository<ProcessMapPlanWellReamDto>, ProcessMapPlanRepository<ProcessMapPlanWellReamDto, ProcessMapWellReam>>();
|
||||||
services.AddTransient<IDepositRepository, DepositRepository>();
|
services.AddTransient<IDepositRepository, DepositRepository>();
|
||||||
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
|
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
|
||||||
services.AddTransient<IEventService, EventService>();
|
services.AddTransient<IEventService, EventService>();
|
||||||
services.AddTransient<FileService>();
|
services.AddTransient<FileService>();
|
||||||
services.AddTransient<IMeasureService, MeasureService>();
|
services.AddTransient<IMeasureService, MeasureService>();
|
||||||
services.AddTransient<IMessageService, MessageService>();
|
services.AddTransient<IMessageService, MessageService>();
|
||||||
services.AddTransient<IOperationsStatService, OperationsStatService>();
|
services.AddTransient<IOperationsStatService, OperationsStatService>();
|
||||||
services.AddTransient<IReportService, ReportService>();
|
services.AddTransient<IReportService, ReportService>();
|
||||||
services.AddTransient<ISetpointsService, SetpointsService>();
|
services.AddTransient<ISetpointsService, SetpointsService>();
|
||||||
services.AddTransient<ITelemetryService, TelemetryService>();
|
services.AddTransient<ITelemetryService, TelemetryService>();
|
||||||
services.AddTransient<ITelemetryUserService, TelemetryUserService>();
|
services.AddTransient<ITelemetryUserService, TelemetryUserService>();
|
||||||
services.AddTransient<ITimezoneService, TimezoneService>();
|
services.AddTransient<ITimezoneService, TimezoneService>();
|
||||||
services.AddTransient<IWellService, WellService>();
|
services.AddTransient<IWellService, WellService>();
|
||||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||||
services.AddTransient<IProcessMapReportWellDrillingExportService, ProcessMapReportWellDrillingExportService>();
|
services.AddTransient<IProcessMapReportWellDrillingExportService, ProcessMapReportWellDrillingExportService>();
|
||||||
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
|
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
|
||||||
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
||||||
services.AddTransient<IScheduleReportService, ScheduleReportService>();
|
services.AddTransient<IDailyReportService, DailyReportService>();
|
||||||
services.AddTransient<IDailyReportService, DailyReportService>();
|
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
|
||||||
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
|
services.AddTransient<ISubsystemOperationTimeService, SubsystemOperationTimeService>();
|
||||||
services.AddTransient<ISubsystemOperationTimeService, SubsystemOperationTimeService>();
|
services.AddTransient<IScheduleRepository, ScheduleRepository>();
|
||||||
services.AddTransient<IScheduleRepository, ScheduleRepository>();
|
services.AddTransient<IRepositoryWellRelated<OperationValueDto>, CrudWellRelatedRepositoryBase<OperationValueDto, OperationValue>>();
|
||||||
services.AddTransient<IRepositoryWellRelated<OperationValueDto>, CrudWellRelatedRepositoryBase<OperationValueDto, OperationValue>>();
|
services.AddTransient<IUserSettingsRepository, UserSettingsRepository>();
|
||||||
services.AddTransient<IUserSettingsRepository, UserSettingsRepository>();
|
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
|
||||||
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
|
services.AddTransient<IFileCategoryService, FileCategoryService>();
|
||||||
services.AddTransient<IFileCategoryService, FileCategoryService>();
|
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
||||||
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
services.AddTransient<IProcessMapReportWellDrillingService, ProcessMapReportWellDrillingService>();
|
||||||
services.AddTransient<IProcessMapReportWellDrillingService, ProcessMapReportWellDrillingService>();
|
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportWellDrillingService>();
|
||||||
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportWellDrillingService>();
|
services.AddTransient<WellInfoService>();
|
||||||
services.AddTransient<WellInfoService>();
|
services.AddTransient<IHelpPageService, HelpPageService>();
|
||||||
services.AddTransient<IHelpPageService, HelpPageService>();
|
|
||||||
|
|
||||||
services.AddTransient<TrajectoryService>();
|
services.AddTransient<TrajectoryService>();
|
||||||
|
|
||||||
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
||||||
|
|
||||||
services.AddTransient<NotificationService>();
|
services.AddTransient<NotificationService>();
|
||||||
services.AddTransient<INotificationRepository, NotificationRepository>();
|
services.AddTransient<INotificationRepository, NotificationRepository>();
|
||||||
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
|
services.AddTransient<ICrudRepository<NotificationCategoryDto>, CrudCacheRepositoryBase<NotificationCategoryDto,
|
||||||
NotificationCategory>>();
|
NotificationCategory>>();
|
||||||
|
services.AddTransient<IDrillTestRepository, DrillTestRepository>();
|
||||||
|
|
||||||
// admin crud services:
|
// admin crud services:
|
||||||
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
services.AddTransient<ICrudRepository<TelemetryDto>, CrudCacheRepositoryBase<TelemetryDto, Telemetry>>(s =>
|
||||||
new CrudCacheRepositoryBase<TelemetryDto, Telemetry>(
|
new CrudCacheRepositoryBase<TelemetryDto, Telemetry>(
|
||||||
s.GetRequiredService<IAsbCloudDbContext>(),
|
s.GetRequiredService<IAsbCloudDbContext>(),
|
||||||
s.GetRequiredService<IMemoryCache>(),
|
s.GetRequiredService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
dbSet => dbSet.Include(t => t.Well))); // может быть включен в сервис TelemetryService
|
||||||
services.AddTransient<ICrudRepository<DepositDto>, CrudCacheRepositoryBase<DepositDto, Deposit>>(s =>
|
services.AddTransient<ICrudRepository<DepositDto>, CrudCacheRepositoryBase<DepositDto, Deposit>>(s =>
|
||||||
new CrudCacheRepositoryBase<DepositDto, Deposit>(
|
new CrudCacheRepositoryBase<DepositDto, Deposit>(
|
||||||
s.GetRequiredService<IAsbCloudDbContext>(),
|
s.GetRequiredService<IAsbCloudDbContext>(),
|
||||||
s.GetRequiredService<IMemoryCache>(),
|
s.GetRequiredService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(d => d.Clusters)));
|
dbSet => dbSet.Include(d => d.Clusters)));
|
||||||
services.AddTransient<ICrudRepository<CompanyDto>, CrudCacheRepositoryBase<CompanyDto, Company>>(s =>
|
services.AddTransient<ICrudRepository<CompanyDto>, CrudCacheRepositoryBase<CompanyDto, Company>>(s =>
|
||||||
new CrudCacheRepositoryBase<CompanyDto, Company>(
|
new CrudCacheRepositoryBase<CompanyDto, Company>(
|
||||||
s.GetRequiredService<IAsbCloudDbContext>(),
|
s.GetRequiredService<IAsbCloudDbContext>(),
|
||||||
s.GetRequiredService<IMemoryCache>(),
|
s.GetRequiredService<IMemoryCache>(),
|
||||||
dbSet => dbSet.Include(c => c.CompanyType)));
|
dbSet => dbSet.Include(c => c.CompanyType)));
|
||||||
|
|
||||||
services.AddTransient<ICrudRepository<CompanyTypeDto>, CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>>();
|
services.AddTransient<ICrudRepository<CompanyTypeDto>, CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>>();
|
||||||
services.AddTransient<ICrudRepository<ClusterDto>, CrudCacheRepositoryBase<ClusterDto, Cluster>>(s =>
|
services.AddTransient<ICrudRepository<ClusterDto>, CrudCacheRepositoryBase<ClusterDto, Cluster>>(s =>
|
||||||
new CrudCacheRepositoryBase<ClusterDto, Cluster>(
|
new CrudCacheRepositoryBase<ClusterDto, Cluster>(
|
||||||
s.GetRequiredService<IAsbCloudDbContext>(),
|
s.GetRequiredService<IAsbCloudDbContext>(),
|
||||||
s.GetRequiredService<IMemoryCache>(),
|
s.GetRequiredService<IMemoryCache>(),
|
||||||
dbSet => dbSet
|
dbSet => dbSet
|
||||||
.Include(c => c.Wells)
|
.Include(c => c.Wells)
|
||||||
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
|
||||||
|
|
||||||
services.AddTransient<ICrudRepository<DrillerDto>, CrudCacheRepositoryBase<DrillerDto, Driller>>();
|
services.AddTransient<ICrudRepository<DrillerDto>, CrudCacheRepositoryBase<DrillerDto, Driller>>();
|
||||||
|
|
||||||
services.AddTransient<IHelpPageRepository, HelpPageRepository>();
|
services.AddTransient<IHelpPageRepository, HelpPageRepository>();
|
||||||
services.AddTransient<IFileRepository, FileRepository>();
|
services.AddTransient<IFileRepository, FileRepository>();
|
||||||
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
|
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
|
||||||
services.AddTransient<IWellCompositeRepository, WellCompositeRepository>();
|
services.AddTransient<IWellCompositeRepository, WellCompositeRepository>();
|
||||||
services.AddTransient<IUserRoleRepository, UserRoleRepository>();
|
services.AddTransient<IUserRoleRepository, UserRoleRepository>();
|
||||||
services.AddTransient<IUserRepository, UserRepository>();
|
services.AddTransient<IUserRepository, UserRepository>();
|
||||||
services.AddTransient<ILimitingParameterRepository, LimitingParameterRepository>();
|
services.AddTransient<ILimitingParameterRepository, LimitingParameterRepository>();
|
||||||
services.AddTransient<ITelemetryWirelineRunOutRepository, TelemetryWirelineRunOutRepository>();
|
services.AddTransient<ITelemetryWirelineRunOutRepository, TelemetryWirelineRunOutRepository>();
|
||||||
services.AddTransient<IWellFinalDocumentsRepository, WellFinalDocumentsRepository>();
|
services.AddTransient<IWellFinalDocumentsRepository, WellFinalDocumentsRepository>();
|
||||||
services.AddTransient<ITrajectoryPlanRepository, TrajectoryPlanRepository>();
|
services.AddTransient<ITrajectoryPlanRepository, TrajectoryPlanRepository>();
|
||||||
services.AddTransient<ITrajectoryFactRepository, TrajectoryFactRepository>();
|
services.AddTransient<ITrajectoryFactRepository, TrajectoryFactRepository>();
|
||||||
services.AddTransient<IFaqRepository, FaqRepository>();
|
services.AddTransient<IFaqRepository, FaqRepository>();
|
||||||
services.AddTransient<ISlipsStatService, SlipsStatService>();
|
services.AddTransient<ISlipsStatService, SlipsStatService>();
|
||||||
services.AddTransient<IWellContactService, WellContactService>();
|
services.AddTransient<IWellContactService, WellContactService>();
|
||||||
services.AddTransient<ICrudRepository<WellSectionTypeDto>, CrudCacheRepositoryBase<WellSectionTypeDto,
|
services.AddTransient<ICrudRepository<WellSectionTypeDto>, CrudCacheRepositoryBase<WellSectionTypeDto,
|
||||||
WellSectionType>>();
|
WellSectionType>>();
|
||||||
|
|
||||||
// Subsystem service
|
// Subsystem service
|
||||||
services.AddTransient<ICrudRepository<SubsystemDto>, CrudCacheRepositoryBase<SubsystemDto, Subsystem>>();
|
services.AddTransient<ICrudRepository<SubsystemDto>, CrudCacheRepositoryBase<SubsystemDto, Subsystem>>();
|
||||||
services.AddTransient<ISubsystemService, SubsystemService>();
|
services.AddTransient<ISubsystemService, SubsystemService>();
|
||||||
|
|
||||||
services.AddTransient<ICrudRepository<PermissionDto>, CrudCacheRepositoryBase<PermissionDto, Permission>>();
|
services.AddTransient<ICrudRepository<PermissionDto>, CrudCacheRepositoryBase<PermissionDto, Permission>>();
|
||||||
|
|
||||||
// TelemetryData services
|
// TelemetryData services
|
||||||
services.AddTransient<ITelemetryDataSaubService, TelemetryDataSaubService>();
|
services.AddTransient<ITelemetryDataSaubService, TelemetryDataSaubService>();
|
||||||
services.AddTransient<ITelemetryDataService<TelemetryDataSpinDto>, TelemetryDataSpinService>();
|
services.AddTransient<ITelemetryDataService<TelemetryDataSpinDto>, TelemetryDataSpinService>();
|
||||||
|
|
||||||
// Wits
|
// Wits
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record1Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record1Dto, AsbCloudDb.Model.WITS.Record1>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record1Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record1Dto, AsbCloudDb.Model.WITS.Record1>>();
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record7Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record7Dto, AsbCloudDb.Model.WITS.Record7>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record7Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record7Dto, AsbCloudDb.Model.WITS.Record7>>();
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record8Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record8Dto, AsbCloudDb.Model.WITS.Record8>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record8Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record8Dto, AsbCloudDb.Model.WITS.Record8>>();
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto, AsbCloudDb.Model.WITS.Record50>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record50Dto, AsbCloudDb.Model.WITS.Record50>>();
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto, AsbCloudDb.Model.WITS.Record60>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record60Dto, AsbCloudDb.Model.WITS.Record60>>();
|
||||||
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto, AsbCloudDb.Model.WITS.Record61>>();
|
services.AddTransient<IWitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto>, WitsRecordRepository<AsbCloudApp.Data.WITS.Record61Dto, AsbCloudDb.Model.WITS.Record61>>();
|
||||||
|
|
||||||
services.AddTransient<IAutoGeneratedDailyReportService, AutoGeneratedDailyReportService>();
|
services.AddTransient<IAutoGeneratedDailyReportService, AutoGeneratedDailyReportService>();
|
||||||
services.AddTransient<IAutoGeneratedDailyReportMakerService, AutoGeneratedDailyReportMakerService>();
|
services.AddTransient<IReportMakerService<AutoGeneratedDailyReportDto>, AutoGeneratedDailyReportMakerService>();
|
||||||
|
services.AddTransient<IDrillTestReportService, DrillTestReportService>();
|
||||||
|
services.AddTransient<IReportMakerService<DrillTestReportDataDto>, DrillTestReportMakerService>();
|
||||||
|
|
||||||
services.AddTransient<IManualDirectoryRepository, ManualDirectoryRepository>();
|
services.AddTransient<IManualDirectoryRepository, ManualDirectoryRepository>();
|
||||||
services.AddTransient<IManualCatalogService, ManualCatalogService>();
|
services.AddTransient<IManualCatalogService, ManualCatalogService>();
|
||||||
services.AddTransient<ICrudRepository<ManualDto>, CrudRepositoryBase<ManualDto, Manual>>();
|
services.AddTransient<ICrudRepository<ManualDto>, CrudRepositoryBase<ManualDto, Manual>>();
|
||||||
|
|
||||||
services.AddTransient<IWellboreService, WellboreService>();
|
services.AddTransient<IWellboreService, WellboreService>();
|
||||||
|
|
||||||
services.AddTransient<IWellOperationExportService, WellOperationExportService>();
|
services.AddTransient<IWellOperationExportService, WellOperationExportService>();
|
||||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||||
services.AddTransient<IWellOperationImportTemplateService, WellOperationImportTemplateService>();
|
services.AddTransient<IWellOperationImportTemplateService, WellOperationImportTemplateService>();
|
||||||
|
|
||||||
services.AddTransient<IWellOperationExcelParser<WellOperationImportDefaultOptionsDto>, WellOperationDefaultExcelParser>();
|
services.AddTransient<IWellOperationExcelParser<WellOperationImportDefaultOptionsDto>, WellOperationDefaultExcelParser>();
|
||||||
services.AddTransient<IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto>, WellOperationGazpromKhantosExcelParser>();
|
services.AddTransient<IWellOperationExcelParser<WellOperationImportGazpromKhantosOptionsDto>, WellOperationGazpromKhantosExcelParser>();
|
||||||
|
|
||||||
services.AddTransient<DetectedOperationExportService>();
|
services.AddTransient<DetectedOperationExportService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddTransientLazy<TService, TImplementation>(this IServiceCollection services)
|
public static IServiceCollection AddTransientLazy<TService, TImplementation>(this IServiceCollection services)
|
||||||
where TService : class
|
where TService : class
|
||||||
where TImplementation : class, TService
|
where TImplementation : class, TService
|
||||||
=> services.AddTransient<TService, TImplementation>()
|
=> services.AddTransient<TService, TImplementation>()
|
||||||
.AddTransient(provider => new Lazy<TService>(provider.GetRequiredService<TService>));
|
.AddTransient(provider => new Lazy<TService>(provider.GetRequiredService<TService>));
|
||||||
|
|
||||||
public static IServiceCollection AddTransientLazy<TService, TImplementation>(this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory)
|
public static IServiceCollection AddTransientLazy<TService, TImplementation>(this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory)
|
||||||
where TService : class
|
where TService : class
|
||||||
where TImplementation : class, TService
|
where TImplementation : class, TService
|
||||||
=> services.AddTransient<TService, TImplementation>(implementationFactory)
|
=> services.AddTransient<TService, TImplementation>(implementationFactory)
|
||||||
.AddTransient(provider => new Lazy<TService>(() => implementationFactory(provider)));
|
.AddTransient(provider => new Lazy<TService>(() => implementationFactory(provider)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
82
AsbCloudInfrastructure/Repository/DrillTestRepository.cs
Normal file
82
AsbCloudInfrastructure/Repository/DrillTestRepository.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository
|
||||||
|
{
|
||||||
|
public class DrillTestRepository : IDrillTestRepository
|
||||||
|
{
|
||||||
|
private readonly IAsbCloudDbContext db;
|
||||||
|
|
||||||
|
public DrillTestRepository(IAsbCloudDbContext db)
|
||||||
|
{
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<DrillTestDto>> GetAllAsync(int idTelemetry, FileReportRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var query = db.DrillTests
|
||||||
|
.Where(d => d.IdTelemetry == idTelemetry)
|
||||||
|
.Include(d => d.Telemetry)
|
||||||
|
.AsNoTracking();
|
||||||
|
|
||||||
|
if (request.GeDate.HasValue)
|
||||||
|
{
|
||||||
|
var startDateUTC = new DateTimeOffset(request.GeDate.Value.Year, request.GeDate.Value.Month, request.GeDate.Value.Day, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
query = query.Where(q => q.TimeStampStart >= startDateUTC);
|
||||||
|
}
|
||||||
|
if (request.LeDate.HasValue)
|
||||||
|
{
|
||||||
|
var finishDateUTC = new DateTimeOffset(request.LeDate.Value.Year, request.LeDate.Value.Month, request.LeDate.Value.Day, 0, 0, 0, TimeSpan.Zero);
|
||||||
|
query = query.Where(q => q.TimeStampStart <= finishDateUTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entities = await query.ToListAsync(cancellationToken);
|
||||||
|
var dtos = entities.Select(e => Convert(e));
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<DrillTestDto> GetAsync(int idTelemetry, int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var drillTest = await db.DrillTests
|
||||||
|
.Where(d => d.Id == id)
|
||||||
|
.Include(d => d.Telemetry)
|
||||||
|
.Where(d => d.Telemetry.Id == idTelemetry)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (drillTest is null)
|
||||||
|
throw new ArgumentInvalidException(new string[] { nameof(id), nameof(idTelemetry) }, $"Drill test with id: {id} and idTelemetry: {idTelemetry} does not exist.");
|
||||||
|
|
||||||
|
var dto = Convert(drillTest);
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token)
|
||||||
|
{
|
||||||
|
var entity = dto.Adapt<DrillTest>();
|
||||||
|
entity.IdTelemetry = idTelemetry;
|
||||||
|
db.DrillTests.Add(entity);
|
||||||
|
var result = await db.SaveChangesAsync(token);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrillTestDto Convert(DrillTest entity)
|
||||||
|
{
|
||||||
|
var dto = entity.Adapt<DrillTestDto>();
|
||||||
|
dto.TimeStampStart = dto.TimeStampStart.ToRemoteDateTime(dto.Telemetry?.TimeZone?.Hours ?? 0);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -147,17 +147,17 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public async Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
|
public async Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
|
||||||
{
|
{
|
||||||
var query = dbSetConfigured
|
var query = dbSetConfigured
|
||||||
.Where(f => ids.Contains(f.Id) && f.IsDeleted);
|
.Where(f => ids.Contains(f.Id));
|
||||||
|
|
||||||
var files = await query.ToListAsync(token);
|
var files = await query.ToListAsync(token);
|
||||||
|
|
||||||
var filesDtos = files.Select(x => Convert(x));
|
var filesDtos = files.Select(x => Convert(x));
|
||||||
|
|
||||||
db.Files.RemoveRange(query);
|
db.Files.RemoveRange(query);
|
||||||
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||||
|
|
||||||
return filesDtos;
|
return filesDtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token)
|
public async Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
@ -128,12 +128,14 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
operation.IdWell,
|
operation.IdWell,
|
||||||
operation.IdType,
|
operation.IdType,
|
||||||
operation.IdWellSectionType,
|
operation.IdWellSectionType,
|
||||||
|
operation.WellSectionType.Caption,
|
||||||
})
|
})
|
||||||
.Select(group => new
|
.Select(group => new
|
||||||
{
|
{
|
||||||
group.Key.IdWell,
|
group.Key.IdWell,
|
||||||
group.Key.IdType,
|
group.Key.IdType,
|
||||||
group.Key.IdWellSectionType,
|
group.Key.IdWellSectionType,
|
||||||
|
group.Key.Caption,
|
||||||
|
|
||||||
First = group
|
First = group
|
||||||
.OrderBy(operation => operation.DateStart)
|
.OrderBy(operation => operation.DateStart)
|
||||||
@ -162,6 +164,8 @@ public class WellOperationRepository : IWellOperationRepository
|
|||||||
IdType = item.IdType,
|
IdType = item.IdType,
|
||||||
IdWellSectionType = item.IdWellSectionType,
|
IdWellSectionType = item.IdWellSectionType,
|
||||||
|
|
||||||
|
Caption = item.Caption,
|
||||||
|
|
||||||
DateStart = item.First.DateStart,
|
DateStart = item.First.DateStart,
|
||||||
DepthStart = item.First.DepthStart,
|
DepthStart = item.First.DepthStart,
|
||||||
|
|
||||||
|
@ -5,14 +5,16 @@ using System.Reflection;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data.AutogeneratedDailyReport;
|
using AsbCloudApp.Data.AutogeneratedDailyReport;
|
||||||
using AsbCloudApp.Services.AutoGeneratedDailyReports;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports.AutogeneratedDailyReportBlocks;
|
using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports.AutogeneratedDailyReportBlocks;
|
||||||
using ClosedXML.Excel;
|
using ClosedXML.Excel;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
namespace AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
||||||
|
|
||||||
public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMakerService
|
public class AutoGeneratedDailyReportMakerService : IReportMakerService<AutoGeneratedDailyReportDto>
|
||||||
{
|
{
|
||||||
|
private readonly string templateName = "AutogeneratedDailyReportTemplate.xlsx";
|
||||||
|
|
||||||
private readonly IEnumerable<IExcelBlockWriter> blockWriters = new List<IExcelBlockWriter>()
|
private readonly IEnumerable<IExcelBlockWriter> blockWriters = new List<IExcelBlockWriter>()
|
||||||
{
|
{
|
||||||
new HeadExcelBlockWriter(),
|
new HeadExcelBlockWriter(),
|
||||||
@ -21,9 +23,11 @@ public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMak
|
|||||||
new TimeBalanceExcelBlockWriter()
|
new TimeBalanceExcelBlockWriter()
|
||||||
};
|
};
|
||||||
|
|
||||||
public async Task<Stream> MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken)
|
public async Task<Stream> MakeReportAsync(AutoGeneratedDailyReportDto report, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
|
using var excelTemplateStream = await Assembly
|
||||||
|
.GetExecutingAssembly()
|
||||||
|
.GetTemplateCopyStreamAsync(templateName, cancellationToken);
|
||||||
|
|
||||||
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
|
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
|
||||||
|
|
||||||
@ -36,22 +40,6 @@ public class AutoGeneratedDailyReportMakerService : IAutoGeneratedDailyReportMak
|
|||||||
return memoryStream;
|
return memoryStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Stream> GetExcelTemplateStreamAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var resourceName = Assembly.GetExecutingAssembly()
|
|
||||||
.GetManifestResourceNames()
|
|
||||||
.FirstOrDefault(n => n.EndsWith("AutogeneratedDailyReportTemplate.xlsx"))!;
|
|
||||||
|
|
||||||
using var stream = Assembly.GetExecutingAssembly()
|
|
||||||
.GetManifestResourceStream(resourceName)!;
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
await stream.CopyToAsync(memoryStream, cancellationToken);
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
return memoryStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddToWorkbook(XLWorkbook workbook, AutoGeneratedDailyReportDto report)
|
private void AddToWorkbook(XLWorkbook workbook, AutoGeneratedDailyReportDto report)
|
||||||
{
|
{
|
||||||
const string sheetName = "Рапорт";
|
const string sheetName = "Рапорт";
|
||||||
|
@ -26,14 +26,14 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
|||||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
||||||
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
|
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
|
||||||
private readonly ILimitingParameterService limitingParameterService;
|
private readonly ILimitingParameterService limitingParameterService;
|
||||||
private readonly IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService;
|
private readonly IReportMakerService<AutoGeneratedDailyReportDto> autoGeneratedDailyReportMakerService;
|
||||||
|
|
||||||
public AutoGeneratedDailyReportService(IWellService wellService,
|
public AutoGeneratedDailyReportService(IWellService wellService,
|
||||||
IWellOperationRepository wellOperationRepository,
|
IWellOperationRepository wellOperationRepository,
|
||||||
ISubsystemOperationTimeService subsystemOperationTimeService,
|
ISubsystemOperationTimeService subsystemOperationTimeService,
|
||||||
ICrudRepository<SubsystemDto> subsystemRepository,
|
ICrudRepository<SubsystemDto> subsystemRepository,
|
||||||
ILimitingParameterService limitingParameterService,
|
ILimitingParameterService limitingParameterService,
|
||||||
IAutoGeneratedDailyReportMakerService autoGeneratedDailyReportMakerService)
|
IReportMakerService<AutoGeneratedDailyReportDto> autoGeneratedDailyReportMakerService)
|
||||||
{
|
{
|
||||||
this.wellOperationRepository = wellOperationRepository;
|
this.wellOperationRepository = wellOperationRepository;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
@ -44,7 +44,7 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
|
public async Task<PaginationContainer<AutoGeneratedDailyReportInfoDto>> GetListAsync(int idWell,
|
||||||
AutoGeneratedDailyReportRequest request,
|
FileReportRequest request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var result = new PaginationContainer<AutoGeneratedDailyReportInfoDto>
|
var result = new PaginationContainer<AutoGeneratedDailyReportInfoDto>
|
||||||
@ -67,19 +67,19 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService
|
|||||||
if (datesRange is null)
|
if (datesRange is null)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (request.StartDate.HasValue)
|
if (request.GeDate.HasValue)
|
||||||
{
|
{
|
||||||
var startDate = new DateTime(request.StartDate.Value.Year, request.StartDate.Value.Month,
|
var startDate = new DateTime(request.GeDate.Value.Year, request.GeDate.Value.Month,
|
||||||
request.StartDate.Value.Day);
|
request.GeDate.Value.Day);
|
||||||
|
|
||||||
if(startDate.Date >= datesRange.From.Date)
|
if(startDate.Date >= datesRange.From.Date)
|
||||||
datesRange.From = startDate;
|
datesRange.From = startDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.FinishDate.HasValue)
|
if (request.LeDate.HasValue)
|
||||||
{
|
{
|
||||||
var finishDate = new DateTime(request.FinishDate.Value.Year, request.FinishDate.Value.Month,
|
var finishDate = new DateTime(request.LeDate.Value.Year, request.LeDate.Value.Month,
|
||||||
request.FinishDate.Value.Day);
|
request.LeDate.Value.Day);
|
||||||
|
|
||||||
if (finishDate.Date <= datesRange.To.Date)
|
if (finishDate.Date <= datesRange.To.Date)
|
||||||
datesRange.To = finishDate;
|
datesRange.To = finishDate;
|
||||||
|
@ -95,12 +95,12 @@ public class WorkOperationDetection: Work
|
|||||||
{
|
{
|
||||||
DateTime = d.DateTime,
|
DateTime = d.DateTime,
|
||||||
IdUser = d.IdUser,
|
IdUser = d.IdUser,
|
||||||
WellDepth = d.WellDepth ?? float.NaN,
|
WellDepth = d.WellDepth,
|
||||||
Pressure = d.Pressure ?? float.NaN,
|
Pressure = d.Pressure,
|
||||||
HookWeight = d.HookWeight ?? float.NaN,
|
HookWeight = d.HookWeight,
|
||||||
BlockPosition = d.BlockPosition ?? float.NaN,
|
BlockPosition = d.BlockPosition,
|
||||||
BitDepth = d.BitDepth ?? float.NaN,
|
BitDepth = d.BitDepth,
|
||||||
RotorSpeed = d.RotorSpeed ?? float.NaN,
|
RotorSpeed = d.RotorSpeed,
|
||||||
})
|
})
|
||||||
.OrderBy(d => d.DateTime);
|
.OrderBy(d => d.DateTime);
|
||||||
|
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
using AsbCloudApp.Data.DrillTestReport;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DrillTestReport
|
||||||
|
{
|
||||||
|
public class DrillTestReportMakerService : IReportMakerService<DrillTestReportDataDto>
|
||||||
|
{
|
||||||
|
private readonly string templateName = "DrillTestReportTemplate.xlsx";
|
||||||
|
private readonly string sheetName = "Лист1";
|
||||||
|
private readonly int startRowNumber = 8;
|
||||||
|
|
||||||
|
public async Task<Stream> MakeReportAsync(DrillTestReportDataDto report, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using var excelTemplateStream = await Assembly.GetExecutingAssembly().GetTemplateCopyStreamAsync(templateName, cancellationToken);
|
||||||
|
|
||||||
|
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
|
||||||
|
|
||||||
|
AddToWorkbook(workbook, report);
|
||||||
|
|
||||||
|
MemoryStream memoryStream = new MemoryStream();
|
||||||
|
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||||
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void AddToWorkbook(XLWorkbook workbook, DrillTestReportDataDto report)
|
||||||
|
{
|
||||||
|
var drillTestEntities = report.Data.Params;
|
||||||
|
if (!drillTestEntities.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName)
|
||||||
|
?? throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
|
||||||
|
|
||||||
|
sheet.Cell(4, 2).Value = report.Caption;
|
||||||
|
sheet.Cell(5, 2)._SetValue(report.Date, setAllBorders: false);
|
||||||
|
|
||||||
|
var rowNumber = startRowNumber;
|
||||||
|
|
||||||
|
var stepWithMaxDepthSpeed = drillTestEntities.OrderByDescending(p => p.DepthSpeed).FirstOrDefault()!.Step;
|
||||||
|
var startDepth = report.Data.DepthStart;
|
||||||
|
var startDate = report.Data.TimeStampStart;
|
||||||
|
|
||||||
|
foreach (var drillTestEntity in drillTestEntities)
|
||||||
|
{
|
||||||
|
var endDepth = startDepth + (drillTestEntity.DepthDrillStep ?? 0);
|
||||||
|
var endDateTime = startDate.AddSeconds(drillTestEntity.TimeDrillStep ?? 0);
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 2).Value = startDepth;
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 3).Value = endDepth;
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 4).Value = drillTestEntity.DepthDrillStep;
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 5).Value = drillTestEntity.Workload;
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 6).Value = drillTestEntity.Speed;
|
||||||
|
|
||||||
|
var cell = sheet.Cell(rowNumber, 7);
|
||||||
|
cell._SetValue(startDate.DateTime);
|
||||||
|
|
||||||
|
cell = sheet.Cell(rowNumber, 8);
|
||||||
|
cell._SetValue(endDateTime.DateTime);
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 9).Value = Math.Round((drillTestEntity.TimeDrillStep ?? 0) / (60 * 60), 2);
|
||||||
|
|
||||||
|
sheet.Cell(rowNumber, 10).Value = drillTestEntity.DepthSpeed;
|
||||||
|
|
||||||
|
if (drillTestEntity.Step == stepWithMaxDepthSpeed)
|
||||||
|
{
|
||||||
|
var currentCells = sheet.Row(rowNumber).Cells(1, 10);
|
||||||
|
currentCells.Style.Fill.BackgroundColor = XLColor.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
startDepth = endDepth;
|
||||||
|
startDate = endDateTime;
|
||||||
|
rowNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.DrillTestReport;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.DrillTestReport
|
||||||
|
{
|
||||||
|
public class DrillTestReportService : IDrillTestReportService
|
||||||
|
{
|
||||||
|
private readonly IWellService wellService;
|
||||||
|
private readonly IDrillTestRepository drillTestRepository;
|
||||||
|
private readonly ITelemetryService telemetryService;
|
||||||
|
private readonly IReportMakerService<DrillTestReportDataDto> drillTestReportMakerService;
|
||||||
|
|
||||||
|
public DrillTestReportService(
|
||||||
|
IWellService wellService,
|
||||||
|
IDrillTestRepository drillTestRepository,
|
||||||
|
ITelemetryService telemetryService,
|
||||||
|
IReportMakerService<DrillTestReportDataDto> drillTestReportMakerService)
|
||||||
|
{
|
||||||
|
this.wellService = wellService;
|
||||||
|
this.drillTestRepository = drillTestRepository;
|
||||||
|
this.telemetryService = telemetryService;
|
||||||
|
this.drillTestReportMakerService = drillTestReportMakerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(string fileName, Stream stream)> GenerateAsync(int idWell, int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var well = wellService.GetOrDefault(idWell);
|
||||||
|
if (well is null)
|
||||||
|
throw new ArgumentInvalidException(nameof(idWell), $"Well with id: {idWell} does not exist.");
|
||||||
|
if (well.IdTelemetry is null)
|
||||||
|
throw new ArgumentInvalidException(nameof(well.IdTelemetry), $"Well with id: {idWell} does not have telemetry.");
|
||||||
|
|
||||||
|
var dto = await drillTestRepository.GetAsync(well.IdTelemetry.Value, id, cancellationToken);
|
||||||
|
|
||||||
|
var report = new DrillTestReportDataDto()
|
||||||
|
{
|
||||||
|
Data = dto,
|
||||||
|
Caption = string.Format("Месторождение: {0}, куст: {1}, скважина: {2}",
|
||||||
|
well.Deposit ?? "-",
|
||||||
|
well.Cluster ?? "-",
|
||||||
|
well.Caption ?? "-"),
|
||||||
|
Date = DateTime.Now,
|
||||||
|
};
|
||||||
|
|
||||||
|
var fileName = string.Format("Drill_test_{0}.xlsx", dto.TimeStampStart.ToString("dd.mm.yyyy_HH_MM_ss"));
|
||||||
|
var stream = await drillTestReportMakerService.MakeReportAsync(report, cancellationToken);
|
||||||
|
|
||||||
|
return (fileName, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<PaginationContainer<DrillTestReportInfoDto>> GetListAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
|
||||||
|
if (telemetry is null)
|
||||||
|
throw new Exception($"Telemetry with idWell: {idWell} does not exist.");
|
||||||
|
|
||||||
|
var result = new PaginationContainer<DrillTestReportInfoDto>
|
||||||
|
{
|
||||||
|
Skip = request.Skip ?? 0,
|
||||||
|
Take = request.Take ?? 10,
|
||||||
|
Items = Enumerable.Empty<DrillTestReportInfoDto>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var reports = new List<DrillTestReportInfoDto>();
|
||||||
|
var timezone = telemetryService.GetTimezone(telemetry.Id);
|
||||||
|
|
||||||
|
var dtos = await drillTestRepository.GetAllAsync(telemetry.Id, request, cancellationToken);
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
var remoteDateTime = dto.TimeStampStart.ToRemoteDateTime(timezone.Hours);
|
||||||
|
|
||||||
|
reports.Add(new DrillTestReportInfoDto
|
||||||
|
{
|
||||||
|
FileName = string.Format("Drill_test_{0}", dto.TimeStampStart.DateTime),
|
||||||
|
DrillDepth = (dto.Params
|
||||||
|
.Where(p => p.DepthDrillStep.HasValue)
|
||||||
|
.Sum(x => x.DepthDrillStep) ?? 0) + dto.DepthStart,
|
||||||
|
DateTime = dto.TimeStampStart.DateTime,
|
||||||
|
Id = dto.Id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Items = reports;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
@ -513,7 +513,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
if (state.IdState == idStateCreating)
|
if (state.IdState == idStateCreating)
|
||||||
{
|
{
|
||||||
var workId = MakeWorkId(idWell);
|
var workId = MakeWorkId(idWell);
|
||||||
if (!backgroundWorker.WorkStore.RunOnceQueue.Any(w => w.Id == workId))
|
if (!backgroundWorker.Works.Any(w => w.Id == workId))
|
||||||
{
|
{
|
||||||
var well = (await wellService.GetOrDefaultAsync(idWell, token))!;
|
var well = (await wellService.GetOrDefaultAsync(idWell, token))!;
|
||||||
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.pdf";
|
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.pdf";
|
||||||
@ -542,7 +542,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
work.OnErrorAsync = onErrorAction;
|
work.OnErrorAsync = onErrorAction;
|
||||||
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorker.Enqueue(work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,7 +556,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
|||||||
private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token)
|
private async Task<int> RemoveDrillingProgramAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var workId = MakeWorkId(idWell);
|
var workId = MakeWorkId(idWell);
|
||||||
backgroundWorker.WorkStore.TryRemoveFromRunOnceQueue(workId);
|
backgroundWorker.TryRemoveFromQueue(workId);
|
||||||
|
|
||||||
var filesIds = await context.Files
|
var filesIds = await context.Files
|
||||||
.Where(f => f.IdWell == idWell &&
|
.Where(f => f.IdWell == idWell &&
|
||||||
|
@ -52,12 +52,12 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
}
|
}
|
||||||
|
|
||||||
var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message);
|
var workId = MakeWorkId(notification.IdUser, notification.Title, notification.Message);
|
||||||
if (!backgroundWorker.WorkStore.RunOnceQueue.Any(w=>w.Id==workId))
|
if (!backgroundWorker.Works.Any(w=>w.Id==workId))
|
||||||
{
|
{
|
||||||
var workAction = MakeEmailSendWorkAction(notification);
|
var workAction = MakeEmailSendWorkAction(notification);
|
||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
backgroundWorker.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorker.Enqueue(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@ -20,6 +20,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
|
private readonly FileService fileService;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly BackgroundWorker backgroundWorkerService;
|
private readonly BackgroundWorker backgroundWorkerService;
|
||||||
|
|
||||||
@ -28,12 +29,14 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
public ReportService(IAsbCloudDbContext db,
|
public ReportService(IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
|
FileService fileService,
|
||||||
BackgroundWorker backgroundWorkerService)
|
BackgroundWorker backgroundWorkerService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.backgroundWorkerService = backgroundWorkerService;
|
this.backgroundWorkerService = backgroundWorkerService;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
|
this.fileService = fileService;
|
||||||
ReportCategoryId = db.FileCategories
|
ReportCategoryId = db.FileCategories
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.First(c => c.Name.Equals("Рапорт"))
|
.First(c => c.Name.Equals("Рапорт"))
|
||||||
@ -95,7 +98,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
};
|
};
|
||||||
|
|
||||||
var work = Work.CreateByDelegate(workId, workAction);
|
var work = Work.CreateByDelegate(workId, workAction);
|
||||||
backgroundWorkerService.WorkStore.RunOnceQueue.Enqueue(work);
|
backgroundWorkerService.Enqueue(work);
|
||||||
|
|
||||||
progressHandler.Invoke(new ReportProgressDto
|
progressHandler.Invoke(new ReportProgressDto
|
||||||
{
|
{
|
||||||
@ -186,6 +189,16 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
return generator;
|
return generator;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public async Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token)
|
||||||
|
{
|
||||||
|
var lifeTimeStartDate = DateTime.UtcNow.Date - lifetime;
|
||||||
|
var fileIds = await db.ReportProperties
|
||||||
|
.Where(r => r.File.UploadDate.Date < lifeTimeStartDate)
|
||||||
|
.Select(r => r.IdFile)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
|
return await fileService.DeleteAsync(fileIds, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
@ -18,12 +20,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
{
|
{
|
||||||
protected readonly IAsbCloudDbContext db;
|
protected readonly IAsbCloudDbContext db;
|
||||||
protected readonly ITelemetryService telemetryService;
|
protected readonly ITelemetryService telemetryService;
|
||||||
protected readonly TelemetryDataCache<TDto> telemetryDataCache;
|
protected readonly ITelemetryDataCache<TDto> telemetryDataCache;
|
||||||
|
|
||||||
public TelemetryDataBaseService(
|
public TelemetryDataBaseService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
TelemetryDataCache<TDto> telemetryDataCache)
|
ITelemetryDataCache<TDto> telemetryDataCache)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
@ -203,41 +205,62 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<DatesRangeDto?> GetRangeAsync(
|
public async Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token)
|
||||||
int idWell,
|
{
|
||||||
DateTimeOffset start,
|
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
|
||||||
DateTimeOffset end,
|
?? throw new ArgumentInvalidException(nameof(idWell), $"По скважине id:{idWell} нет телеметрии");
|
||||||
CancellationToken token)
|
|
||||||
|
if ((DateTimeOffset.UtcNow - geDate) < TimeSpan.FromHours(12))
|
||||||
|
{
|
||||||
|
// пробуем обойтись кешем
|
||||||
|
var cechedRange = telemetryDataCache.GetOrDefaultCachedaDateRange(telemetry.Id);
|
||||||
|
if (cechedRange?.From <= geDate)
|
||||||
|
{
|
||||||
|
var datesRange = new DatesRangeDto
|
||||||
|
{
|
||||||
|
From = geDate.DateTime,
|
||||||
|
To = cechedRange.To
|
||||||
|
};
|
||||||
|
if (leDate.HasValue && leDate > geDate)
|
||||||
|
datesRange.To = leDate.Value.Date;
|
||||||
|
return datesRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = db.Set<TEntity>()
|
||||||
|
.Where(entity => entity.IdTelemetry == telemetry.Id)
|
||||||
|
.Where(entity => entity.DateTime >= geDate.ToUniversalTime());
|
||||||
|
|
||||||
|
if(leDate.HasValue)
|
||||||
|
query = query.Where(entity => entity.DateTime <= leDate.Value.ToUniversalTime());
|
||||||
|
|
||||||
|
var gquery = query
|
||||||
|
.GroupBy(entity => entity.IdTelemetry)
|
||||||
|
.Select(group => new
|
||||||
|
{
|
||||||
|
MinDate = group.Min(entity => entity.DateTime),
|
||||||
|
MaxDate = group.Max(entity => entity.DateTime),
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = await gquery.FirstOrDefaultAsync(token);
|
||||||
|
if (result is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var range = new DatesRangeDto
|
||||||
|
{
|
||||||
|
From = result.MinDate.ToOffset(TimeSpan.FromHours(telemetry.TimeZone!.Hours)).DateTime,
|
||||||
|
To = result.MaxDate.ToOffset(TimeSpan.FromHours(telemetry.TimeZone!.Hours)).DateTime,
|
||||||
|
};
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatesRangeDto? GetRange(int idWell)
|
||||||
{
|
{
|
||||||
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
|
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
|
||||||
if (telemetry is null)
|
if (telemetry is null)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
var timezone = telemetryService.GetTimezone(telemetry.Id);
|
return telemetryDataCache.GetOrDefaultDataDateRange(telemetry.Id);
|
||||||
var startUtc = start.ToOffset(TimeSpan.Zero);
|
|
||||||
var endUtc = end.ToOffset(TimeSpan.Zero);
|
|
||||||
|
|
||||||
var dbSet = db.Set<TEntity>();
|
|
||||||
var query = dbSet
|
|
||||||
.Where(i => i.IdTelemetry == telemetry.Id)
|
|
||||||
.Where(i => i.DateTime >= startUtc)
|
|
||||||
.Where(i => i.DateTime <= endUtc)
|
|
||||||
.GroupBy(i => i.IdTelemetry)
|
|
||||||
.Select(g => new
|
|
||||||
{
|
|
||||||
DateStart = g.Min(i => i.DateTime),
|
|
||||||
DateEnd = g.Max(i => i.DateTime),
|
|
||||||
});
|
|
||||||
|
|
||||||
var data = await query.FirstOrDefaultAsync(token);
|
|
||||||
if (data is null)
|
|
||||||
return default;
|
|
||||||
|
|
||||||
return new DatesRangeDto
|
|
||||||
{
|
|
||||||
From = data.DateStart.ToRemoteDateTime(timezone.Hours),
|
|
||||||
To = data.DateEnd.ToRemoteDateTime(timezone.Hours),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract TDto Convert(TEntity src, double timezoneOffset);
|
public abstract TDto Convert(TEntity src, double timezoneOffset);
|
||||||
|
@ -6,26 +6,24 @@ using System.Linq;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.SAUB
|
namespace AsbCloudInfrastructure.Services.SAUB
|
||||||
{
|
{
|
||||||
public class TelemetryDataCache<TDto>
|
public class TelemetryDataCache<TDto> : ITelemetryDataCache<TDto> where TDto : AsbCloudApp.Data.ITelemetryData
|
||||||
where TDto : AsbCloudApp.Data.ITelemetryData
|
|
||||||
{
|
{
|
||||||
class TelemetryDataCacheItem
|
class TelemetryDataCacheItem
|
||||||
{
|
{
|
||||||
public TDto? FirstByDate { get; init; }
|
public TDto FirstByDate { get; init; } = default!;
|
||||||
public CyclycArray<TDto> LastData { get; init; } = null!;
|
public CyclycArray<TDto> LastData { get; init; } = null!;
|
||||||
public double TimezoneHours { get; init; } = 5;
|
public double TimezoneHours { get; init; } = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IServiceProvider provider = null!;
|
|
||||||
private const int activeWellCapacity = 12 * 60 * 60;
|
private const int activeWellCapacity = 12 * 60 * 60;
|
||||||
private const int doneWellCapacity = 65 * 60;
|
private const int doneWellCapacity = 65 * 60;
|
||||||
|
|
||||||
@ -48,14 +46,14 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
instance = new TelemetryDataCache<TDto>();
|
instance = new TelemetryDataCache<TDto>();
|
||||||
var worker = provider.GetRequiredService<BackgroundWorker>();
|
var worker = provider.GetRequiredService<BackgroundWorker>();
|
||||||
var workId = $"Telemetry cache loading from DB {typeof(TEntity).Name}";
|
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<IAsbCloudDbContext>();
|
var db = provider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
|
await instance.InitializeCacheFromDBAsync<TEntity>(db, onProgress, token);
|
||||||
});
|
});
|
||||||
work.Timeout = TimeSpan.FromMinutes(15);
|
work.Timeout = TimeSpan.FromMinutes(15);
|
||||||
worker.WorkStore.RunOnceQueue.Enqueue(work);
|
worker.Enqueue(work);
|
||||||
}
|
}
|
||||||
instance.provider = provider;
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,10 +67,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
if (!range.Any())
|
if (!range.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var newItems = range
|
range = range.OrderBy(x => x.DateTime);
|
||||||
.OrderBy(i => i.DateTime);
|
|
||||||
|
|
||||||
foreach (var item in newItems)
|
foreach (var item in range)
|
||||||
item.IdTelemetry = idTelemetry;
|
item.IdTelemetry = idTelemetry;
|
||||||
|
|
||||||
TelemetryDataCacheItem cacheItem;
|
TelemetryDataCacheItem cacheItem;
|
||||||
@ -87,12 +84,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
{
|
{
|
||||||
cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem()
|
cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem()
|
||||||
{
|
{
|
||||||
FirstByDate = newItems.ElementAt(0),
|
FirstByDate = range.ElementAt(0),
|
||||||
LastData = new CyclycArray<TDto>(activeWellCapacity)
|
LastData = new CyclycArray<TDto>(activeWellCapacity)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheItem.LastData.AddRange(newItems);
|
cacheItem.LastData.AddRange(range);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -107,7 +104,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IEnumerable<TDto>? GetOrDefault(int idTelemetry, DateTime dateBegin, double intervalSec = 600d, int approxPointsCount = 1024)
|
public IEnumerable<TDto>? 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;
|
return null;
|
||||||
|
|
||||||
var cacheLastData = cacheItem.LastData;
|
var cacheLastData = cacheItem.LastData;
|
||||||
@ -127,7 +124,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TDto? GetLastOrDefault(int idTelemetry)
|
public virtual TDto? GetLastOrDefault(int idTelemetry)
|
||||||
{
|
{
|
||||||
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
|
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
|
||||||
return default;
|
return default;
|
||||||
@ -141,7 +138,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var from = cacheItem.FirstByDate?.DateTime;
|
var from = cacheItem.FirstByDate?.DateTime;
|
||||||
if(!cacheItem.LastData.Any())
|
if (!cacheItem.LastData.Any())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var to = cacheItem.LastData[^1].DateTime;
|
var to = cacheItem.LastData[^1].DateTime;
|
||||||
@ -150,42 +147,74 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
return new DatesRangeDto { From = from.Value, To = to };
|
return new DatesRangeDto { From = from.Value, To = to };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DatesRangeDto? GetOrDefaultCachedaDateRange(int idTelemetry)
|
||||||
|
{
|
||||||
|
if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (cacheItem.LastData.Count < 2)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var to = cacheItem.LastData[^1].DateTime;
|
||||||
|
var from = cacheItem.LastData[0].DateTime;
|
||||||
|
|
||||||
|
return new DatesRangeDto { From = from, 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<TEntity>(IAsbCloudDbContext db, Action<string, double?> onProgress, CancellationToken token)
|
private async Task InitializeCacheFromDBAsync<TEntity>(IAsbCloudDbContext db, Action<string, double?> onProgress, CancellationToken token)
|
||||||
where TEntity : class, AsbCloudDb.Model.ITelemetryData
|
where TEntity : class, AsbCloudDb.Model.ITelemetryData
|
||||||
{
|
{
|
||||||
if (isLoading)
|
|
||||||
throw new Exception("Multiple cache loading detected.");
|
|
||||||
|
|
||||||
isLoading = true;
|
|
||||||
|
|
||||||
var defaultTimeout = db.Database.GetCommandTimeout();
|
var defaultTimeout = db.Database.GetCommandTimeout();
|
||||||
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
Well[] wells = await db.Set<Well>()
|
if (isLoading)
|
||||||
.Include(well => well.Telemetry)
|
throw new Exception("Multiple cache loading detected.");
|
||||||
.Include(well => well.Cluster)
|
|
||||||
.Where(well => well.IdTelemetry != null)
|
|
||||||
.ToArrayAsync(token);
|
|
||||||
|
|
||||||
var count = wells.Length;
|
try
|
||||||
var i = 0d;
|
|
||||||
foreach (Well well in wells)
|
|
||||||
{
|
{
|
||||||
var capacity = well.IdState == 1
|
isLoading = true;
|
||||||
? activeWellCapacity
|
|
||||||
: doneWellCapacity;
|
|
||||||
|
|
||||||
var idTelemetry = well.IdTelemetry!.Value;
|
Well[] wells = await db.Set<Well>()
|
||||||
var hoursOffset = well.Timezone.Hours;
|
.Include(well => well.Telemetry)
|
||||||
|
.Include(well => well.Cluster)
|
||||||
|
.Where(well => well.IdTelemetry != null)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count);
|
var count = wells.Length;
|
||||||
var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token);
|
var i = 0d;
|
||||||
if(cacheItem is not null)
|
foreach (Well well in wells)
|
||||||
caches.TryAdd(idTelemetry, cacheItem);
|
{
|
||||||
|
var capacity = well.IdState == 1
|
||||||
|
? activeWellCapacity
|
||||||
|
: doneWellCapacity;
|
||||||
|
|
||||||
|
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);
|
||||||
|
var cacheItem = await GetOrDefaultCacheDataFromDbAsync<TEntity>(db, idTelemetry, capacity, hoursOffset, token);
|
||||||
|
if (cacheItem is not null)
|
||||||
|
caches.TryAdd(idTelemetry, cacheItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isLoading = false;
|
||||||
|
db.Database.SetCommandTimeout(defaultTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoading = false;
|
|
||||||
db.Database.SetCommandTimeout(defaultTimeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<TelemetryDataCacheItem?> GetOrDefaultCacheDataFromDbAsync<TEntity>(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token)
|
private static async Task<TelemetryDataCacheItem?> GetOrDefaultCacheDataFromDbAsync<TEntity>(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token)
|
||||||
@ -212,7 +241,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
var dtos = entities
|
var dtos = entities
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Reverse()
|
.Reverse()
|
||||||
.Select(entity => {
|
.Select(entity =>
|
||||||
|
{
|
||||||
var dto = entity.Adapt<TDto>();
|
var dto = entity.Adapt<TDto>();
|
||||||
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
|
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
|
||||||
return dto;
|
return dto;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
@ -26,7 +27,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
ITelemetryUserService telemetryUserService,
|
ITelemetryUserService telemetryUserService,
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||||
: base(db, telemetryService, telemetryDataCache)
|
: base(db, telemetryService, telemetryDataCache)
|
||||||
{
|
{
|
||||||
this.telemetryUserService = telemetryUserService;
|
this.telemetryUserService = telemetryUserService;
|
||||||
@ -43,37 +44,37 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
.Where(t => t.BlockPosition > 0.0001)
|
.Where(t => t.BlockPosition > 0.0001)
|
||||||
.Where(t => t.WellDepth > 0.0001)
|
.Where(t => t.WellDepth > 0.0001)
|
||||||
.Where(t => t.Mode != null)
|
.Where(t => t.Mode != null)
|
||||||
.Where(t => modes.Contains(t.Mode!.Value))
|
.Where(t => modes.Contains(t.Mode))
|
||||||
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
||||||
.GroupBy(t => new {
|
.GroupBy(t => new {
|
||||||
t.DateTime.Hour,
|
t.DateTime.Hour,
|
||||||
WellDepthX10 = Math.Truncate(t.WellDepth!.Value * 10),
|
WellDepthX10 = Math.Truncate(t.WellDepth * 10),
|
||||||
t.Mode,
|
t.Mode,
|
||||||
t.IdFeedRegulator})
|
t.IdFeedRegulator})
|
||||||
.Select(g => new TelemetryDataSaubStatDto
|
.Select(g => new TelemetryDataSaubStatDto
|
||||||
{
|
{
|
||||||
Count = g.Count(),
|
Count = g.Count(),
|
||||||
IdMode = g.Key.Mode??0,
|
IdMode = g.Key.Mode,
|
||||||
IdFeedRegulator = g.Key.IdFeedRegulator,
|
IdFeedRegulator = g.Key.IdFeedRegulator,
|
||||||
|
|
||||||
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||||
DateMax = DateTime.SpecifyKind(g.Max(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!.Value),
|
WellDepthMin = g.Min(t => t.WellDepth),
|
||||||
WellDepthMax = g.Max(t => t.WellDepth!.Value),
|
WellDepthMax = g.Max(t => t.WellDepth),
|
||||||
|
|
||||||
Pressure = g.Average(t => t.Pressure!.Value),
|
Pressure = g.Average(t => t.Pressure),
|
||||||
PressureSp = g.Average(t => t.PressureSp!.Value),
|
PressureSp = g.Average(t => t.PressureSp!.Value),
|
||||||
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
||||||
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
||||||
PressureDelta = g.Average(t => t.Pressure!.Value - t.PressureIdle!.Value),
|
PressureDelta = g.Average(t => t.Pressure - t.PressureIdle!.Value),
|
||||||
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
|
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
|
||||||
|
|
||||||
AxialLoad = g.Average(t => t.AxialLoad!.Value),
|
AxialLoad = g.Average(t => t.AxialLoad),
|
||||||
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
|
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
|
||||||
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
|
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
|
||||||
|
|
||||||
RotorTorque = g.Average(t => t.RotorTorque!.Value),
|
RotorTorque = g.Average(t => t.RotorTorque),
|
||||||
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
|
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
|
||||||
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
|
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
@ -11,7 +12,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public TelemetryDataSpinService(
|
public TelemetryDataSpinService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache)
|
ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache)
|
||||||
: base(db, telemetryService, telemetryDataCache)
|
: base(db, telemetryService, telemetryDataCache)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
@ -18,7 +19,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache;
|
//TODO: методы использующие ITelemetryDataCache, скорее всего, тут не нужны
|
||||||
|
private readonly ITelemetryDataCache<TelemetryDataSaubDto> dataSaubCache;
|
||||||
private readonly ITimezoneService timezoneService;
|
private readonly ITimezoneService timezoneService;
|
||||||
|
|
||||||
public ITimezoneService TimeZoneService => timezoneService;
|
public ITimezoneService TimeZoneService => timezoneService;
|
||||||
@ -26,7 +28,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
public TelemetryService(
|
public TelemetryService(
|
||||||
IAsbCloudDbContext db,
|
IAsbCloudDbContext db,
|
||||||
IMemoryCache memoryCache,
|
IMemoryCache memoryCache,
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> dataSaubCache,
|
ITelemetryDataCache<TelemetryDataSaubDto> dataSaubCache,
|
||||||
ITimezoneService timezoneService)
|
ITimezoneService timezoneService)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
@ -26,7 +26,7 @@ public class WorkSubsystemOperationTimeCalc : Work
|
|||||||
public WorkSubsystemOperationTimeCalc()
|
public WorkSubsystemOperationTimeCalc()
|
||||||
: base("Subsystem operation time calc")
|
: base("Subsystem operation time calc")
|
||||||
{
|
{
|
||||||
Timeout = TimeSpan.FromMinutes(20);
|
Timeout = TimeSpan.FromMinutes(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
||||||
@ -55,10 +55,12 @@ public class WorkSubsystemOperationTimeCalc : Work
|
|||||||
{
|
{
|
||||||
IdTelemetry = outer,
|
IdTelemetry = outer,
|
||||||
inner.SingleOrDefault()?.LastDate,
|
inner.SingleOrDefault()?.LastDate,
|
||||||
});
|
})
|
||||||
|
.OrderByDescending(i => i.IdTelemetry);
|
||||||
|
|
||||||
var count = telemetryLastDetectedDates.Count();
|
var count = telemetryLastDetectedDates.Count();
|
||||||
var i = 0d;
|
var i = 0d;
|
||||||
|
|
||||||
foreach (var item in telemetryLastDetectedDates)
|
foreach (var item in telemetryLastDetectedDates)
|
||||||
{
|
{
|
||||||
onProgressCallback($"Start handling telemetry: {item.IdTelemetry} from {item.LastDate}", i++ / count);
|
onProgressCallback($"Start handling telemetry: {item.IdTelemetry} from {item.LastDate}", i++ / count);
|
||||||
@ -277,11 +279,11 @@ public class WorkSubsystemOperationTimeCalc : Work
|
|||||||
.Where(d => d.DateTime <= dateEnd)
|
.Where(d => d.DateTime <= dateEnd)
|
||||||
.Where(d => d.WellDepth != null)
|
.Where(d => d.WellDepth != null)
|
||||||
.Where(d => d.WellDepth > 0)
|
.Where(d => d.WellDepth > 0)
|
||||||
.GroupBy(d => Math.Ceiling(d.WellDepth ?? 0 * 10))
|
.GroupBy(d => Math.Ceiling(d.WellDepth * 10))
|
||||||
.Select(g => new
|
.Select(g => new
|
||||||
{
|
{
|
||||||
DateMin = g.Min(d => d.DateTime),
|
DateMin = g.Min(d => d.DateTime),
|
||||||
DepthMin = g.Min(d => d.WellDepth) ?? 0,
|
DepthMin = g.Min(d => d.WellDepth),
|
||||||
})
|
})
|
||||||
.OrderBy(i => i.DateMin)
|
.OrderBy(i => i.DateMin)
|
||||||
.ToArrayAsync(token);
|
.ToArrayAsync(token);
|
||||||
|
@ -36,7 +36,7 @@ public class WellInfoService
|
|||||||
var operationsStatService = services.GetRequiredService<IOperationsStatService>();
|
var operationsStatService = services.GetRequiredService<IOperationsStatService>();
|
||||||
var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
|
var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
|
||||||
var subsystemOperationTimeService = services.GetRequiredService<ISubsystemOperationTimeService>();
|
var subsystemOperationTimeService = services.GetRequiredService<ISubsystemOperationTimeService>();
|
||||||
var telemetryDataSaubCache = services.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
|
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||||
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
|
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
|
||||||
|
|
||||||
var wells = await wellService.GetAllAsync(token);
|
var wells = await wellService.GetAllAsync(token);
|
||||||
@ -82,7 +82,7 @@ public class WellInfoService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
|
var wellOperationsStat = operationsStat.FirstOrDefault(s => s.Id == well.Id);
|
||||||
var wellLastFactSection = wellOperationsStat?.Sections.LastOrDefault(s => s.Fact is not null);
|
var wellLastFactSection = wellOperationsStat?.Sections.OrderBy(s => s.Fact?.WellDepthStart).LastOrDefault(s => s.Fact is not null);
|
||||||
currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd;
|
currentDepth ??= wellLastFactSection?.Fact?.WellDepthEnd;
|
||||||
|
|
||||||
var wellProcessMaps = processMapPlanWellDrillings
|
var wellProcessMaps = processMapPlanWellDrillings
|
||||||
@ -180,16 +180,16 @@ public class WellInfoService
|
|||||||
public IEnumerable<int> IdsCompanies { get; set; } = null!;
|
public IEnumerable<int> IdsCompanies { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
|
private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache;
|
||||||
private readonly TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache;
|
private readonly ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache;
|
||||||
private readonly IWitsRecordRepository<Record7Dto> witsRecord7Repository;
|
private readonly IWitsRecordRepository<Record7Dto> witsRecord7Repository;
|
||||||
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
|
private readonly IWitsRecordRepository<Record1Dto> witsRecord1Repository;
|
||||||
private readonly IGtrRepository gtrRepository;
|
private readonly IGtrRepository gtrRepository;
|
||||||
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
|
private static IEnumerable<WellMapInfoWithComanies> WellMapInfo = Enumerable.Empty<WellMapInfoWithComanies>();
|
||||||
|
|
||||||
public WellInfoService(
|
public WellInfoService(
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataSaubCache,
|
||||||
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
|
ITelemetryDataCache<TelemetryDataSpinDto> telemetryDataSpinCache,
|
||||||
IWitsRecordRepository<Record7Dto> witsRecord7Repository,
|
IWitsRecordRepository<Record7Dto> witsRecord7Repository,
|
||||||
IWitsRecordRepository<Record1Dto> witsRecord1Repository,
|
IWitsRecordRepository<Record1Dto> witsRecord1Repository,
|
||||||
IGtrRepository gtrRepository)
|
IGtrRepository gtrRepository)
|
||||||
|
@ -11,6 +11,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.WellOperationService;
|
namespace AsbCloudInfrastructure.Services.WellOperationService;
|
||||||
|
|
||||||
@ -19,10 +20,10 @@ public class OperationsStatService : IOperationsStatService
|
|||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
||||||
|
|
||||||
public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService,
|
public OperationsStatService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService,
|
||||||
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.memoryCache = memoryCache;
|
this.memoryCache = memoryCache;
|
||||||
|
@ -33,7 +33,8 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
.Include(w => w.Telemetry)
|
.Include(w => w.Telemetry)
|
||||||
.Include(w => w.WellType)
|
.Include(w => w.WellType)
|
||||||
.Include(w => w.RelationCompaniesWells)
|
.Include(w => w.RelationCompaniesWells)
|
||||||
.ThenInclude(r => r.Company);
|
.ThenInclude(r => r.Company)
|
||||||
|
.AsNoTracking();
|
||||||
|
|
||||||
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService, WellInfoService wellInfoService)
|
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService, WellInfoService wellInfoService)
|
||||||
: base(db, memoryCache, MakeQueryWell)
|
: base(db, memoryCache, MakeQueryWell)
|
||||||
@ -105,19 +106,18 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
public async Task<WellMapInfoWithTelemetryStat?> GetOrDefaultStatAsync(int idWell, CancellationToken token)
|
public async Task<WellMapInfoWithTelemetryStat?> GetOrDefaultStatAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var dto = wellInfoService.FirstOrDefault(well => well.Id == idWell);
|
var well = await GetOrDefaultAsync(idWell, token);
|
||||||
if (dto is not null)
|
|
||||||
return dto;
|
|
||||||
|
|
||||||
var request = new WellRequest{Ids = new[] { idWell }};
|
if (well is null)
|
||||||
var entities = await GetEntitiesAsync(request, token);
|
|
||||||
var entity = entities.FirstOrDefault();
|
|
||||||
if (entity is null)
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
dto = entity.Adapt<WellMapInfoWithTelemetryStat>();
|
var wellInfo = wellInfoService.FirstOrDefault(well => well.Id == idWell);
|
||||||
|
|
||||||
return dto;
|
if (wellInfo is null)
|
||||||
|
return well.Adapt<WellMapInfoWithTelemetryStat>();
|
||||||
|
|
||||||
|
wellInfo.IdState = well.IdState;
|
||||||
|
return wellInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<WellDto>> GetAsync(WellRequest request, CancellationToken token)
|
public async Task<IEnumerable<WellDto>> GetAsync(WellRequest request, CancellationToken token)
|
||||||
|
@ -1,91 +1,134 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
using Mapster;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services;
|
namespace AsbCloudInfrastructure.Services;
|
||||||
|
|
||||||
public class WellboreService : IWellboreService
|
public class WellboreService : IWellboreService
|
||||||
{
|
{
|
||||||
|
const string WellboreNameFormat = "Ствол {0}";
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
private readonly IWellOperationRepository wellOperationRepository;
|
private readonly IWellOperationRepository wellOperationRepository;
|
||||||
|
private readonly ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
||||||
|
|
||||||
public WellboreService(IWellService wellService, IWellOperationRepository wellOperationRepository)
|
public WellboreService(
|
||||||
|
IWellService wellService,
|
||||||
|
IWellOperationRepository wellOperationRepository,
|
||||||
|
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||||
{
|
{
|
||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
this.wellOperationRepository = wellOperationRepository;
|
this.wellOperationRepository = wellOperationRepository;
|
||||||
}
|
this.telemetryDataCache = telemetryDataCache;
|
||||||
|
|
||||||
public async Task<WellboreDto?> 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<WellboreDto>> GetWellboresAsync(WellboreRequest request,
|
public async Task<IEnumerable<WellboreDto>> GetWellboresAsync(IEnumerable<int> idsWells,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
var wellbores = new List<WellboreDto>(request.Ids.Count());
|
var wellRequest = new WellRequest { Ids = idsWells };
|
||||||
var skip = request.Skip ?? 0;
|
var wells = await wellService.GetAsync(wellRequest, token);
|
||||||
var take = request.Take ?? 10;
|
|
||||||
|
|
||||||
var sections = wellOperationRepository.GetSectionTypes()
|
var rowSections = await wellOperationRepository.GetSectionsAsync(idsWells, token);
|
||||||
.ToDictionary(w => w.Id, w => w);
|
var groupedSections = rowSections
|
||||||
|
.Where(section => section.IdType == 1)
|
||||||
|
.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<WellboreDto> MakeWellboreDefault(WellDto well)
|
||||||
|
{
|
||||||
|
var wellbore = new WellboreDto {
|
||||||
|
Id = 1,
|
||||||
|
Name = string.Format(WellboreNameFormat, 1),
|
||||||
|
Well = well,
|
||||||
|
};
|
||||||
|
//if(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)
|
wellbore.DateEnd = dataCache.Value.Last.DateTime;
|
||||||
continue;
|
wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value;
|
||||||
|
}
|
||||||
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<WellWithTimezoneDto>(),
|
|
||||||
DateStart = section.DateStart.ToOffset(wellTimezoneOffset),
|
|
||||||
DateEnd = section.DateEnd.ToOffset(wellTimezoneOffset),
|
|
||||||
DepthStart = section.DepthStart,
|
|
||||||
DepthEnd = section.DepthEnd,
|
|
||||||
});
|
|
||||||
|
|
||||||
wellbores.AddRange(wellWellbores);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wellbores
|
return new[] { wellbore };
|
||||||
.OrderBy(w => w.Well.Id).ThenBy(w => w.Id)
|
}
|
||||||
.Skip(skip).Take(take);
|
|
||||||
}
|
private IEnumerable<WellboreDto> MakeWellboreBySections(IEnumerable<SectionByOperationsDto> sections, WellDto well)
|
||||||
|
{
|
||||||
|
var orderedSections = sections.OrderBy(s => s.DateStart);
|
||||||
|
var wellbores = new List<WellboreDto>();
|
||||||
|
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.DateEnd = dataCache.Value.Last.DateTime;
|
||||||
|
wellbore.DepthEnd = dataCache.Value.Last.WellDepth!.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wellbores;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
using AsbCloudApp.Services;
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudDb.Model;
|
|
||||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||||
using AsbCloudInfrastructure.Services;
|
using AsbCloudInfrastructure.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
using System;
|
||||||
@ -10,8 +8,9 @@ using System.Threading.Tasks;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using AsbCloudApp.Data.SAUB;
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudInfrastructure.Services.SAUB;
|
|
||||||
using AsbCloudInfrastructure.Services.Subsystems;
|
using AsbCloudInfrastructure.Services.Subsystems;
|
||||||
|
using AsbCloudDb;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
{
|
{
|
||||||
@ -23,19 +22,19 @@ namespace AsbCloudInfrastructure
|
|||||||
var provider = scope.ServiceProvider;
|
var provider = scope.ServiceProvider;
|
||||||
|
|
||||||
var context = provider.GetRequiredService<IAsbCloudDbContext>();
|
var context = provider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
context.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
context.Database.EnshureCreatedAndMigrated();
|
||||||
context.Database.Migrate();
|
|
||||||
|
|
||||||
// TODO: Сделать инициализацию кеша телеметрии более явной.
|
// TODO: Сделать инициализацию кеша телеметрии более явной.
|
||||||
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSaubDto>>();
|
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||||
_ = provider.GetRequiredService<TelemetryDataCache<TelemetryDataSpinDto>>();
|
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>();
|
||||||
|
|
||||||
var backgroundWorker = provider.GetRequiredService<BackgroundWorker>();
|
var backgroundWorker = provider.GetRequiredService<PeriodicBackgroundWorker>();
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WorkToDeleteOldReports>(TimeSpan.FromDays(1));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkOperationDetection>(TimeSpan.FromMinutes(15));
|
backgroundWorker.Add<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WorkOperationDetection>(TimeSpan.FromMinutes(15));
|
||||||
backgroundWorker.WorkStore.AddPeriodic<WorkLimitingParameterCalc>(TimeSpan.FromMinutes(30));
|
backgroundWorker.Add<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
||||||
backgroundWorker.WorkStore.AddPeriodic(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
|
backgroundWorker.Add<WorkLimitingParameterCalc>(TimeSpan.FromMinutes(30));
|
||||||
|
backgroundWorker.Add(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
|
var notificationBackgroundWorker = provider.GetRequiredService<NotificationBackgroundWorker>();
|
||||||
|
|
||||||
|
@ -8,119 +8,123 @@ namespace AsbCloudInfrastructure;
|
|||||||
|
|
||||||
internal static class XLExtentions
|
internal static class XLExtentions
|
||||||
{
|
{
|
||||||
internal static IXLRange _SetValue(this IXLRange range, object value)
|
internal static IXLRange _SetValue(this IXLRange range, object value)
|
||||||
{
|
{
|
||||||
var mergedRange = range.Merge();
|
var mergedRange = range.Merge();
|
||||||
mergedRange.FirstCell()._SetValue(value);
|
mergedRange.FirstCell()._SetValue(value);
|
||||||
var colWidth = mergedRange.FirstCell().WorksheetColumn().Width;
|
var colWidth = mergedRange.FirstCell().WorksheetColumn().Width;
|
||||||
var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize);
|
var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize);
|
||||||
if (value is string valueString && valueString.Length > maxCharsToWrap)
|
if (value is string valueString && valueString.Length > maxCharsToWrap)
|
||||||
{
|
{
|
||||||
var row = mergedRange.FirstCell().WorksheetRow();
|
var row = mergedRange.FirstCell().WorksheetRow();
|
||||||
var baseHeight = row.Height;
|
var baseHeight = row.Height;
|
||||||
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap);
|
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedRange.Style.SetAllBorders()
|
mergedRange.Style.SetAllBorders()
|
||||||
.Alignment.SetWrapText(true);
|
.Alignment.SetWrapText(true);
|
||||||
return mergedRange;
|
return mergedRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLCell _SetValue(this IXLCell cell, object value)
|
internal static IXLCell _SetValue(this IXLCell cell, object value)
|
||||||
{
|
{
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case DateTime dateTime:
|
case DateTime dateTime:
|
||||||
cell._SetValue(dateTime);
|
cell._SetValue(dateTime);
|
||||||
break;
|
break;
|
||||||
case IFormattable formattable:
|
case IFormattable formattable:
|
||||||
cell._SetValue(formattable);
|
cell._SetValue(formattable);
|
||||||
break;
|
break;
|
||||||
case string valueString:
|
case string valueString:
|
||||||
cell._SetValue(valueString);
|
cell._SetValue(valueString);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLCell _SetValue(this IXLCell cell, string value, bool adaptRowHeight = false)
|
internal static IXLCell _SetValue(this IXLCell cell, string value, bool adaptRowHeight = false)
|
||||||
{
|
{
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
cell.Style
|
cell.Style
|
||||||
.SetAllBorders()
|
.SetAllBorders()
|
||||||
.Alignment.WrapText = true;
|
.Alignment.WrapText = true;
|
||||||
|
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
if (adaptRowHeight)
|
if (adaptRowHeight)
|
||||||
{
|
{
|
||||||
var colWidth = cell.WorksheetColumn().Width;
|
var colWidth = cell.WorksheetColumn().Width;
|
||||||
var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
|
var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
|
||||||
if (value.Length > maxCharsToWrap)
|
if (value.Length > maxCharsToWrap)
|
||||||
{
|
{
|
||||||
var row = cell.WorksheetRow();
|
var row = cell.WorksheetRow();
|
||||||
var baseHeight = row.Height;
|
var baseHeight = row.Height;
|
||||||
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
|
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLCell _ValueNoBorder(this IXLCell cell, string value, bool adaptRowHeight = false)
|
internal static IXLCell _ValueNoBorder(this IXLCell cell, string value, bool adaptRowHeight = false)
|
||||||
{
|
{
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
cell.Style.Alignment.WrapText = true;
|
cell.Style.Alignment.WrapText = true;
|
||||||
|
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
if (adaptRowHeight)
|
if (adaptRowHeight)
|
||||||
{
|
{
|
||||||
var colWidth = cell.WorksheetColumn().Width;
|
var colWidth = cell.WorksheetColumn().Width;
|
||||||
var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
|
var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
|
||||||
if (value.Length > maxCharsToWrap)
|
if (value.Length > maxCharsToWrap)
|
||||||
{
|
{
|
||||||
var row = cell.WorksheetRow();
|
var row = cell.WorksheetRow();
|
||||||
var baseHeight = row.Height;
|
var baseHeight = row.Height;
|
||||||
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
|
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static IXLCell _SetValue(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS")
|
internal static IXLCell _SetValue(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS", bool setAllBorders = true)
|
||||||
{
|
{
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
cell.Style
|
if (setAllBorders == true)
|
||||||
.SetAllBorders()
|
{
|
||||||
.Alignment.WrapText = true;
|
cell.Style
|
||||||
|
.SetAllBorders()
|
||||||
|
.Alignment.WrapText = true;
|
||||||
|
}
|
||||||
|
|
||||||
cell.Value = value;
|
|
||||||
|
|
||||||
cell.DataType = XLDataType.DateTime;
|
cell.Value = value;
|
||||||
cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS";
|
|
||||||
|
|
||||||
return cell;
|
cell.DataType = XLDataType.DateTime;
|
||||||
}
|
cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS";
|
||||||
|
|
||||||
internal static IXLCell _SetValue(this IXLCell cell, IFormattable value, string format = "0.00")
|
return cell;
|
||||||
{
|
}
|
||||||
cell.Value = value;
|
|
||||||
cell.Style
|
|
||||||
.SetAllBorders()
|
|
||||||
.Alignment.WrapText = true;
|
|
||||||
|
|
||||||
cell.Value = value;
|
internal static IXLCell _SetValue(this IXLCell cell, IFormattable value, string format = "0.00")
|
||||||
|
{
|
||||||
|
cell.Value = value;
|
||||||
|
cell.Style
|
||||||
|
.SetAllBorders()
|
||||||
|
.Alignment.WrapText = true;
|
||||||
|
|
||||||
cell.DataType = XLDataType.Number;
|
cell.Value = value;
|
||||||
cell.Style.NumberFormat.Format = "0.00";
|
|
||||||
|
|
||||||
return cell;
|
cell.DataType = XLDataType.Number;
|
||||||
}
|
cell.Style.NumberFormat.Format = "0.00";
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
public static IXLCell SetVal(this IXLCell cell, double? value, string format = "0.00")
|
public static IXLCell SetVal(this IXLCell cell, double? value, string format = "0.00")
|
||||||
{
|
{
|
||||||
@ -158,60 +162,60 @@ internal static class XLExtentions
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLStyle SetAllBorders(this IXLStyle style, XLBorderStyleValues borderStyle = XLBorderStyleValues.Thin)
|
internal static IXLStyle SetAllBorders(this IXLStyle style, XLBorderStyleValues borderStyle = XLBorderStyleValues.Thin)
|
||||||
{
|
{
|
||||||
style.Border.RightBorder = borderStyle;
|
style.Border.RightBorder = borderStyle;
|
||||||
style.Border.LeftBorder = borderStyle;
|
style.Border.LeftBorder = borderStyle;
|
||||||
style.Border.TopBorder = borderStyle;
|
style.Border.TopBorder = borderStyle;
|
||||||
style.Border.BottomBorder = borderStyle;
|
style.Border.BottomBorder = borderStyle;
|
||||||
style.Border.InsideBorder = borderStyle;
|
style.Border.InsideBorder = borderStyle;
|
||||||
style.Border.OutsideBorder = borderStyle;
|
style.Border.OutsideBorder = borderStyle;
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLStyle SetBaseFont(this IXLStyle style)
|
internal static IXLStyle SetBaseFont(this IXLStyle style)
|
||||||
{
|
{
|
||||||
style.Font.FontName = "Calibri";
|
style.Font.FontName = "Calibri";
|
||||||
style.Font.FontSize = 10;
|
style.Font.FontSize = 10;
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IXLStyle SetH1(this IXLStyle style)
|
internal static IXLStyle SetH1(this IXLStyle style)
|
||||||
{
|
{
|
||||||
style.Font.FontName = "Calibri";
|
style.Font.FontName = "Calibri";
|
||||||
style.Font.FontSize = 14;
|
style.Font.FontSize = 14;
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Костыль исправляющий проблему в библиотеке IXLRange Range(this IXLWorksheet, IXLAddress, IXLAddress) с кастингом IXLAddress к XLAddress.
|
/// Костыль исправляющий проблему в библиотеке IXLRange Range(this IXLWorksheet, IXLAddress, IXLAddress) с кастингом IXLAddress к XLAddress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sheet"></param>
|
/// <param name="sheet"></param>
|
||||||
/// <param name="begin"></param>
|
/// <param name="begin"></param>
|
||||||
/// <param name="end"></param>
|
/// <param name="end"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static IXLRange _Range(this IXLWorksheet sheet, CellAddress begin, CellAddress end)
|
internal static IXLRange _Range(this IXLWorksheet sheet, CellAddress begin, CellAddress end)
|
||||||
=> sheet.Range(begin.RowNumber, begin.ColumnNumber, end.RowNumber, end.ColumnNumber);
|
=> sheet.Range(begin.RowNumber, begin.ColumnNumber, end.RowNumber, end.ColumnNumber);
|
||||||
|
|
||||||
|
|
||||||
internal static T? GetCellValue<T>(this IXLCell cell)
|
internal static T? GetCellValue<T>(this IXLCell cell)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (cell.IsEmpty() && default(T) == null)
|
if (cell.IsEmpty() && default(T) == null)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
if (typeof(T) != typeof(DateTime))
|
if (typeof(T) != typeof(DateTime))
|
||||||
return (T)Convert.ChangeType(cell.GetFormattedString(), typeof(T), CultureInfo.InvariantCulture);
|
return (T)Convert.ChangeType(cell.GetFormattedString(), typeof(T), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
if (cell.Value is DateTime dateTime)
|
if (cell.Value is DateTime dateTime)
|
||||||
return (T)(object)dateTime;
|
return (T)(object)dateTime;
|
||||||
|
|
||||||
return (T)(object)DateTime.FromOADate((double)cell.Value);
|
return (T)(object)DateTime.FromOADate((double)cell.Value);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
throw new FileFormatException(
|
throw new FileFormatException(
|
||||||
$"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение");
|
$"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,6 +15,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||||
<PackageReference Include="MockQueryable.Moq" Version="6.0.1" />
|
<PackageReference Include="MockQueryable.Moq" Version="6.0.1" />
|
||||||
<PackageReference Include="Moq" Version="4.18.2" />
|
<PackageReference Include="Moq" Version="4.18.2" />
|
||||||
|
<PackageReference Include="NSubstitute" Version="5.1.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.2" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
@ -48,11 +48,26 @@ namespace AsbCloudWebApi.Tests.Middlware
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DatesRangeDto? GetRange(int idWell, DateTimeOffset start, DateTimeOffset end)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatesRangeDto? GetRange(int idWell)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token)
|
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset start, DateTimeOffset end, CancellationToken token)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<DatesRangeDto?> GetRangeAsync(int idWell, DateTimeOffset geDate, DateTimeOffset? leDate, CancellationToken token)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) => throw new NotImplementedException();
|
public Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token) => throw new NotImplementedException();
|
||||||
|
|
||||||
public Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
public Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
||||||
|
113
AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs
Normal file
113
AsbCloudWebApi.Tests/Services/BackgroundWorkertest.cs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services;
|
||||||
|
|
||||||
|
public class BackgroundWorkerTest
|
||||||
|
{
|
||||||
|
private IServiceProvider provider;
|
||||||
|
private BackgroundWorker service;
|
||||||
|
|
||||||
|
public BackgroundWorkerTest()
|
||||||
|
{
|
||||||
|
provider = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
||||||
|
var serviceScope = Substitute.For<IServiceScope>();
|
||||||
|
var serviceScopeFactory = Substitute.For<IServiceScopeFactory>();
|
||||||
|
serviceScopeFactory.CreateScope().Returns(serviceScope);
|
||||||
|
((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory);
|
||||||
|
|
||||||
|
service = new BackgroundWorker(provider);
|
||||||
|
typeof(BackgroundWorker)
|
||||||
|
.GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_n_works()
|
||||||
|
{
|
||||||
|
var workCount = 10;
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
for (int i = 0; i < workCount; i++)
|
||||||
|
{
|
||||||
|
var work = Work.CreateByDelegate(i.ToString(), workAction);
|
||||||
|
service.Enqueue(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(workCount, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_continues_after_exceptions()
|
||||||
|
{
|
||||||
|
var expectadResult = 42;
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result = expectadResult;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
var goodWork = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
Task failAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
=> throw new Exception();
|
||||||
|
|
||||||
|
var badWork = Work.CreateByDelegate("", failAction);
|
||||||
|
badWork.OnErrorAsync = (id, exception, token) => throw new Exception();
|
||||||
|
|
||||||
|
//act
|
||||||
|
service.Enqueue(badWork);
|
||||||
|
service.Enqueue(goodWork);
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(expectadResult, result);
|
||||||
|
Assert.Equal(1, service.Felled.Count);
|
||||||
|
Assert.Equal(1, service.Done.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TryRemove()
|
||||||
|
{
|
||||||
|
var workCount = 5;
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.Delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
for (int i = 0; i < workCount; i++)
|
||||||
|
{
|
||||||
|
var work = Work.CreateByDelegate(i.ToString(), workAction);
|
||||||
|
service.Enqueue(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
var removed = service.TryRemoveFromQueue((workCount - 1).ToString());
|
||||||
|
|
||||||
|
await service.ExecuteTask;
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.True(removed);
|
||||||
|
Assert.Equal(workCount - 1, result);
|
||||||
|
Assert.Equal(workCount - 1, service.Done.Count);
|
||||||
|
}
|
||||||
|
}
|
@ -366,7 +366,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
|||||||
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
var state = await service.GetStateAsync(idWell, publisher1.Id, CancellationToken.None);
|
||||||
|
|
||||||
Assert.Equal(2, state.IdState);
|
Assert.Equal(2, state.IdState);
|
||||||
backgroundWorkerMock.Verify(s => s.Push(It.IsAny<Work>()));
|
backgroundWorkerMock.Verify(s => s.Enqueue(It.IsAny<Work>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
@ -0,0 +1,97 @@
|
|||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.Services;
|
||||||
|
|
||||||
|
public class PeriodicBackgroundWorkerTest
|
||||||
|
{
|
||||||
|
private IServiceProvider provider;
|
||||||
|
private PeriodicBackgroundWorker service;
|
||||||
|
|
||||||
|
public PeriodicBackgroundWorkerTest()
|
||||||
|
{
|
||||||
|
provider = Substitute.For<IServiceProvider, ISupportRequiredService>();
|
||||||
|
var serviceScope = Substitute.For<IServiceScope>();
|
||||||
|
var serviceScopeFactory = Substitute.For<IServiceScopeFactory>();
|
||||||
|
serviceScopeFactory.CreateScope().Returns(serviceScope);
|
||||||
|
((ISupportRequiredService)provider).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactory);
|
||||||
|
|
||||||
|
service = new PeriodicBackgroundWorker(provider);
|
||||||
|
typeof(PeriodicBackgroundWorker)
|
||||||
|
.GetField("minDelay", BindingFlags.NonPublic | BindingFlags.Instance)?
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
|
||||||
|
typeof(PeriodicBackgroundWorker)
|
||||||
|
.GetField("executePeriod", BindingFlags.NonPublic | BindingFlags.Instance)?
|
||||||
|
.SetValue(service, TimeSpan.FromMilliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WorkRunsTwice()
|
||||||
|
{
|
||||||
|
var workCount = 2;
|
||||||
|
var periodMs = 100d;
|
||||||
|
|
||||||
|
var period = TimeSpan.FromMilliseconds(periodMs);
|
||||||
|
|
||||||
|
var result = 0;
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
//act
|
||||||
|
var work = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
var stopwatch = Stopwatch.StartNew();
|
||||||
|
service.Add(work, period);
|
||||||
|
|
||||||
|
var delay = (periodMs / 20) + (periodMs * workCount) - stopwatch.ElapsedMilliseconds;
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(delay));
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(workCount, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Enqueue_continues_after_exceptions()
|
||||||
|
{
|
||||||
|
var expectadResult = 42;
|
||||||
|
var result = 0;
|
||||||
|
|
||||||
|
Task workAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
{
|
||||||
|
result = expectadResult;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
var goodWork = Work.CreateByDelegate("", workAction);
|
||||||
|
|
||||||
|
Task failAction(string id, IServiceProvider services, Action<string, double?> callback, CancellationToken token)
|
||||||
|
=> throw new Exception();
|
||||||
|
|
||||||
|
var badWork = Work.CreateByDelegate("", failAction);
|
||||||
|
badWork.OnErrorAsync = (id, exception, token) => throw new Exception();
|
||||||
|
|
||||||
|
//act
|
||||||
|
service.Add(badWork, TimeSpan.FromSeconds(2));
|
||||||
|
service.Add(goodWork, TimeSpan.FromSeconds(2));
|
||||||
|
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(20));
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(expectadResult, result);
|
||||||
|
Assert.Equal(1, badWork.CountErrors);
|
||||||
|
Assert.Equal(1, goodWork.CountComplete);
|
||||||
|
Assert.Equal(1, goodWork.CountStart);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using AsbCloudInfrastructure.Background;
|
||||||
|
using AsbCloudInfrastructure.Services.SAUB;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Tests.ServicesTests.SAUB;
|
||||||
|
|
||||||
|
public class TelemetryDataSaubCacheTests
|
||||||
|
{
|
||||||
|
private const int idTelemetry = 1;
|
||||||
|
|
||||||
|
private readonly IEnumerable<TelemetryDataSaubDto> fakeTelemetries = new[]
|
||||||
|
{
|
||||||
|
new TelemetryDataSaubDto()
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly IServiceProvider serviceProviderMock = Substitute.For<IServiceProvider>();
|
||||||
|
|
||||||
|
private readonly TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache;
|
||||||
|
private readonly Type telemetryDataCacheType;
|
||||||
|
|
||||||
|
public TelemetryDataSaubCacheTests()
|
||||||
|
{
|
||||||
|
serviceProviderMock.GetService<BackgroundWorker>().Returns(new BackgroundWorker(serviceProviderMock));
|
||||||
|
|
||||||
|
telemetryDataCache = TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(serviceProviderMock);
|
||||||
|
|
||||||
|
telemetryDataCacheType = telemetryDataCache.GetType();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddRange_ShouldReturn_AddedElementToCache()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, false);
|
||||||
|
|
||||||
|
//act
|
||||||
|
telemetryDataCache.AddRange(idTelemetry, fakeTelemetries);
|
||||||
|
var lastTelemetry = telemetryDataCache.GetLastOrDefault(idTelemetry);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(lastTelemetry, fakeTelemetries.Last());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddRange_ShouldReturn_NotAddedToCache()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, true);
|
||||||
|
|
||||||
|
//act
|
||||||
|
telemetryDataCache.AddRange(idTelemetry, fakeTelemetries);
|
||||||
|
var lastTelemetry = telemetryDataCache.GetLastOrDefault(idTelemetry);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotEqual(lastTelemetry, fakeTelemetries.Last());
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user