Merge branch 'dev' into SubsystemsOperationTime

This commit is contained in:
ngfrolov 2022-10-19 13:55:53 +05:00
commit 24a1afb5a8
60 changed files with 9357 additions and 1350 deletions

6
.gitignore vendored
View File

@ -174,13 +174,13 @@ publish/
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# *.pubxml
# *.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# PublishScripts/
# NuGet Packages
*.nupkg

View File

@ -13,4 +13,16 @@
<ItemGroup>
<None Remove="Data\DailyReport\" />
</ItemGroup>
<ItemGroup>
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>
<ItemGroup>
<None Include="D:\Source\AsbCloudApp\Services\.editorconfig" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AsbCloudDb\AsbCloudDb.csproj" />
</ItemGroup>
</Project>

View File

@ -1,5 +1,6 @@
namespace AsbCloudApp.Data.DailyReport
{
#nullable enable
/// <summary>
/// Блоки для формирования суточного рапорта
/// </summary>
@ -35,4 +36,5 @@
/// </summary>
public SignDto Sign { get; set; } = new();
}
#nullable disable
}

View File

@ -13,14 +13,9 @@ namespace AsbCloudApp.Data
public int IdWell { get; set; }
/// <summary>
/// Ãëóáèíà íà÷àëà èíòåðâàëà äëÿ ýòèõ ïàðàìåòðîâ
/// Ãëóáèíà èíòåðâàëà
/// </summary>
public double DepthStart { get; set; }
/// <summary>
/// Ãëóáèíà îêîí÷àíèÿ èíòåðâàëà äëÿ ýòèõ ïàðàìåòðîâ
/// </summary>
public double DepthEnd { get; set; }
public MinMaxDto<double> Depth { get; set; }
/// <summary>
/// id well section type.
@ -28,78 +23,28 @@ namespace AsbCloudApp.Data
public int IdWellSectionType { get; set; }
/// <summary>
/// axial load min.
/// axial load
/// </summary>
public double AxialLoadMin { get; set; }
public MinMaxExtendedViewDto AxialLoad { get; set; }
/// <summary>
/// axial load avg.
/// pressure
/// </summary>
public double AxialLoadAvg { get; set; }
public MinMaxExtendedViewDto Pressure { get; set; }
/// <summary>
/// axial load max.
/// rotor torque
/// </summary>
public double AxialLoadMax { get; set; }
public MinMaxExtendedViewDto RotorTorque { get; set; }
/// <summary>
/// pressure min.
/// rotor speed
/// </summary>
public double PressureMin { get; set; }
public MinMaxExtendedViewDto RotorSpeed { get; set; }
/// <summary>
/// pressure avg.
/// flow
/// </summary>
public double PressureAvg { get; set; }
/// <summary>
/// pressure max.
/// </summary>
public double PressureMax { get; set; }
/// <summary>
/// rotor torque min.
/// </summary>
public double RotorTorqueMin { get; set; }
/// <summary>
/// rotor torque avg.
/// </summary>
public double RotorTorqueAvg { get; set; }
/// <summary>
/// rotor torque max.
/// </summary>
public double RotorTorqueMax { get; set; }
/// <summary>
/// rotor speed min.
/// </summary>
public double RotorSpeedMin { get; set; }
/// <summary>
/// rotor speed avg.
/// </summary>
public double RotorSpeedAvg { get; set; }
/// <summary>
/// rotor speed max.
/// </summary>
public double RotorSpeedMax { get; set; }
/// <summary>
/// flow min.
/// </summary>
public double FlowMin { get; set; }
/// <summary>
/// flow avg.
/// </summary>
public double FlowAvg { get; set; }
/// <summary>
/// flow max.
/// </summary>
public double FlowMax { get; set; }
public MinMaxExtendedViewDto Flow { get; set; }
}
}

View File

@ -39,6 +39,11 @@ namespace AsbCloudApp.Data
/// </summary>
public long Size { get; set; }
/// <summary>
/// Помечен как удаленный
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// DTO автора
/// </summary>

View File

@ -0,0 +1,56 @@
using System;
using System.Collections;
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// Состояние фоновой задачи
/// </summary>
public enum JobState
{
/// <summary>
/// Ожидает в очереди на выполнение
/// </summary>
Waiting,
/// <summary>
/// выполняется
/// </summary>
Working,
/// <summary>
/// успешно выполнена
/// </summary>
Done,
/// <summary>
/// завершена с ошибкой
/// </summary>
Fail
};
/// <summary>
/// работа фоновой задачи
/// </summary>
public class JobDto
{
/// <summary>
/// идентификатор
/// </summary>
public int Id { get; set; }
/// <summary>
/// Состояние
/// </summary>
public JobState State { get; set; }
/// <summary>
/// результат выполнения
/// </summary>
public Hashtable? Results { get; set; }
/// <summary>
/// Исключение, если возникла ошибка
/// </summary>
public string? Error { get; set; }
}
#nullable disable
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// Минимальное и максимальное значение
/// </summary>
public class MinMaxDto<T>
{
/// <summary>
/// Минимальное значение
/// </summary>
public T? Min { get; set; }
/// <summary>
/// Максимальное значение
/// </summary>
public T? Max { get; set; }
}
#nullable disable
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsbCloudApp.Data
{
#nullable enable
/// <summary>
/// Расширение для класса MinMaxDto
/// </summary>
public class MinMaxExtendedViewDto : MinMaxDto<double>
{
/// <summary>
/// Среднее значение
/// </summary>
public double Avg { get; set; }
/// <summary>
/// Является максимальным
/// </summary>
public bool IsMax { get; set; }
/// <summary>
/// Является минимальным
/// </summary>
public bool IsMin { get; set; }
}
#nullable disable
}

View File

@ -2,80 +2,77 @@
namespace AsbCloudApp.Data.SAUB
{
#pragma warning disable CS1591 // Отсутствует комментарий XML для открытого видимого типа или члена
#nullable enable
public class TelemetryDataSpinDto : ITelemetryData
{
/// <inheritdoc/>
/// <summary>
/// Идентификатор телеметрии
/// </summary>
public int IdTelemetry { get; set; }
/// <summary>
/// Дата
/// </summary>
public DateTime DateTime { get; set; }
public DateTime Date // TODO: remove this legacy after all panels updated
/// <summary>
/// Дата
/// </summary>
public DateTime Date
{
get { return DateTime; }
set { DateTime = value; }
}
public float? TopDriveSpeed { get; set; }
public float? TopDriveSpeedMin { get; set; }
public float? TopDriveSpeedMax { get; set; }
public float? TopDriveSpeedOffset { get; set; }
public short? TopDriveSpeedErr { get; set; }
public float? TopDriveTorque { get; set; }
public float? TopDriveTorqueMin { get; set; }
public float? TopDriveTorqueMax { get; set; }
public float? TopDriveTorqueOffset { get; set; }
public short? TopDriveTorqueErr { get; set; }
public float? TopDriveSpeedSpFrom { get; set; }
public float? TopDriveSpeedSpFromMin { get; set; }
public float? TopDriveSpeedSpFromMax { get; set; }
public float? TopDriveSpeedSpFromOffset { get; set; }
public short? TopDriveSpeedSpFromErr { get; set; }
public float? TopDriveTorqueSpFrom { get; set; }
public float? TopDriveTorqueSpFromMin { get; set; }
public float? TopDriveTorqueSpFromMax { get; set; }
public float? TopDriveTorqueSpFromOffset { get; set; }
public short? TopDriveTorqueSpFromErr { get; set; }
public float? TopDriveSpeedSpTo { get; set; }
public float? TopDriveSpeedSpToMin { get; set; }
public float? TopDriveSpeedSpToMax { get; set; }
public float? TopDriveSpeedSpToOffset { get; set; }
public short? TopDriveSpeedSpToErr { get; set; }
public float? TopDriveTorqueSpTo { get; set; }
public float? TopDriveTorqueSpToMin { get; set; }
public float? TopDriveTorqueSpToMax { get; set; }
public float? TopDriveTorqueSpToOffset { get; set; }
public short? TopDriveTorqueSpToErr { get; set; }
public short? W2800 { get; set; }
public short? W2810 { get; set; }
public short? Mode { get; set; }
public short? W2808 { get; set; }
public float? TorqueStarting { get; set; }
public float? RotorTorqueAvg { get; set; }
public float? EncoderResolution { get; set; }
public float? Ratio { get; set; }
public float? TorqueRightLimit { get; set; }
public float? TorqueLeftLimit { get; set; }
/// <summary>
/// Ограничение числа оборотов вправо
/// </summary>
public float? RevolsRightLimit { get; set; }
/// <summary>
/// Ограничение числа оборотов влево
/// </summary>
public float? RevolsLeftLimit { get; set; }
/// <summary>
/// Заданная скорость вращения вправо
/// </summary>
public float? SpeedRightSp { get; set; }
/// <summary>
/// Заданная скорость вращения влево
/// </summary>
public float? SpeedLeftSp { get; set; }
/// <summary>
/// Суммарное количество оборотов вправо
/// </summary>
public float? RevolsRightTotal { get; set; }
/// <summary>
/// Суммарное количество оборотов влево
/// </summary>
public float? RevolsLeftTotal { get; set; }
public float? TurnRightOnceByTorque { get; set; }
public float? TurnLeftOnceByTorque { get; set; }
public float? TurnRightOnceByAngle { get; set; }
public float? TurnLeftOnceByAngle { get; set; }
public float? TurnRightOnceByRevols { get; set; }
public float? TurnLeftOnceByRevols { get; set; }
public float? BreakAngleK { get; set; }
public float? ReverseKTorque { get; set; }
/// <summary>
/// Нулевая позиция осцилляции
/// </summary>
public float? PositionZero { get; set; }
/// <summary>
/// Крайний правый угол осцилляции
/// </summary>
public float? PositionRight { get; set; }
public float? TorqueRampTime { get; set; }
public float? Ver { get; set; }
public short? ReverseSpeedSpZeroTime { get; set; }
public float? UnlockBySectorOut { get; set; }
public float? PidMuxTorqueLeftLimit { get; set; }
/// <summary>
/// Выбранный режим управления
/// </summary>
public short? Mode { get; set; }
/// <summary>
/// Переменная этапа
/// </summary>
public short? State { get; set; }
public float? BreakAngleLeft { get; set; }
}
#pragma warning restore CS1591 // Отсутствует комментарий XML для открытого видимого типа или члена
#nullable disable
}

View File

@ -0,0 +1,83 @@
using AsbCloudApp.Requests;
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
#nullable enable
/// <summary>
/// Сервис доступа к файлам
/// </summary>
public interface IFileRepository : ICrudService<FileInfoDto>
{
/// <summary>
/// Получение файлов по скважине
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<FileInfoDto>> GetInfosAsync(FileRequest request, CancellationToken token);
/// <summary>
/// Получить список файлов в контейнере
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<FileInfoDto>> GetInfosPaginatedAsync(FileRequest request, CancellationToken token = default);
/// <summary>
/// Пометить файл как удаленный
/// </summary>
/// <param name="idFile"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> MarkAsDeletedAsync(int idFile, CancellationToken token = default);
/// <summary>
/// удалить файлы
/// </summary>
/// <param name="ids"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token);
/// <summary>
/// получить инфо о файле по метке
/// </summary>
/// <param name="idMark"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token);
/// <summary>
/// добавить метку на файл
/// </summary>
/// <param name="fileMarkDto"></param>
/// <param name="idUser"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token);
/// <summary>
/// Инфо о файлах
/// </summary>
/// <param name="idsFile"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<FileInfoDto>> GetInfoByIdsAsync(IEnumerable<int> idsFile, CancellationToken token);
/// <summary>
/// пометить метки файлов как удаленные
/// </summary>
/// <param name="idsMarks"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> MarkFileMarkAsDeletedAsync(IEnumerable<int> idsMarks, CancellationToken token);
}
#nullable disable
}

View File

@ -0,0 +1,80 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Repositories
{
#nullable enable
/// <summary>
/// Репозиторий хранения фалов
/// </summary>
public interface IFileStorageRepository
{
/// <summary>
/// Получение длинны фала и проверка его наличия, если отсутствует падает исключение
/// </summary>
/// <param name="srcFilePath"></param>
/// <returns></returns>
long GetFileLength(string srcFilePath);
/// <summary>
/// Перемещение файла
/// </summary>
/// <param name="srcFilePath"></param>
/// <param name="filePath"></param>
void MoveFile(string srcFilePath, string filePath);
/// <summary>
/// Копирование файла
/// </summary>
/// <param name="filePathRec"></param>
/// <param name="fileStreamSrc"></param>
/// <param name="token"></param>
/// <returns></returns>
Task SaveFileAsync(string filePathRec, Stream fileStreamSrc, CancellationToken token);
/// <summary>
/// Удаление файла
/// </summary>
/// <param name="filesName"></param>
void DeleteFile(IEnumerable<string> filesName);
/// <summary>
/// Удаление всех файлов с диска о которых нет информации в базе
/// </summary>
/// <param name="idWell"></param>
/// <param name="idsFiles"></param>
int DeleteFilesNotInList(int idWell, IEnumerable<int> idsFiles);
/// <summary>
/// Вывод списка всех файлов из базы, для которых нет файла на диске
/// </summary>
/// <param name="idWell"></param>
/// <param name="files"></param>
/// <returns></returns>
IEnumerable<FileInfoDto> GetListFilesNotDisc(IEnumerable<FileInfoDto> files);
/// <summary>
/// Получение пути к файлу
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="fileFullName"></param>
/// <param name="fileId"></param>
/// <returns></returns>
string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId);
/// <summary>
/// Получить путь для скачивания
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="idFile"></param>
/// <param name="dotExtention"></param>
/// <returns></returns>
string GetUrl(int idWell, int idCategory, int idFile, string dotExtention);
}
#nullable disable
}

View File

@ -0,0 +1,50 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests
{
#nullable enable
/// <summary>
/// Параметры запроса для файлового сервиса
/// </summary>
public class FileRequest : RequestBase
{
/// <summary>
/// Идентификатор скважины
/// </summary>
[Required]
public int IdWell { get; set; }
/// <summary>
/// Идентификатор категории файла
/// </summary>
[Required]
public int? IdCategory { get; set; }
/// <summary>
/// Наименование компании
/// </summary>
public string? CompanyNamePart { get; set; }
/// <summary>
/// Имя файла
/// </summary>
public string? FileNamePart { get; set; }
/// <summary>
/// Дата начала периода
/// </summary>
public DateTime? Begin { get; set; }
/// <summary>
/// Дата окончания периода
/// </summary>
public DateTime? End { get; set; }
/// <summary>
/// Признак удаления
/// </summary>
public bool? IsDeleted { get; set; }
}
#nullable disable
}

View File

@ -0,0 +1,312 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
#nullable enable
/// <summary>
/// Сервис доступа к файлам
/// </summary>
public class FileService
{
private readonly IFileRepository fileRepository;
private readonly IFileStorageRepository fileStorageRepository;
/// <summary>
/// Сервис доступа к файлам
/// </summary>
/// <param name="fileRepository"></param>
/// <param name="fileStorageRepository"></param>
public FileService(IFileRepository fileRepository, IFileStorageRepository fileStorageRepository)
{
this.fileRepository = fileRepository;
this.fileStorageRepository = fileStorageRepository;
}
/// <summary>
/// переместить файл
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="idCategory"></param>
/// <param name="destinationFileName"></param>
/// <param name="srcFilePath"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<FileInfoDto?> MoveAsync(int idWell, int? idUser, int idCategory,
string destinationFileName, string srcFilePath, CancellationToken token = default)
{
destinationFileName = Path.GetFileName(destinationFileName);
srcFilePath = Path.GetFullPath(srcFilePath);
var fileSize = fileStorageRepository.GetFileLength(srcFilePath);
//save info to db
var dto = new FileInfoDto {
IdWell = idWell,
IdAuthor = idUser,
IdCategory = idCategory,
Name = destinationFileName,
Size = fileSize
};
var fileId = await fileRepository.InsertAsync(dto, token)
.ConfigureAwait(false);
string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, destinationFileName, fileId);
fileStorageRepository.MoveFile(srcFilePath, filePath);
return await GetOrDefaultAsync(fileId, token);
}
/// <summary>
/// Сохранить файл
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="idCategory"></param>
/// <param name="fileFullName"></param>
/// <param name="fileStream"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<FileInfoDto?> SaveAsync(int idWell, int? idUser, int idCategory,
string fileFullName, Stream fileStream, CancellationToken token)
{
//save info to db
var dto = new FileInfoDto
{
IdWell = idWell,
IdAuthor = idUser,
IdCategory = idCategory,
Name = Path.GetFileName(fileFullName),
Size = fileStream.Length
};
var fileId = await fileRepository.InsertAsync(dto, token)
.ConfigureAwait(false);
//save stream to disk
string filePath = fileStorageRepository.MakeFilePath(idWell, idCategory, fileFullName, fileId);
await fileStorageRepository.SaveFileAsync(filePath, fileStream, token);
return await GetOrDefaultAsync(fileId, token);
}
/// <summary>
/// удалить файл
/// </summary>
/// <param name="idFile"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<int> DeleteAsync(int idFile, CancellationToken token)
=> DeleteAsync(new int[] { idFile }, token);
/// <summary>
/// удалить файлы
/// </summary>
/// <param name="ids"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
{
if (ids is null || !ids.Any())
return 0;
var files = await fileRepository.DeleteAsync(ids, token).ConfigureAwait(false);
if (files is null || !files.Any())
return 0;
var filesName = files.Select(x => GetUrl(x.IdWell, x.IdCategory, x.Id, Path.GetExtension(x.Name)));
fileStorageRepository.DeleteFile(filesName);
return files.Any() ? 1 : 0;
}
/// <summary>
/// получить путь для скачивания
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
public string GetUrl(FileInfoDto fileInfo) =>
GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
/// <summary>
/// получить путь для скачивания
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="idFile"></param>
/// <param name="dotExtention"></param>
/// <returns></returns>
public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) =>
fileStorageRepository.GetUrl(idWell, idCategory, idFile, dotExtention);
/// <summary>
/// пометить метку файла как удаленную
/// </summary>
/// <param name="idMark"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<int> MarkFileMarkAsDeletedAsync(int idMark,
CancellationToken token)
=> fileRepository.MarkFileMarkAsDeletedAsync(new int[] { idMark }, token);
/// <summary>
/// Инфо о файле
/// </summary>
/// <param name="idsFile"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<IEnumerable<FileInfoDto>> GetInfoByIdsAsync(IEnumerable<int> idsFile, CancellationToken token)
{
var result = await fileRepository.GetInfoByIdsAsync(idsFile, token).ConfigureAwait(false);
foreach (var entity in result)
{
var ext = Path.GetExtension(entity.Name);
var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext);
var fullPath = Path.GetFullPath(relativePath);
}
return result;
}
/// <summary>
/// Получить файлы определенной категории
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<IEnumerable<FileInfoDto>> GetInfosAsync(FileRequest request, CancellationToken token)
=> fileRepository.GetInfosAsync(request, token);
/// <summary>
/// Получить список файлов в контейнере
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<PaginationContainer<FileInfoDto>> GetInfosPaginatedAsync(FileRequest request, CancellationToken token)
=> fileRepository.GetInfosPaginatedAsync(request, token);
/// <summary>
/// Пометить файл как удаленный
/// </summary>
/// <param name="idFile"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<int> MarkAsDeletedAsync(int idFile, CancellationToken token = default)
=> fileRepository.MarkAsDeletedAsync(idFile, token);
/// <summary>
/// добавить метку на файл
/// </summary>
/// <param name="fileMarkDto"></param>
/// <param name="idUser"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<int> CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token)
=> fileRepository.CreateFileMarkAsync(fileMarkDto, idUser, token);
/// <summary>
/// Получить запись по id
/// </summary>
/// <param name="id"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<FileInfoDto?> GetOrDefaultAsync(int id, CancellationToken token)
=> fileRepository.GetOrDefaultAsync(id, token);
/// <summary>
/// получить инфо о файле по метке
/// </summary>
/// <param name="idMark"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token)
=> fileRepository.GetByMarkId(idMark, token);
/// <summary>
/// получить инфо о файле по метке
/// </summary>
/// <param name="idsMarks"></param>
/// <param name="token"></param>
/// <returns></returns>
public Task<int> MarkFileMarkAsDeletedAsync(IEnumerable<int> idsMarks, CancellationToken token)
=> fileRepository.MarkFileMarkAsDeletedAsync(idsMarks, token);
/// <summary>
/// Удаление всех файлов по скважине помеченных как удаленные
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<int> DeleteFilesFromDbMarkedDeletionByIdWell(int idWell, CancellationToken token)
{
var files = await fileRepository.GetInfosAsync(
new FileRequest
{
IdWell = idWell,
IsDeleted = true
},
token);
var result = await DeleteAsync(files.Select(x => x.Id), token);
return result;
}
/// <summary>
/// Удаление всех файлов с диска о которых нет информации в базе
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
public async Task<int> DeleteFilesNotExistStorage(int idWell, CancellationToken token)
{
var files = await fileRepository.GetInfosAsync(
new FileRequest
{
IdWell = idWell
},
token);
var result = await Task.FromResult(fileStorageRepository.DeleteFilesNotInList(idWell, files.Select(x => x.Id)));
return result;
}
/// <summary>
/// Вывод списка всех файлов из базы, для которых нет файла на диске
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<IEnumerable<FileInfoDto>> GetListFilesNotDisc(int idWell, CancellationToken token)
{
var files = await fileRepository.GetInfosAsync(
new FileRequest
{
IdWell = idWell
},
token);
var result = fileStorageRepository.GetListFilesNotDisc(files);
return result;
}
/// <summary>
/// Получить файловый поток по идентификатору файла
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
public Stream GetFileStream(FileInfoDto fileInfo)
{
var relativePath = GetUrl(fileInfo);
var fileStream = new FileStream(Path.GetFullPath(relativePath), FileMode.Open);
return fileStream;
}
}
#nullable disable
}

View File

@ -1,179 +0,0 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
//TODO: refactor IFileService
/// <summary>
/// Сервис доступа к файлам
/// </summary>
public interface IFileService
{
/// <summary>
/// Директория хранения файлов
/// </summary>
string RootPath { get; }
/// <summary>
/// Сохранить файл
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="idCategory"></param>
/// <param name="fileFullName"></param>
/// <param name="fileStream"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<FileInfoDto> SaveAsync(int idWell, int? idUser, int idCategory, string fileFullName, Stream fileStream, CancellationToken token = default);
/// <summary>
/// Получить список файлов в контейнере
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="companyName"></param>
/// <param name="fileName"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<PaginationContainer<FileInfoDto>> GetInfosAsync(int idWell,
int idCategory, string companyName = default, string fileName = default, DateTime begin = default, DateTime end = default,
int skip = 0, int take = 32, CancellationToken token = default);
/// <summary>
/// Инфо о файле
/// </summary>
/// <param name="idFile"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<FileInfoDto> GetInfoAsync(int idFile,
CancellationToken token);
/// <summary>
/// Пометить файл как удаленный
/// </summary>
/// <param name="idFile"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> MarkAsDeletedAsync(int idFile,
CancellationToken token = default);
/// <summary>
/// Получить файлы определенной категории
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<FileInfoDto>> GetInfosByCategoryAsync(int idWell, int idCategory, CancellationToken token = default);
/// <summary>
/// удалить файл
/// </summary>
/// <param name="id"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAsync(int id, CancellationToken token);
/// <summary>
/// удалить файлы
/// </summary>
/// <param name="ids"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token);
/// <summary>
/// получить путь для скачивания
/// </summary>
/// <param name="fileInfo"></param>
/// <returns></returns>
string GetUrl(FileInfoDto fileInfo);
/// <summary>
/// получить путь для скачивания
/// </summary>
/// <param name="idFile"></param>
/// <returns></returns>
string GetUrl(int idFile);
/// <summary>
/// получить путь для скачивания
/// </summary>
/// <param name="idWell"></param>
/// <param name="idCategory"></param>
/// <param name="idFile"></param>
/// <param name="dotExtention"></param>
/// <returns></returns>
string GetUrl(int idWell, int idCategory, int idFile, string dotExtention);
/// <summary>
/// добавить метку на файл
/// </summary>
/// <param name="fileMarkDto"></param>
/// <param name="idUser"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token);
/// <summary>
/// пометить метку файла как удаленную
/// </summary>
/// <param name="idMark"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> MarkFileMarkAsDeletedAsync(int idMark, CancellationToken token);
/// <summary>
/// переместить файл
/// </summary>
/// <param name="idWell"></param>
/// <param name="idUser"></param>
/// <param name="idCategory"></param>
/// <param name="destinationFileName"></param>
/// <param name="srcFileFullName"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<FileInfoDto> MoveAsync(int idWell, int? idUser, int idCategory, string destinationFileName, string srcFileFullName, CancellationToken token = default);
/// <summary>
/// получить инфо о файле по метке
/// </summary>
/// <param name="idMark"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token);
/// <summary>
/// пометить метки файлов как удаленные
/// </summary>
/// <param name="idsMarks"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> MarkFileMarkAsDeletedAsync(IEnumerable<int> idsMarks, CancellationToken token);
/// <summary>
/// Инфо о файле
/// </summary>
/// <param name="idsFile"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<List<FileInfoDto>> GetInfoByIdsAsync(List<int> idsFile, CancellationToken token);
/// <summary>
/// Получение файлов по скважине
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<FileInfoDto>> GetInfosByWellIdAsync(int idWell, CancellationToken token);
}
}

View File

@ -0,0 +1,43 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
namespace AsbCloudApp.Services
{
#nullable enable
/// <summary>
/// Делегат обновления состояния задачи
/// </summary>
/// <param name="job"></param>
public delegate void OnJobProgressDelagate(JobDto job);
/// <summary>
/// Сервис прореживания архива БД.
/// Удаляет часть телеметрии.
/// Понижает частоту записей в БД с 1 запись за 1 сек до 1 запись за N сек.
/// </summary>
public interface IReduceSamplingService
{
/// <summary>
/// Получить все задания. Задания удаляются минимум через 10 сек после выполнения, возможно позднее.
/// </summary>
/// <returns>Enumerable of JobDto or empty</returns>
IEnumerable<JobDto> GetJobs();
/// <summary>
/// Получить состояние определенной задачи
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
JobDto? GetOrDefaultState(int idTelemetry);
/// <summary>
/// Создать задачу прореживанию архива и добавить её в очередь на выполнение
/// </summary>
/// <param name="idTelemetry">телеметрия для прореживания</param>
/// <param name="onProgress">колбек процесса выполнения</param>
/// <param name="jobDto">созданная задача или задача из очереди</param>
/// <returns>задача добавлена == true</returns>
bool TryEnqueueRediceSamplingJob(int idTelemetry, OnJobProgressDelagate onProgress, out JobDto jobDto);
}
#nullable disable
}

View File

@ -69,6 +69,15 @@ namespace AsbCloudDb
return database.ExecuteSqlRawAsync(query, token);
}
public static Task<int> ExecInsertAsync<T>(this Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade database, DbSet<T> dbSet, IEnumerable<T> items, CancellationToken token)
where T : class
{
var factory = GetQueryStringFactory(dbSet);
var query = factory.MakeInsertSql(items);
return database.ExecuteSqlRawAsync(query, token);
}
public static string GetTableName<T>(this DbSet<T> dbSet)
where T : class
{
@ -108,6 +117,17 @@ namespace AsbCloudDb
}
return stat;
}
public static IQueryable<T> SkipTake<T>(this IQueryable<T> query, int? skip, int? take)
{
if (skip > 0)
query = query.Skip((int)skip);
if (take > 0)
query = query.Take((int)take);
return query;
}
}
interface IQueryStringFactory { }
@ -154,6 +174,14 @@ namespace AsbCloudDb
return builder.ToString();
}
public string MakeInsertSql(IEnumerable<T> items)
{
var builder = new StringBuilder(insertHeader, 7);
BuildRows(builder, items);
builder.Append(';');
return builder.ToString();
}
private StringBuilder BuildRows(StringBuilder builder, IEnumerable<T> items)
{
var list = items.ToList();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,577 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Delete_colums_table_t_telemetry_data_spin : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "break_angle_k",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "break_angle_left",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "encoder_resolution",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "pid_mux_torque_left_limit",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "ratio",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "reverse_k_torque",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "reverse_speed_sp_zero_time",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "rotor_torque_avg",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_from",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_from_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_from_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_from_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_from_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_to",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_to_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_to_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_to_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_speed_sp_to_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_from",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_from_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_from_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_from_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_from_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_to",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_to_err",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_to_max",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_to_min",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "top_drive_torque_sp_to_offset",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "torque_left_limit",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "torque_ramp_time",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "torque_right_limit",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "torque_starting",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_left_once_by_angle",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_left_once_by_revols",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_left_once_by_torque",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_right_once_by_angle",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_right_once_by_revols",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "turn_right_once_by_torque",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "unlock_by_sector_out",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "ver",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "w2800",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "w2808",
table: "t_telemetry_data_spin");
migrationBuilder.DropColumn(
name: "w2810",
table: "t_telemetry_data_spin");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<float>(
name: "break_angle_k",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Коэффициент для расчёта за какой угол нужно тормозить");
migrationBuilder.AddColumn<float>(
name: "break_angle_left",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Угол торможения влево при работе по моменту");
migrationBuilder.AddColumn<float>(
name: "encoder_resolution",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Разрешение энкодера");
migrationBuilder.AddColumn<float>(
name: "pid_mux_torque_left_limit",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: " Момент при котором определяется ехать назад по моменту или по скорости");
migrationBuilder.AddColumn<float>(
name: "ratio",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: " Коэффициент редукции редуктора");
migrationBuilder.AddColumn<float>(
name: "reverse_k_torque",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Коэффициент на который умножается момент, для того чтобы система поняла что мы движемся в обратную сторону");
migrationBuilder.AddColumn<short>(
name: "reverse_speed_sp_zero_time",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true,
comment: "Время выдачи сигнала нулевой скорости на при смене направления");
migrationBuilder.AddColumn<float>(
name: "rotor_torque_avg",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Момент в роторе средний");
migrationBuilder.AddColumn<float>(
name: "top_drive_speed",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Скорость СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_speed_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "верхний предел");
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "нижний предел");
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "смещение");
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_from",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Заданная скорость c СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_speed_sp_from_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_from_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_from_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_from_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_to",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Задание скорости на СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_speed_sp_to_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_to_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_to_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_speed_sp_to_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Момент СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_torque_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_from",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Заданный момент c СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_torque_sp_from_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_from_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_from_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_from_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_to",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Задание момента на СВП");
migrationBuilder.AddColumn<short>(
name: "top_drive_torque_sp_to_err",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_to_max",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_to_min",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "top_drive_torque_sp_to_offset",
table: "t_telemetry_data_spin",
type: "real",
nullable: true);
migrationBuilder.AddColumn<float>(
name: "torque_left_limit",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Ограничение крутящего момента влево");
migrationBuilder.AddColumn<float>(
name: "torque_ramp_time",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Время нарастания момента");
migrationBuilder.AddColumn<float>(
name: "torque_right_limit",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Ограничение крутящего момента вправо");
migrationBuilder.AddColumn<float>(
name: "torque_starting",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Страгивающий момент");
migrationBuilder.AddColumn<float>(
name: "turn_left_once_by_angle",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по градусам единожды влево");
migrationBuilder.AddColumn<float>(
name: "turn_left_once_by_revols",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по оборотам единожды влево");
migrationBuilder.AddColumn<float>(
name: "turn_left_once_by_torque",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по моменту единожды влево");
migrationBuilder.AddColumn<float>(
name: "turn_right_once_by_angle",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по градусам единожды вправо");
migrationBuilder.AddColumn<float>(
name: "turn_right_once_by_revols",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по оборотам единожды вправо");
migrationBuilder.AddColumn<float>(
name: "turn_right_once_by_torque",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Доворот по моменту единожды вправо");
migrationBuilder.AddColumn<float>(
name: "unlock_by_sector_out",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: " Градус отклонения от сектора для автоматического сброса блокировки");
migrationBuilder.AddColumn<float>(
name: "ver",
table: "t_telemetry_data_spin",
type: "real",
nullable: true,
comment: "Версия ПО ПЛК");
migrationBuilder.AddColumn<short>(
name: "w2800",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true,
comment: "Установка нуля энкодера");
migrationBuilder.AddColumn<short>(
name: "w2808",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true,
comment: "Неисправность энкодера");
migrationBuilder.AddColumn<short>(
name: "w2810",
table: "t_telemetry_data_spin",
type: "smallint",
nullable: true,
comment: " автоматический сброс блокировки");
}
}
}

View File

@ -3435,31 +3435,11 @@ namespace AsbCloudDb.Migrations
.HasColumnName("date")
.HasComment("'2021-10-19 18:23:54+05'");
b.Property<float?>("BreakAngleK")
.HasColumnType("real")
.HasColumnName("break_angle_k")
.HasComment("Коэффициент для расчёта за какой угол нужно тормозить");
b.Property<float?>("BreakAngleLeft")
.HasColumnType("real")
.HasColumnName("break_angle_left")
.HasComment("Угол торможения влево при работе по моменту");
b.Property<float?>("EncoderResolution")
.HasColumnType("real")
.HasColumnName("encoder_resolution")
.HasComment("Разрешение энкодера");
b.Property<short?>("Mode")
.HasColumnType("smallint")
.HasColumnName("mode")
.HasComment("Выбранный режим управления");
b.Property<float?>("PidMuxTorqueLeftLimit")
.HasColumnType("real")
.HasColumnName("pid_mux_torque_left_limit")
.HasComment(" Момент при котором определяется ехать назад по моменту или по скорости");
b.Property<float?>("PositionRight")
.HasColumnType("real")
.HasColumnName("position_right")
@ -3470,21 +3450,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("position_zero")
.HasComment("Нулевая позиция осцилляции");
b.Property<float?>("Ratio")
.HasColumnType("real")
.HasColumnName("ratio")
.HasComment(" Коэффициент редукции редуктора");
b.Property<float?>("ReverseKTorque")
.HasColumnType("real")
.HasColumnName("reverse_k_torque")
.HasComment("Коэффициент на который умножается момент, для того чтобы система поняла что мы движемся в обратную сторону");
b.Property<short?>("ReverseSpeedSpZeroTime")
.HasColumnType("smallint")
.HasColumnName("reverse_speed_sp_zero_time")
.HasComment("Время выдачи сигнала нулевой скорости на при смене направления");
b.Property<float?>("RevolsLeftLimit")
.HasColumnType("real")
.HasColumnName("revols_left_limit")
@ -3505,11 +3470,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("revols_right_total")
.HasComment("Суммарное количество оборотов вправо");
b.Property<float?>("RotorTorqueAvg")
.HasColumnType("real")
.HasColumnName("rotor_torque_avg")
.HasComment("Момент в роторе средний");
b.Property<float?>("SpeedLeftSp")
.HasColumnType("real")
.HasColumnName("speed_left_sp")
@ -3525,210 +3485,6 @@ namespace AsbCloudDb.Migrations
.HasColumnName("state")
.HasComment("Переменная этапа");
b.Property<float?>("TopDriveSpeed")
.HasColumnType("real")
.HasColumnName("top_drive_speed")
.HasComment("Скорость СВП");
b.Property<short?>("TopDriveSpeedErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_speed_err");
b.Property<float?>("TopDriveSpeedMax")
.HasColumnType("real")
.HasColumnName("top_drive_speed_max")
.HasComment("верхний предел");
b.Property<float?>("TopDriveSpeedMin")
.HasColumnType("real")
.HasColumnName("top_drive_speed_min")
.HasComment("нижний предел");
b.Property<float?>("TopDriveSpeedOffset")
.HasColumnType("real")
.HasColumnName("top_drive_speed_offset")
.HasComment("смещение");
b.Property<float?>("TopDriveSpeedSpFrom")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_from")
.HasComment("Заданная скорость c СВП");
b.Property<short?>("TopDriveSpeedSpFromErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_speed_sp_from_err");
b.Property<float?>("TopDriveSpeedSpFromMax")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_from_max");
b.Property<float?>("TopDriveSpeedSpFromMin")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_from_min");
b.Property<float?>("TopDriveSpeedSpFromOffset")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_from_offset");
b.Property<float?>("TopDriveSpeedSpTo")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_to")
.HasComment("Задание скорости на СВП");
b.Property<short?>("TopDriveSpeedSpToErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_speed_sp_to_err");
b.Property<float?>("TopDriveSpeedSpToMax")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_to_max");
b.Property<float?>("TopDriveSpeedSpToMin")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_to_min");
b.Property<float?>("TopDriveSpeedSpToOffset")
.HasColumnType("real")
.HasColumnName("top_drive_speed_sp_to_offset");
b.Property<float?>("TopDriveTorque")
.HasColumnType("real")
.HasColumnName("top_drive_torque")
.HasComment("Момент СВП");
b.Property<short?>("TopDriveTorqueErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_torque_err");
b.Property<float?>("TopDriveTorqueMax")
.HasColumnType("real")
.HasColumnName("top_drive_torque_max");
b.Property<float?>("TopDriveTorqueMin")
.HasColumnType("real")
.HasColumnName("top_drive_torque_min");
b.Property<float?>("TopDriveTorqueOffset")
.HasColumnType("real")
.HasColumnName("top_drive_torque_offset");
b.Property<float?>("TopDriveTorqueSpFrom")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_from")
.HasComment("Заданный момент c СВП");
b.Property<short?>("TopDriveTorqueSpFromErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_torque_sp_from_err");
b.Property<float?>("TopDriveTorqueSpFromMax")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_from_max");
b.Property<float?>("TopDriveTorqueSpFromMin")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_from_min");
b.Property<float?>("TopDriveTorqueSpFromOffset")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_from_offset");
b.Property<float?>("TopDriveTorqueSpTo")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_to")
.HasComment("Задание момента на СВП");
b.Property<short?>("TopDriveTorqueSpToErr")
.HasColumnType("smallint")
.HasColumnName("top_drive_torque_sp_to_err");
b.Property<float?>("TopDriveTorqueSpToMax")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_to_max");
b.Property<float?>("TopDriveTorqueSpToMin")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_to_min");
b.Property<float?>("TopDriveTorqueSpToOffset")
.HasColumnType("real")
.HasColumnName("top_drive_torque_sp_to_offset");
b.Property<float?>("TorqueLeftLimit")
.HasColumnType("real")
.HasColumnName("torque_left_limit")
.HasComment("Ограничение крутящего момента влево");
b.Property<float?>("TorqueRampTime")
.HasColumnType("real")
.HasColumnName("torque_ramp_time")
.HasComment("Время нарастания момента");
b.Property<float?>("TorqueRightLimit")
.HasColumnType("real")
.HasColumnName("torque_right_limit")
.HasComment("Ограничение крутящего момента вправо");
b.Property<float?>("TorqueStarting")
.HasColumnType("real")
.HasColumnName("torque_starting")
.HasComment("Страгивающий момент");
b.Property<float?>("TurnLeftOnceByAngle")
.HasColumnType("real")
.HasColumnName("turn_left_once_by_angle")
.HasComment("Доворот по градусам единожды влево");
b.Property<float?>("TurnLeftOnceByRevols")
.HasColumnType("real")
.HasColumnName("turn_left_once_by_revols")
.HasComment("Доворот по оборотам единожды влево");
b.Property<float?>("TurnLeftOnceByTorque")
.HasColumnType("real")
.HasColumnName("turn_left_once_by_torque")
.HasComment("Доворот по моменту единожды влево");
b.Property<float?>("TurnRightOnceByAngle")
.HasColumnType("real")
.HasColumnName("turn_right_once_by_angle")
.HasComment("Доворот по градусам единожды вправо");
b.Property<float?>("TurnRightOnceByRevols")
.HasColumnType("real")
.HasColumnName("turn_right_once_by_revols")
.HasComment("Доворот по оборотам единожды вправо");
b.Property<float?>("TurnRightOnceByTorque")
.HasColumnType("real")
.HasColumnName("turn_right_once_by_torque")
.HasComment("Доворот по моменту единожды вправо");
b.Property<float?>("UnlockBySectorOut")
.HasColumnType("real")
.HasColumnName("unlock_by_sector_out")
.HasComment(" Градус отклонения от сектора для автоматического сброса блокировки");
b.Property<float?>("Ver")
.HasColumnType("real")
.HasColumnName("ver")
.HasComment("Версия ПО ПЛК");
b.Property<short?>("W2800")
.HasColumnType("smallint")
.HasColumnName("w2800")
.HasComment("Установка нуля энкодера");
b.Property<short?>("W2808")
.HasColumnType("smallint")
.HasColumnName("w2808")
.HasComment("Неисправность энкодера");
b.Property<short?>("W2810")
.HasColumnType("smallint")
.HasColumnName("w2810")
.HasComment(" автоматический сброс блокировки");
b.HasKey("IdTelemetry", "DateTime");
b.ToTable("t_telemetry_data_spin");

View File

@ -11,135 +11,37 @@ namespace AsbCloudDb.Model
{
[Column("id_telemetry")]
public int IdTelemetry { get; set; }
[Column("date", TypeName = "timestamp with time zone"), Comment("'2021-10-19 18:23:54+05'")]
public DateTimeOffset DateTime { get; set; }
[Column("top_drive_speed"), Comment("Скорость СВП")]
public float? TopDriveSpeed { get; set; }
[Column("top_drive_speed_min"), Comment("нижний предел")]
public float? TopDriveSpeedMin { get; set; }
[Column("top_drive_speed_max"), Comment("верхний предел")]
public float? TopDriveSpeedMax { get; set; }
[Column("top_drive_speed_offset"), Comment("смещение")]
public float? TopDriveSpeedOffset { get; set; }
[Column("top_drive_torque"), Comment("Момент СВП")]
public float? TopDriveTorque { get; set; }
[Column("top_drive_torque_min")]
public float? TopDriveTorqueMin { get; set; }
[Column("top_drive_torque_max")]
public float? TopDriveTorqueMax { get; set; }
[Column("top_drive_torque_offset")]
public float? TopDriveTorqueOffset { get; set; }
[Column("top_drive_speed_sp_from"), Comment("Заданная скорость c СВП")]
public float? TopDriveSpeedSpFrom { get; set; }
[Column("top_drive_speed_sp_from_min")]
public float? TopDriveSpeedSpFromMin { get; set; }
[Column("top_drive_speed_sp_from_max")]
public float? TopDriveSpeedSpFromMax { get; set; }
[Column("top_drive_speed_sp_from_offset")]
public float? TopDriveSpeedSpFromOffset { get; set; }
[Column("top_drive_torque_sp_from"), Comment("Заданный момент c СВП")]
public float? TopDriveTorqueSpFrom { get; set; }
[Column("top_drive_torque_sp_from_min")]
public float? TopDriveTorqueSpFromMin { get; set; }
[Column("top_drive_torque_sp_from_max")]
public float? TopDriveTorqueSpFromMax { get; set; }
[Column("top_drive_torque_sp_from_offset")]
public float? TopDriveTorqueSpFromOffset { get; set; }
[Column("top_drive_speed_sp_to"), Comment("Задание скорости на СВП")]
public float? TopDriveSpeedSpTo { get; set; }
[Column("top_drive_speed_sp_to_min")]
public float? TopDriveSpeedSpToMin { get; set; }
[Column("top_drive_speed_sp_to_max")]
public float? TopDriveSpeedSpToMax { get; set; }
[Column("top_drive_speed_sp_to_offset")]
public float? TopDriveSpeedSpToOffset { get; set; }
[Column("top_drive_torque_sp_to"), Comment("Задание момента на СВП")]
public float? TopDriveTorqueSpTo { get; set; }
[Column("top_drive_torque_sp_to_min")]
public float? TopDriveTorqueSpToMin { get; set; }
[Column("top_drive_torque_sp_to_max")]
public float? TopDriveTorqueSpToMax { get; set; }
[Column("top_drive_torque_sp_to_offset")]
public float? TopDriveTorqueSpToOffset { get; set; }
[Column("torque_starting"), Comment("Страгивающий момент")]
public float? TorqueStarting { get; set; }
[Column("rotor_torque_avg"), Comment("Момент в роторе средний")]
public float? RotorTorqueAvg { get; set; }
[Column("encoder_resolution"), Comment("Разрешение энкодера")]
public float? EncoderResolution { get; set; }
[Column("ratio"), Comment(" Коэффициент редукции редуктора")]
public float? Ratio { get; set; }
[Column("torque_right_limit"), Comment("Ограничение крутящего момента вправо")]
public float? TorqueRightLimit { get; set; }
[Column("torque_left_limit"), Comment("Ограничение крутящего момента влево")]
public float? TorqueLeftLimit { get; set; }
[Column("revols_right_limit"), Comment("Ограничение числа оборотов вправо")]
public float? RevolsRightLimit { get; set; }
[Column("revols_left_limit"), Comment("Ограничение числа оборотов влево")]
public float? RevolsLeftLimit { get; set; }
[Column("speed_right_sp"), Comment("Заданная скорость вращения вправо")]
public float? SpeedRightSp { get; set; }
[Column("speed_left_sp"), Comment("Заданная скорость вращения влево")]
public float? SpeedLeftSp { get; set; }
[Column("revols_right_total"), Comment("Суммарное количество оборотов вправо")]
public float? RevolsRightTotal { get; set; }
[Column("revols_left_total"), Comment("Суммарное количество оборотов влево")]
public float? RevolsLeftTotal { get; set; }
[Column("turn_right_once_by_torque"), Comment("Доворот по моменту единожды вправо")]
public float? TurnRightOnceByTorque { get; set; }
[Column("turn_left_once_by_torque"), Comment("Доворот по моменту единожды влево")]
public float? TurnLeftOnceByTorque { get; set; }
[Column("turn_right_once_by_angle"), Comment("Доворот по градусам единожды вправо")]
public float? TurnRightOnceByAngle { get; set; }
[Column("turn_left_once_by_angle"), Comment("Доворот по градусам единожды влево")]
public float? TurnLeftOnceByAngle { get; set; }
[Column("turn_right_once_by_revols"), Comment("Доворот по оборотам единожды вправо")]
public float? TurnRightOnceByRevols { get; set; }
[Column("turn_left_once_by_revols"), Comment("Доворот по оборотам единожды влево")]
public float? TurnLeftOnceByRevols { get; set; }
[Column("break_angle_k"), Comment("Коэффициент для расчёта за какой угол нужно тормозить")]
public float? BreakAngleK { get; set; }
[Column("reverse_k_torque"), Comment("Коэффициент на который умножается момент, для того чтобы система поняла что мы движемся в обратную сторону")]
public float? ReverseKTorque { get; set; }
[Column("position_zero"), Comment("Нулевая позиция осцилляции")]
public float? PositionZero { get; set; }
[Column("position_right"), Comment("Крайний правый угол осцилляции")]
public float? PositionRight { get; set; }
[Column("torque_ramp_time"), Comment("Время нарастания момента")]
public float? TorqueRampTime { get; set; }
[Column("ver"), Comment("Версия ПО ПЛК")]
public float? Ver { get; set; }
[Column("unlock_by_sector_out"), Comment(" Градус отклонения от сектора для автоматического сброса блокировки")]
public float? UnlockBySectorOut { get; set; }
[Column("pid_mux_torque_left_limit"), Comment(" Момент при котором определяется ехать назад по моменту или по скорости")]
public float? PidMuxTorqueLeftLimit { get; set; }
[Column("break_angle_left"), Comment("Угол торможения влево при работе по моменту")]
public float? BreakAngleLeft { get; set; }
[Column("top_drive_speed_err")]
public short? TopDriveSpeedErr { get; set; }
[Column("top_drive_torque_err")]
public short? TopDriveTorqueErr { get; set; }
[Column("top_drive_speed_sp_from_err")]
public short? TopDriveSpeedSpFromErr { get; set; }
[Column("top_drive_torque_sp_from_err")]
public short? TopDriveTorqueSpFromErr { get; set; }
[Column("top_drive_speed_sp_to_err")]
public short? TopDriveSpeedSpToErr { get; set; }
[Column("top_drive_torque_sp_to_err")]
public short? TopDriveTorqueSpToErr { get; set; }
[Column("w2800"), Comment("Установка нуля энкодера")]
public short? W2800 { get; set; }
[Column("w2810"), Comment(" автоматический сброс блокировки")]
public short? W2810 { get; set; }
[Column("mode"), Comment("Выбранный режим управления")]
public short? Mode { get; set; }
[Column("w2808"), Comment("Неисправность энкодера")]
public short? W2808 { get; set; }
[Column("reverse_speed_sp_zero_time"), Comment("Время выдачи сигнала нулевой скорости на при смене направления")]
public short? ReverseSpeedSpZeroTime { get; set; }
[Column("state"), Comment("Переменная этапа")]
public short? State { get; set; }

View File

@ -1,6 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.Subsystems;
using AsbCloudDb.Model;
@ -82,8 +83,12 @@ namespace AsbCloudInfrastructure
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
MapsterSetup();
var connectionStringName = "DefaultConnection";
#if DEBUG
connectionStringName = "DebugConnection";
#endif
services.AddDbContext<AsbCloudDbContext>(options =>
options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")));
options.UseNpgsql(configuration.GetConnectionString(connectionStringName)));
services.AddFluentValidation();
@ -98,6 +103,7 @@ namespace AsbCloudInfrastructure
services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
services.AddSingleton<IBackgroundWorkerService, BackgroundWorkerService>();
services.AddSingleton<IReduceSamplingService>(provider => ReduceSamplingService.GetInstance(configuration));
services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IClusterService, ClusterService>();
@ -105,7 +111,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IDrillParamsService, DrillParamsService>();
services.AddTransient<IEventService, EventService>();
services.AddTransient<IFileService, FileService>();
services.AddTransient<FileService>();
services.AddTransient<IMeasureService, MeasureService>();
services.AddTransient<IMessageService, MessageService>();
services.AddTransient<IOperationsStatService, OperationsStatService>();
@ -154,6 +160,8 @@ namespace AsbCloudInfrastructure
dbSet => dbSet
.Include(c => c.Wells)
.Include(c => c.Deposit))); // может быть включен в сервис ClusterService
services.AddTransient<IFileRepository, FileRepository>();
services.AddTransient<IFileStorageRepository, FileStorageRepository>();
// Subsystem service
services.AddTransient<ICrudService<SubsystemDto>, CrudCacheServiceBase<SubsystemDto, Subsystem>>();
services.AddTransient<ISubsystemService, SubsystemService>();

View File

@ -0,0 +1,297 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Wordprocessing;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
#nullable enable
public class FileRepository : IFileRepository
{
private readonly IQueryable<FileInfo> dbSetConfigured;
private readonly IAsbCloudDbContext db;
public FileRepository(IAsbCloudDbContext db)
{
this.db = db;
this.dbSetConfigured = db.Files
.Include(f => f.Author)
.ThenInclude(u => u.Company)
.ThenInclude(c => c.CompanyType)
.Include(f => f.FileMarks)
.ThenInclude(m => m.User)
.Include(f => f.Well);
}
private IQueryable<FileInfo> BuildQuery(FileRequest request)
{
var query = dbSetConfigured
.Where(e => e.IdWell == request.IdWell);
double timezoneOffsetHours = query.FirstOrDefault()
?.Well.Timezone.Hours ?? 5d;
if (request.IdCategory is not null)
query = query.Where(x => x.IdCategory == request.IdCategory);
if (request.IsDeleted is not null)
query = query.Where(x => x.IsDeleted == request.IsDeleted);
if (request.CompanyNamePart is not null)
query = query.Where(e => e.Author.Company.Caption.ToLower().Contains(request.CompanyNamePart.ToLower()));
if (request.FileNamePart is not null)
query = query.Where(e => e.Name.ToLower().Contains(request.FileNamePart.ToLower()));
if (request.Begin is not null)
{
var beginUtc = request.Begin.Value.ToUtcDateTimeOffset(timezoneOffsetHours);
query = query.Where(e => e.UploadDate >= beginUtc);
}
if (request.End is not null)
{
var endUtc = request.End.Value.ToUtcDateTimeOffset(timezoneOffsetHours);
query = query.Where(e => e.UploadDate <= endUtc);
}
if (request?.SortFields?.Any() == true)
{
query = query.SortBy(request.SortFields);
}
else
query = query
.OrderBy(o => o.UploadDate);
return query;
}
public async Task<IEnumerable<FileInfoDto>> GetInfosAsync(FileRequest request, CancellationToken token)
{
var query = BuildQuery(request);
var entities = await query
.SkipTake(request.Skip, request.Take)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(e => Convert(e));
return dtos;
}
public async Task<PaginationContainer<FileInfoDto>> GetInfosPaginatedAsync(FileRequest request, CancellationToken token = default)
{
var skip = request.Skip ?? 0;
var take = request.Take ?? 32;
var query = BuildQuery(request);
var result = new PaginationContainer<FileInfoDto>()
{
Skip = skip,
Take = take,
Count = await query.CountAsync(token),
};
if (result.Count == 0)
return result;
var entities = await query
.SkipTake(skip, take)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
result.Items = entities.Select(e => Convert(e)).ToList();
return result;
}
public async Task<IEnumerable<FileInfoDto>> GetInfoByIdsAsync(IEnumerable<int> idsFile, CancellationToken token)
{
var result = Enumerable.Empty<FileInfoDto>();
var entities = await dbSetConfigured
.AsNoTracking()
.Where(f => idsFile.Contains(f.Id))
.ToListAsync(token)
.ConfigureAwait(false);
if (entities is not null)
result = entities.Select(entity => Convert(entity));
return result;
}
public async Task<int> MarkAsDeletedAsync(int idFile, CancellationToken token = default)
{
var fileInfo = await db.Files.FirstOrDefaultAsync(f => f.Id == idFile, token).ConfigureAwait(false);
if (fileInfo is null)
return 0;
fileInfo.IsDeleted = true;
return await db.SaveChangesAsync(token).ConfigureAwait(false);
}
public async Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
{
var query = dbSetConfigured
.Where(f => ids.Contains(f.Id) && f.IsDeleted);
var files = await query.ToListAsync(token);
var filesDtos = files.Select(x => Convert(x));
db.Files.RemoveRange(query);
await db.SaveChangesAsync(token).ConfigureAwait(false);
return filesDtos;
}
public async Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token)
{
var entity = await dbSetConfigured
.FirstOrDefaultAsync(f => f.FileMarks.Any(m => m.Id == idMark), token)
.ConfigureAwait(false);
FileInfoDto dto = Convert(entity!);
return dto;
}
public async Task<int> CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token)
{
var fileMark = await db.FileMarks
.FirstOrDefaultAsync(m => m.IdFile == fileMarkDto.IdFile &&
m.IdMarkType == fileMarkDto.IdMarkType &&
m.IdUser == idUser &&
m.IsDeleted == false,
token)
.ConfigureAwait(false);
if (fileMark is not null)
return 0;
var newFileMark = fileMarkDto.Adapt<FileMark>();
newFileMark.Id = default;
newFileMark.DateCreated = DateTime.UtcNow;
newFileMark.IdUser = idUser;
newFileMark.User = null;
db.FileMarks.Add(newFileMark);
return await db.SaveChangesAsync(token);
}
public async Task<int> MarkFileMarkAsDeletedAsync(IEnumerable<int> idsMarks, CancellationToken token)
{
var fileMarkQuery = db.FileMarks
.Where(m => idsMarks.Contains(m.Id));
foreach (var fileMark in fileMarkQuery)
fileMark.IsDeleted = true;
return await db.SaveChangesAsync(token);
}
public async Task<IEnumerable<FileInfoDto>> GetAllAsync(CancellationToken token)
=> await dbSetConfigured.AsNoTracking()
.Select(x => Convert(x))
.ToListAsync(token)
.ConfigureAwait(false);
public async Task<FileInfoDto?> GetOrDefaultAsync(int id, CancellationToken token)
{
var entity = await dbSetConfigured
.AsNoTracking()
.FirstOrDefaultAsync(f => f.Id == id, token)
.ConfigureAwait(false);
if (entity is null)
return null;
var dto = Convert(entity);
return dto;
}
public FileInfoDto? GetOrDefault(int id)
{
var entity = dbSetConfigured
.AsNoTracking()
.FirstOrDefault(f => f.Id == id);
if (entity is null)
return null;
var dto = Convert(entity);
return dto;
}
public async Task<int> InsertAsync(FileInfoDto newItem, CancellationToken token)
{
var fileInfo = new FileInfo()
{
IdWell = newItem.IdWell,
IdAuthor = newItem.IdAuthor,
IdCategory = newItem.IdCategory,
Name = newItem.Name,
UploadDate = DateTime.UtcNow,
IsDeleted = false,
Size = newItem.Size,
};
var entry = db.Files.Add(fileInfo);
await db.SaveChangesAsync(token).ConfigureAwait(false);
return entry.Entity.Id;
}
public Task<int> InsertRangeAsync(IEnumerable<FileInfoDto> newItems, CancellationToken token)
{
throw new NotImplementedException();
}
public Task<int> UpdateAsync(FileInfoDto item, CancellationToken token)
{
throw new NotImplementedException();
}
public Task<int> DeleteAsync(int id, CancellationToken token)
{
throw new NotImplementedException();
}
private static FileInfoDto Convert(FileInfo entity)
{
var timezoneOffset = entity.Well.Timezone?.Hours ?? 5;
return Convert(entity, timezoneOffset);
}
private static FileInfoDto Convert(FileInfo entity, double timezoneOffset)
{
var dto = entity.Adapt<FileInfoDto>();
dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset);
dto.FileMarks = entity.FileMarks.Select(m =>
{
var mark = m.Adapt<FileMarkDto>();
mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset);
return mark;
});
return dto;
}
}
#nullable disable
}

View File

@ -0,0 +1,121 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Repository
{
#nullable enable
public class FileStorageRepository : IFileStorageRepository
{
/// <summary>
/// Директория хранения файлов
/// </summary>
private readonly string RootPath = "files";
public FileStorageRepository()
{
}
public async Task SaveFileAsync(string filePathRec, Stream fileStreamSrc, CancellationToken token)
{
CreateDirectory(filePathRec);
using var newfileStream = new FileStream(filePathRec, FileMode.Create);
await fileStreamSrc.CopyToAsync(newfileStream, token).ConfigureAwait(false);
}
public void DeleteFile(IEnumerable<string> filesName)
{
foreach (var fileName in filesName)
{
if (File.Exists(fileName))
File.Delete(fileName);
}
}
public long GetFileLength(string srcFilePath)
{
var sysFileInfo = new FileInfo(srcFilePath);
return sysFileInfo.Length;
}
public void MoveFile(string srcFilePath, string filePath)
{
CreateDirectory(filePath);
File.Move(srcFilePath, filePath);
}
public string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId)
{
return Path.Combine(RootPath, $"{idWell}",
$"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}");
}
public int DeleteFilesNotInList(int idWell, IEnumerable<int> idsFilesList)
{
var allFilesPath = GetFilesPath(idWell);
var result = 0;
foreach (var filePath in allFilesPath)
{
if (int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile)
|| !idsFilesList.Any(x => x == idFile))
{
File.Delete(filePath);
result++;
}
}
return result;
}
public IEnumerable<FileInfoDto> GetListFilesNotDisc(IEnumerable<FileInfoDto> files)
{
var resutl = new List<FileInfoDto>();
var groupFiles = files.GroupBy(x => x.IdWell);
foreach (var itemGroupFiles in groupFiles)
{
var idsFilesStorage = GetIdsFiles(itemGroupFiles.Key);
foreach (var file in files)
{
if (!idsFilesStorage.Any(x => x == file.Id))
resutl.Add(file);
}
}
return resutl;
}
public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) =>
Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}");
private IEnumerable<int> GetIdsFiles(int idWell)
{
var result = new List<int>();
var allFilesPath = GetFilesPath(idWell);
foreach (var filePath in allFilesPath)
if(int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile))
result.Add(idFile);
return result;
}
private IEnumerable<string> GetFilesPath(int idWell)
{
var path = Path.Combine(RootPath, $"{idWell}");
return Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
}
private static void CreateDirectory(string filePath)
{
var directoryName = Path.GetDirectoryName(filePath)!;
Directory.CreateDirectory(directoryName);
}
}
#nullable disable
}

View File

@ -66,17 +66,33 @@ namespace AsbCloudInfrastructure.Repository
return new TDto[] { Convert(data, timezoneHours) };
}
public Task SaveDataAsync(int idTelemetry, IEnumerable<TDto> dtos, CancellationToken token)
public async Task SaveDataAsync(int idTelemetry, IEnumerable<TDto> dtos, CancellationToken token)
{
if (dtos?.Any() != true)
return Task.CompletedTask;
return;
var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours;
var entities = dtos
.DistinctBy(d => d.DateTime)
.Select(dto => Convert(dto, idTelemetry, timezoneHours));
dbset.AddRange(entities);
return db.SaveChangesAsync(token);
var dateMin = entities.Min(e => e.DateTime);
var dateMax = entities.Max(e => e.DateTime);
var existingEntities = await dbset
.Where(e => e.IdTelemetry == idTelemetry)
.Where(e => e.DateTime >= dateMin && e.DateTime <= dateMax)
.Select(e => new { e.DateTime, e.IdTelemetry})
.ToArrayAsync(token);
foreach (var entity in entities)
{
if (existingEntities.Any(e=>e.IdTelemetry == entity.IdTelemetry && e.DateTime == entity.DateTime))
dbset.Update(entity);
else
dbset.Add(entity);
}
await db.SaveChangesAsync(token);
}
private static TEntity Convert(TDto dto, int idTelemetry, double timezoneHours)

View File

@ -162,7 +162,7 @@ namespace AsbCloudInfrastructure.Services.DailyReport.DailyReportBlocks
sheet.Cell(AddressWatchData[1])
._SetValue($"{blockDto.WorkTimeSpinMaster}");
sheet.Cell(AddressMetreData[1])
._SetValue($"{blockDto.PenetrationTorkMaster}");
._SetValue($"{blockDto.PenetrationSpinMaster}");
sheet._Range(AddressWorkSaubData[2], AddressWorkSaubData[2] + (0, 2))
._SetValue("Торк Мастер (демпфирование), ч/:");
sheet.Cell(AddressWatchData[2])

View File

@ -44,7 +44,9 @@ namespace AsbCloudInfrastructure.Services.DailyReport
timeBalance.Draw(sheet);
blockDimensionless.Draw(sheet);
blockSaub.Draw(sheet);
blockSign.Draw(sheet);
blockSign.Draw(sheet);
//sheet.Columns().AdjustToContents(); // Adjust column width
sheet.Rows().AdjustToContents();
}
}
}

View File

@ -48,9 +48,10 @@ namespace AsbCloudInfrastructure.Services.DailyReport
public async Task<DailyReportDto> GetOrGenerateAsync(int idWell, DateTime date, CancellationToken token)
{
var dailyReportDto = await GetAsync(idWell, date, token);
var dateOnly = DateTime.SpecifyKind(date.Date, DateTimeKind.Utc);
var dailyReportDto = await GetAsync(idWell, dateOnly, token);
if (dailyReportDto is null)
dailyReportDto = await MakeDefaultDailyReportAsync(idWell, date, token);
dailyReportDto = await MakeDefaultDailyReportAsync(idWell, dateOnly, token);
return dailyReportDto;
}
@ -124,10 +125,27 @@ namespace AsbCloudInfrastructure.Services.DailyReport
ClusterName = well?.Cluster ?? "",
},
TimeBalance = await MakeTimeBalanceAsync(idWell, date, token),
Bha = await GetPrevOrNewBhaAsync(idWell, date, token)
};
return dto;
}
private async Task<BhaDto> GetPrevOrNewBhaAsync(int idWell, DateTime date, CancellationToken token)
{
var dateOffset = date.Date;
var entity = await db.DailyReports
.Where(x => x.IdWell == idWell)
.OrderByDescending(x => x.StartDate)
.FirstOrDefaultAsync(r => r.StartDate.Year <= dateOffset.Year &&
r.StartDate.DayOfYear <= dateOffset.DayOfYear, token);
if (entity is null)
return new BhaDto();
var dto = Convert(entity);
return dto.Bha;
}
private async Task<TimeBalanceDto> MakeTimeBalanceAsync(int idWell, DateTime date, CancellationToken token)
{
var stat = await detectedOperationService.GetOperationsStatAsync(new DetectedOperationRequest

View File

@ -10,12 +10,12 @@ namespace AsbCloudInfrastructure.Services.DailyReport
var mergedRange = range.Merge();
mergedRange.FirstCell()._SetValue(value);
var colWidth = mergedRange.FirstCell().WorksheetColumn().Width;
var maxCharsToWrap = colWidth / (0.05d * mergedRange.FirstCell().Style.Font.FontSize);
var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize);
if (value is string valueString && valueString.Length > maxCharsToWrap)
{
var row = mergedRange.FirstCell().WorksheetRow();
var baseHeight = row.Height;
row.Height = 0.45d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap);
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap);
}
mergedRange.Style.SetAllBorders()
.Alignment.SetWrapText(true);
@ -59,7 +59,7 @@ namespace AsbCloudInfrastructure.Services.DailyReport
{
var row = cell.WorksheetRow();
var baseHeight = row.Height;
row.Height = 0.52d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
}
}
@ -80,7 +80,7 @@ namespace AsbCloudInfrastructure.Services.DailyReport
{
var row = cell.WorksheetRow();
var baseHeight = row.Height;
row.Height = 0.52d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
}
}

View File

@ -11,6 +11,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
#nullable enable
public class DrillParamsService : CrudServiceBase<DrillParamsDto, DrillParams>, IDrillParamsService
{
private readonly IAsbCloudDbContext db;
@ -23,7 +24,7 @@ namespace AsbCloudInfrastructure.Services
this.telemetryService = telemetryService;
}
public async Task<DrillParamsDto> GetDefaultDrillParamsAsync(int idWell,
public async Task<DrillParamsDto?> GetDefaultDrillParamsAsync(int idWell,
double startDepth, double endDepth, CancellationToken token = default)
{
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell);
@ -39,28 +40,46 @@ namespace AsbCloudInfrastructure.Services
select new DrillParamsDto()
{
IdWell = idWell,
DepthStart = startDepth,
DepthEnd = endDepth,
Depth = new MinMaxDto<double>
{
Min = endDepth,
Max = startDepth
},
IdWellSectionType = 0,
AxialLoadMin = g.Min(t => t.AxialLoad) ?? double.NaN,
AxialLoadAvg = g.Average(t => t.AxialLoad) ?? double.NaN,
AxialLoadMax = g.Max(t => t.AxialLoad) ?? double.NaN,
PressureMin = g.Min(t => t.Pressure) ?? double.NaN,
PressureAvg = g.Average(t => t.Pressure) ?? double.NaN,
PressureMax = g.Max(t => t.Pressure) ?? double.NaN,
RotorTorqueMin = g.Min(t => t.RotorTorque) ?? double.NaN,
RotorTorqueAvg = g.Average(t => t.RotorTorque) ?? double.NaN,
RotorTorqueMax = g.Max(t => t.RotorTorque) ?? double.NaN,
RotorSpeedMin = g.Min(t => t.RotorSpeed) ?? double.NaN,
RotorSpeedAvg = g.Average(t => t.RotorSpeed) ?? double.NaN,
RotorSpeedMax = g.Max(t => t.RotorSpeed) ?? double.NaN,
FlowMin = g.Min(t => t.Flow) ?? double.NaN,
FlowAvg = g.Min(t => t.Flow) ?? double.NaN,
FlowMax = g.Min(t => t.Flow) ?? double.NaN
AxialLoad = new MinMaxExtendedViewDto
{
Min = g.Min(t => t.AxialLoad) ?? double.NaN,
Avg = g.Average(t => t.AxialLoad) ?? double.NaN,
Max = g.Max(t => t.AxialLoad) ?? double.NaN
},
Pressure = new MinMaxExtendedViewDto
{
Min = g.Min(t => t.Pressure) ?? double.NaN,
Avg = g.Average(t => t.Pressure) ?? double.NaN,
Max = g.Max(t => t.Pressure) ?? double.NaN
},
RotorTorque = new MinMaxExtendedViewDto
{
Min = g.Min(t => t.RotorTorque) ?? double.NaN,
Avg = g.Average(t => t.RotorTorque) ?? double.NaN,
Max = g.Max(t => t.RotorTorque) ?? double.NaN
},
RotorSpeed = new MinMaxExtendedViewDto
{
Min = g.Min(t => t.RotorSpeed) ?? double.NaN,
Avg = g.Average(t => t.RotorSpeed) ?? double.NaN,
Max = g.Max(t => t.RotorSpeed) ?? double.NaN
},
Flow = new MinMaxExtendedViewDto
{
Min = g.Min(t => t.Flow) ?? double.NaN,
Avg = g.Min(t => t.Flow) ?? double.NaN,
Max = g.Min(t => t.Flow) ?? double.NaN
}
})
.AsNoTracking()
.DefaultIfEmpty()
.OrderBy(t => t.AxialLoadMin)
.OrderBy(t => t.AxialLoad.Min)
.FirstOrDefaultAsync(token)
.ConfigureAwait(false);
@ -70,35 +89,62 @@ namespace AsbCloudInfrastructure.Services
public async Task<IEnumerable<DrillParamsDto>> GetAllAsync(int idWell,
CancellationToken token = default)
{
var entities = await (from p in db.DrillParams
where p.IdWell == idWell
orderby p.Id
select p)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var entities = await db.DrillParams
.Where(p => p.IdWell == idWell)
.OrderBy(p=> p.Id)
.AsNoTracking()
.ToArrayAsync(token)
.ConfigureAwait(false);
var dto = entities.Adapt<IEnumerable<DrillParamsDto>>();
return dto;
var dtos = entities.Select(p =>
{
var dto = new DrillParamsDto
{
IdWell = p.IdWell,
Id = p.Id,
IdWellSectionType = p.IdWellSectionType,
Depth = new MinMaxDto<double> { Max = p.PressureMax, Min = p.PressureMin },
Pressure = MakeMinMaxExtended(p.PressureAvg, p.PressureMax, p.PressureMin),
AxialLoad = MakeMinMaxExtended(p.AxialLoadAvg, p.AxialLoadMax, p.AxialLoadMin),
Flow = MakeMinMaxExtended(p.FlowAvg, p.FlowMax, p.FlowMin),
RotorSpeed = MakeMinMaxExtended(p.RotorSpeedAvg, p.RotorSpeedMax, p.RotorSpeedMin),
RotorTorque = MakeMinMaxExtended(p.RotorTorqueAvg, p.RotorTorqueMax, p.RotorTorqueMin)
};
return dto;
});
return dtos;
}
public async Task<IEnumerable<DrillParamsDto>> GetCompositeAllAsync(int idWell,
CancellationToken token = default)
{
var compositeWellDrillParams =
await (from p in db.DrillParams
from c in db.WellComposites
where c.IdWell == idWell &&
p.IdWell == c.IdWellSrc &&
p.IdWellSectionType == c.IdWellSectionType
select p)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var allDrillParamsQuery = db.WellComposites
.Where(c => c.IdWell == idWell)
.Join(db.DrillParams,
c => c.IdWellSrc,
p => p.IdWell,
(c, p) => p);
var compositeDrillParamsDtos = compositeWellDrillParams.Adapt<IEnumerable<DrillParamsDto>>();
var allDrillParams = await allDrillParamsQuery
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
return compositeDrillParamsDtos;
var compositeWellDrillParamsQuery = db.WellComposites
.Where(c => c.IdWell == idWell)
.Join(db.DrillParams,
c => new { IdWell = c.IdWellSrc, IdSection = c.IdWellSectionType },
p => new { IdWell = p.IdWell, IdSection = p.IdWellSectionType },
(c, p) => p);
var compositeWellDrillParams = await compositeWellDrillParamsQuery
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var result = compositeWellDrillParams.Select(x => Convert(x, allDrillParams));
return result;
}
public async Task<int> InsertAsync(int idWell, DrillParamsDto dto,
@ -143,5 +189,34 @@ namespace AsbCloudInfrastructure.Services
var result = await base.UpdateAsync(dto, token).ConfigureAwait(false);
return result;
}
private static DrillParamsDto Convert(DrillParams entity, IEnumerable<DrillParams> drillParams)
{
return new DrillParamsDto
{
Id = entity.Id,
IdWellSectionType = entity.IdWellSectionType,
AxialLoad = MakeMinMaxExtended(entity.AxialLoadAvg, entity.AxialLoadMax, entity.AxialLoadMin, drillParams.Select(x => (x.AxialLoadMin, x.AxialLoadMax))),
Depth = new MinMaxDto<double> {
Min = entity.DepthEnd,
Max = entity.DepthStart
},
Flow = MakeMinMaxExtended(entity.FlowAvg, entity.FlowMax, entity.FlowMin, drillParams.Select(x => (x.FlowMin, x.FlowMax))),
IdWell = entity.IdWell,
Pressure = MakeMinMaxExtended(entity.PressureAvg, entity.PressureMax, entity.PressureMin, drillParams.Select(x => (x.PressureMin, x.PressureMax))),
RotorSpeed = MakeMinMaxExtended(entity.RotorSpeedAvg, entity.RotorSpeedMax, entity.RotorSpeedMin, drillParams.Select(x => (x.RotorSpeedMin, x.RotorSpeedMax))),
RotorTorque = MakeMinMaxExtended(entity.RotorTorqueAvg, entity.RotorTorqueMax, entity.RotorTorqueMin, drillParams.Select(x => (x.RotorTorqueMin, x.RotorTorqueMax)))
};
}
private static MinMaxExtendedViewDto MakeMinMaxExtended(double avg, double max, double min, IEnumerable<(double min, double max)>? allDrillParams = null)
=> new MinMaxExtendedViewDto {
Avg = avg,
Max = max,
Min = min,
IsMax = (! allDrillParams?.Any (mx => mx.max > max)) ?? false,
IsMin = (! allDrillParams?.Any (mn => mn.min < min)) ?? false
};
}
#nullable disable
}

View File

@ -2,6 +2,7 @@
using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -19,7 +20,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
private static readonly Dictionary<string, DrillingProgramCreateError> drillingProgramCreateErrors = new Dictionary<string, DrillingProgramCreateError>();
private readonly IAsbCloudDbContext context;
private readonly IFileService fileService;
private readonly FileService fileService;
private readonly IUserService userService;
private readonly IWellService wellService;
private readonly IConfiguration configuration;
@ -49,7 +50,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
public DrillingProgramService(
IAsbCloudDbContext context,
IFileService fileService,
FileService fileService,
IUserService userService,
IWellService wellService,
IConfiguration configuration,
@ -281,7 +282,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
fileMarkDto.IdMarkType != idMarkTypeReject)
throw new ArgumentInvalidException($"В этом методе допустимы только отметки о принятии или отклонении.", nameof(fileMarkDto));
var fileInfo = await fileService.GetInfoAsync(fileMarkDto.IdFile, token)
var fileInfo = await fileService.GetOrDefaultAsync(fileMarkDto.IdFile, token)
.ConfigureAwait(false);
if (fileInfo is null)
@ -356,7 +357,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
{
var file = await fileService.GetInfoAsync(fileMark.IdFile, token);
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
var user = file.Author;
var factory = new DrillingMailBodyFactory(configuration);
@ -368,7 +369,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
{
var file = await fileService.GetInfoAsync(fileMark.IdFile, token);
var file = await fileService.GetOrDefaultAsync(fileMark.IdFile, token);
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
var user = file.Author;
var factory = new DrillingMailBodyFactory(configuration);
@ -472,14 +473,15 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
var well = await wellService.GetOrDefaultAsync(idWell, token);
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx";
var tempResultFilePath = Path.Combine(Path.GetTempPath(), "drillingProgram", resultFileName);
var mailService = new EmailService(backgroundWorker, configuration);
async Task funcProgramMake(string id, CancellationToken token)
{
var contextOptions = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql(connectionString)
.Options;
using var context = new AsbCloudDbContext(contextOptions);
var fileService = new FileService(context);
var fileRepository = new FileRepository(context);
var fileStorageRepository = new FileStorageRepository();
var fileService = new FileService(fileRepository, fileStorageRepository);
var files = state.Parts.Select(p => fileService.GetUrl(p.File));
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token);

View File

@ -1,379 +0,0 @@
using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class FileService : IFileService
{
public string RootPath { get; private set; }
private readonly IQueryable<AsbCloudDb.Model.FileInfo> dbSetConfigured;
private readonly IAsbCloudDbContext db;
public FileService(IAsbCloudDbContext db)
{
RootPath = "files";
this.db = db;
dbSetConfigured = db.Files
.Include(f => f.Author)
.ThenInclude(u => u.Company)
.ThenInclude(c => c.CompanyType)
.Include(f => f.FileMarks)
.ThenInclude(m => m.User)
.Include(f => f.Well);
}
public async Task<FileInfoDto> MoveAsync(int idWell, int? idUser, int idCategory,
string destinationFileName, string srcFilePath, CancellationToken token = default)
{
destinationFileName = Path.GetFileName(destinationFileName);
srcFilePath = Path.GetFullPath(srcFilePath);
if (!File.Exists(srcFilePath))
throw new ArgumentInvalidException($"file {srcFilePath} doesn't exist", nameof(srcFilePath));
var sysFileInfo = new System.IO.FileInfo(srcFilePath);
//save info to db
var fileInfo = new AsbCloudDb.Model.FileInfo()
{
IdWell = idWell,
IdAuthor = idUser,
IdCategory = idCategory,
Name = destinationFileName,
UploadDate = DateTime.UtcNow,
IsDeleted = false,
Size = sysFileInfo.Length,
};
var entry = db.Files.Add(fileInfo);
await db.SaveChangesAsync(token).ConfigureAwait(false);
var fileId = entry.Entity.Id;
string filePath = MakeFilePath(idWell, idCategory, destinationFileName, fileId);
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.Move(srcFilePath, filePath);
return await GetInfoAsync(entry.Entity.Id, token);
}
public async Task<FileInfoDto> SaveAsync(int idWell, int? idUser, int idCategory,
string fileFullName, Stream fileStream, CancellationToken token)
{
//save info to db
var fileInfo = new AsbCloudDb.Model.FileInfo()
{
IdWell = idWell,
IdAuthor = idUser,
IdCategory = idCategory,
Name = Path.GetFileName(fileFullName),
UploadDate = DateTime.UtcNow,
IsDeleted = false,
Size = fileStream?.Length ?? 0
};
var entry = db.Files.Add(fileInfo);
await db.SaveChangesAsync(token).ConfigureAwait(false);
var fileId = entry.Entity.Id;
//save stream to disk
string filePath = MakeFilePath(idWell, idCategory, fileFullName, fileId);
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
using var newfileStream = new FileStream(filePath, FileMode.Create);
await fileStream.CopyToAsync(newfileStream, token).ConfigureAwait(false);
return await GetInfoAsync(entry.Entity.Id, token);
}
private string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId)
{
return Path.Combine(RootPath, $"{idWell}",
$"{idCategory}", $"{fileId}" + $"{Path.GetExtension(fileFullName)}");
}
public async Task<IEnumerable<FileInfoDto>> GetInfosByCategoryAsync(int idWell,
int idCategory, CancellationToken token)
{
var entities = await dbSetConfigured
.Where(e => e.IdWell == idWell && e.IdCategory == idCategory && e.IsDeleted == false)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(e => Convert(e));
return dtos;
}
public async Task<PaginationContainer<FileInfoDto>> GetInfosAsync(int idWell,
int idCategory, string companyName = default, string fileName = default, DateTime begin = default,
DateTime end = default, int skip = 0, int take = 32, CancellationToken token = default)
{
var query = dbSetConfigured
.Where(e => e.IdWell == idWell &&
e.IdCategory == idCategory &&
!e.IsDeleted);
if (!string.IsNullOrEmpty(companyName))
query = query.Where(e => (e.Author == null) ||
(e.Author.Company == null) ||
e.Author.Company.Caption.Contains(companyName));
if (!string.IsNullOrEmpty(fileName))
query = query.Where(e => e.Name.ToLower().Contains(fileName.ToLower()));
var firstFile = await query.FirstOrDefaultAsync(token);
if (firstFile is null)
return new PaginationContainer<FileInfoDto>()
{
Skip = skip,
Take = take,
Count = 0,
};
var timezoneOffset = firstFile.Well.Timezone?.Hours ?? 5;
if (begin != default)
{
var beginUtc = begin.ToUtcDateTimeOffset(timezoneOffset);
query = query.Where(e => e.UploadDate >= beginUtc);
}
if (end != default)
{
var endUtc = end.ToUtcDateTimeOffset(timezoneOffset);
query = query.Where(e => e.UploadDate <= endUtc);
}
var count = await query.CountAsync(token).ConfigureAwait(false);
var result = new PaginationContainer<FileInfoDto>(count)
{
Skip = skip,
Take = take,
Count = count,
};
if (count <= skip)
return result;
query = query.OrderBy(e => e.UploadDate);
if (skip > 0)
query = query.Skip(skip);
query = query.Take(take);
var entities = await query
.Take(take).AsNoTracking().ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(e => Convert(e, timezoneOffset));
result.Items.AddRange(dtos);
return result;
}
public async Task<FileInfoDto> GetInfoAsync(int idFile,
CancellationToken token)
{
var entity = await dbSetConfigured
.AsNoTracking()
.FirstOrDefaultAsync(f => f.Id == idFile, token)
.ConfigureAwait(false);
if (entity is null)
{
throw new FileNotFoundException($"fileId:{idFile} not found");
}
var ext = Path.GetExtension(entity.Name);
var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext);
var fullPath = Path.GetFullPath(relativePath);
if (!File.Exists(fullPath))
{
throw new FileNotFoundException("not found", relativePath);
}
var dto = Convert(entity);
return dto;
}
public async Task<int> MarkAsDeletedAsync(int idFile,
CancellationToken token = default)
{
var fileInfo = await db.Files.FirstOrDefaultAsync(f => f.Id == idFile, token).ConfigureAwait(false);
if (fileInfo is null)
return 0;
fileInfo.IsDeleted = true;
return await db.SaveChangesAsync(token).ConfigureAwait(false);
}
public Task<int> DeleteAsync(int idFile, CancellationToken token)
=> DeleteAsync(new int[] { idFile }, token);
public async Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
{
if (ids is null || !ids.Any())
return 0;
var filesQuery = db.Files
.Where(f => ids.Contains(f.Id));
var files = await filesQuery.ToListAsync(token);
if (files is null || !files.Any())
return 0;
foreach (var file in files)
{
var fileName = GetUrl(file.IdWell, file.IdCategory, file.Id, Path.GetExtension(file.Name));
if (File.Exists(fileName))
File.Delete(fileName);
}
db.Files.RemoveRange(filesQuery);
return await db.SaveChangesAsync(token).ConfigureAwait(false);
}
public string GetUrl(int idFile)
{
var fileInfo = db.Files
.FirstOrDefault(f => f.Id == idFile);
if (fileInfo is null)
return null;
return GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
}
public string GetUrl(FileInfoDto fileInfo) =>
GetUrl(fileInfo.IdWell, fileInfo.IdCategory, fileInfo.Id, Path.GetExtension(fileInfo.Name));
public string GetUrl(int idWell, int idCategory, int idFile, string dotExtention) =>
Path.Combine(RootPath, idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}");
public async Task<FileInfoDto> GetByMarkId(int idMark,
CancellationToken token)
{
var entity = await dbSetConfigured
.FirstOrDefaultAsync(f => f.FileMarks.Any(m => m.Id == idMark), token)
.ConfigureAwait(false);
FileInfoDto dto = Convert(entity);
return dto;
}
private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity)
{
var timezoneOffset = entity.Well.Timezone?.Hours ?? 5;
return Convert(entity, timezoneOffset);
}
private static FileInfoDto Convert(AsbCloudDb.Model.FileInfo entity, double timezoneOffset)
{
var dto = entity.Adapt<FileInfoDto>();
dto.UploadDate = entity.UploadDate.ToRemoteDateTime(timezoneOffset);
dto.FileMarks = entity.FileMarks.Select(m =>
{
var mark = m.Adapt<FileMarkDto>();
mark.DateCreated = m.DateCreated.ToRemoteDateTime(timezoneOffset);
return mark;
});
return dto;
}
public async Task<int> CreateFileMarkAsync(FileMarkDto fileMarkDto, int idUser, CancellationToken token)
{
var fileMark = await db.FileMarks
.FirstOrDefaultAsync(m => m.IdFile == fileMarkDto.IdFile &&
m.IdMarkType == fileMarkDto.IdMarkType &&
m.IdUser == idUser &&
m.IsDeleted == false,
token)
.ConfigureAwait(false);
if (fileMark is not null)
return 0;
var newFileMark = fileMarkDto.Adapt<FileMark>();
newFileMark.Id = default;
newFileMark.DateCreated = DateTime.UtcNow;
newFileMark.IdUser = idUser;
newFileMark.User = null;
db.FileMarks.Add(newFileMark);
return await db.SaveChangesAsync(token);
}
public Task<int> MarkFileMarkAsDeletedAsync(int idMark,
CancellationToken token)
=> MarkFileMarkAsDeletedAsync(new int[] { idMark }, token);
public async Task<int> MarkFileMarkAsDeletedAsync(IEnumerable<int> idsMarks,
CancellationToken token)
{
var fileMarkQuery = db.FileMarks
.Where(m => idsMarks.Contains(m.Id));
foreach (var fileMark in fileMarkQuery)
fileMark.IsDeleted = true;
return await db.SaveChangesAsync(token);
}
public async Task<List<FileInfoDto>> GetInfoByIdsAsync(List<int> idsFile, CancellationToken token)
{
var result = new List<FileInfoDto>();
var entities = await dbSetConfigured
.AsNoTracking()
.Where(f => idsFile.Contains(f.Id))
.ToListAsync(token)
.ConfigureAwait(false);
foreach (var entity in entities)
{
if (entity is null)
{
throw new FileNotFoundException($"fileId:{entity.Id} not found");
}
var ext = Path.GetExtension(entity.Name);
var relativePath = GetUrl(entity.IdWell, entity.IdCategory, entity.Id, ext);
var fullPath = Path.GetFullPath(relativePath);
if (!File.Exists(fullPath))
{
throw new FileNotFoundException("not found", relativePath);
}
result.Add(Convert(entity));
}
return result;
}
public async Task<IEnumerable<FileInfoDto>> GetInfosByWellIdAsync(int idWell, CancellationToken token)
{
var entities = await dbSetConfigured
.Where(e => e.IdWell == idWell && e.IsDeleted == false)
.AsNoTracking()
.ToListAsync(token)
.ConfigureAwait(false);
var dtos = entities.Select(e => Convert(e));
return dtos;
}
}
}

View File

@ -0,0 +1,335 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
#nullable enable
class JobHandle
{
public int Id => Job.Id;
public JobDto Job { get; set; } = null!;
public DateTime DateCreate { get; set; } = DateTime.Now;
public OnJobProgressDelagate? OnProgress { get; set; }
}
public class ReduceSamplingService : IReduceSamplingService
{
private const string jobResultKeyDeleted = "deleted";
private const string jobResultKeyTotal = "total";
private static ReduceSamplingService? instance;
private readonly string connectionString;
private const int ratio = 5;
private readonly List<JobHandle> jobHandlers = new(5);
private bool isHandling;
private CancellationTokenSource? cancellationTokenSource;
private Task? task;
private ReduceSamplingService(IConfiguration configuration)
{
connectionString = configuration.GetConnectionString("DefaultConnection");
}
~ReduceSamplingService()
{
Stop();
}
/// <summary>
/// Get singleton Instance
/// </summary>
/// <param name="configuration"></param>
/// <returns></returns>
public static ReduceSamplingService GetInstance(IConfiguration configuration)
{
instance ??= new(configuration);
return instance;
}
/// <inheritdoc/>
public bool TryEnqueueRediceSamplingJob(int idTelemetry, OnJobProgressDelagate? onProgress, out JobDto jobDto)
{
lock (jobHandlers)
{
var oldJob = jobHandlers.FirstOrDefault(j => j.Id == idTelemetry);
if (oldJob is not null)
{
jobDto = oldJob.Job;
return false;
}
jobDto = new JobDto
{
Id = idTelemetry,
State = JobState.Waiting,
Results = new(),
};
var jobHandler = new JobHandle
{
Job = jobDto,
OnProgress = onProgress,
};
jobHandlers.Add(jobHandler);
}
EnsureHandleQueueStarted();
return true;
}
/// <inheritdoc/>
public JobDto? GetOrDefaultState(int idTelemetry)
{
JobHandle? jobHandler;
lock (jobHandlers)
{
jobHandler = jobHandlers.FirstOrDefault(j => j.Id == idTelemetry);
}
return jobHandler?.Job;
}
/// <inheritdoc/>
public IEnumerable<JobDto> GetJobs() => jobHandlers.Select(j=>j.Job);
private bool TryTakeWaitingJob(out JobHandle? job)
{
lock (jobHandlers)
{
job = jobHandlers.FirstOrDefault(j => j.Job.State == JobState.Waiting);
}
return job is not null;
}
private void EnsureHandleQueueStarted()
{
if (isHandling)
return;
isHandling = true;
cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
task = Task.Run(async () => await HandleJobs(token))
.ContinueWith(_ => isHandling = false);
}
private async Task HandleJobs(CancellationToken token)
{
while (TryTakeWaitingJob(out JobHandle? jobHandler))
{
jobHandler!.Job.State = JobState.Working;
try
{
await RediceSamplingSaubAsync(jobHandler, token);
await RediceSamplingSpinAsync(jobHandler, token);
jobHandler.Job.State = JobState.Done;
}
catch (Exception exception)
{
jobHandler.Job.State = JobState.Fail;
jobHandler.Job.Results = null;
jobHandler.Job.Error = exception.Message;
jobHandler.OnProgress?.Invoke(jobHandler.Job);
}
if (!jobHandlers.Any(j => j.Job.State == JobState.Waiting))
{
var sw = Stopwatch.StartNew();
await VacuumAsync(token);
sw.Stop();
if (sw.ElapsedMilliseconds < 10_000)
{
var delayMs = 10_000 - (int)sw.ElapsedMilliseconds;
await Task.Delay(delayMs, token);
}
CleanJobs();
}
}
}
private void CleanJobs()
{
lock (jobHandlers)
{
jobHandlers.RemoveAll(j => j.Job.State == JobState.Done || j.Job.State == JobState.Fail);
}
}
private async Task VacuumAsync(CancellationToken token)
{
using var db = MakeContext();
var sqlVacuum = "vacuum (SKIP_LOCKED);";
await db.Database.ExecuteSqlRawAsync(sqlVacuum, token);
}
private void Stop()
{
cancellationTokenSource?.Cancel();
task?.Wait(1_000);
task = null;
cancellationTokenSource?.Dispose();
cancellationTokenSource = null;
}
private Task RediceSamplingSaubAsync(JobHandle job, CancellationToken token)
{
const int ramLimit = 10 * 1024 * 1024;
const int dataItemSize = 345; // by profiler
const int chankSize = ramLimit / dataItemSize; // ~ 90_000
const double maxWellDepthGap = 0.1;
var maxDateGapSec = ratio;
var sqlSelectTemplate =
"select " +
" * " +
"from " +
" (select " +
" *, " +
" rank() over win1 as row_num, " +
" lag(\"date\", 1) over win1 as lag_date, " +
" lag(\"mode\", 1) over win1 as lag_mode, " +
" lag(mse_state, 1) over win1 as lag_mse_state, " +
" lag(well_depth, 1) over win1 as lag_well_depth, " +
" lag(id_feed_regulator, 1) over win1 as lag_id_feed_regulator " +
" from t_telemetry_data_saub " +
$" where id_telemetry = {job.Id} and \"date\" > {{0}}" +
" window win1 as (order by \"date\") " +
" ) as t_1 " +
"where " +
$" (row_num % {ratio}) = 0 " +
" or \"mode\" != lag_mode " +
$" or(\"date\" - lag_date) >= interval '{maxDateGapSec} second' " +
$" or well_depth - lag_well_depth > {maxWellDepthGap:#0,0#} " +
" or mse_state != lag_mse_state " +
" or id_feed_regulator != lag_id_feed_regulator " +
"order by \"date\" ";
var sqlDeleteTemplate = "delete " +
"from t_telemetry_data_saub " +
$"where id_telemetry = {job.Id} and \"date\" between {{0}} and {{1}};";
return RediceSamplingAsync<TelemetryDataSaub>(
job,
chankSize,
sqlSelectTemplate,
sqlDeleteTemplate,
token);
}
private Task RediceSamplingSpinAsync(JobHandle job, CancellationToken token)
{
const int ramLimit = 10 * 1024 * 1024;
const int dataItemSize = 345; // by profiler
const int chankSize = ramLimit / dataItemSize; // ~ 90_000
var maxDateGapSec = ratio;
var sqlSelectTemplate =
"select " +
" * " +
"from " +
" (select " +
" *, " +
" rank() over win1 as row_num, " +
" lag(\"date\", 1) over win1 as lag_date, " +
" lag(\"mode\", 1) over win1 as lag_mode, " +
" lag(state, 1) over win1 as lag_state " +
" from t_telemetry_data_spin " +
$" where id_telemetry = {job.Id} and \"date\" > {{0}}" +
" window win1 as (order by \"date\") " +
" ) as t_1 " +
"where " +
$" (row_num % {ratio}) = 0 " +
" or \"mode\" != lag_mode " +
$" or(\"date\" - lag_date) >= interval '{maxDateGapSec} second' " +
" or state != lag_state " +
"order by \"date\" ";
var sqlDeleteTemplate = "delete " +
"from t_telemetry_data_spin " +
$"where id_telemetry = {job.Id} and \"date\" between {{0}} and {{1}};";
return RediceSamplingAsync<TelemetryDataSpin>(
job,
chankSize,
sqlSelectTemplate,
sqlDeleteTemplate,
token);
}
private async Task RediceSamplingAsync<TEntity>(
JobHandle jobHandle,
int chankSize,
string sqlSelectTemplate,
string sqlDeleteTemplate,
CancellationToken token)
where TEntity : class, AsbCloudDb.Model.ITelemetryData
{
using var db = MakeContext();
var dbset = db.Set<TEntity>();
var deleted = 0;
var totalCount = await dbset.Where(t => t.IdTelemetry == jobHandle.Id).CountAsync(token);
var result = jobHandle.Job.Results!;
if (result[jobResultKeyDeleted] is int previousDeleted)
deleted += previousDeleted;
if (result[jobResultKeyTotal] is int previousCount)
totalCount += previousCount;
result[jobResultKeyDeleted] = deleted;
result[jobResultKeyTotal] = totalCount;
jobHandle.OnProgress?.Invoke(jobHandle.Job);
var startDate = DateTimeOffset.MinValue;
do
{
var query = dbset
.FromSqlRaw(sqlSelectTemplate, startDate)
.AsNoTracking();
var data = await query
.Take(chankSize)
.ToArrayAsync(token);
var currentDataCount = data.Length;
if (currentDataCount == 0)
break;
var lastDate = data.Last().DateTime;
var currentDeleted = await db.Database.ExecuteSqlRawAsync(sqlDeleteTemplate, new object[] { startDate, lastDate }.AsEnumerable(), token);
if (currentDeleted == 0)
break;
await db.Database.ExecInsertAsync(dbset, data, token);
startDate = lastDate;
deleted += currentDeleted;
result[jobResultKeyDeleted] = deleted;
result[jobResultKeyTotal] = totalCount;
jobHandle.OnProgress?.Invoke(jobHandle.Job);
} while (true);
return;
}
private AsbCloudDbContext MakeContext()
{
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql(connectionString)
.Options;
return new AsbCloudDbContext(options);
}
}
#nullable disable
}

View File

@ -1,6 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using AsbSaubReport;
using Mapster;
using Microsoft.EntityFrameworkCore;
@ -65,7 +66,9 @@ namespace AsbCloudInfrastructure.Services
};
generator.Make(reportFileName);
var fileService = new FileService(context);
var fileRepository = new FileRepository(context);
var fileStorageRepository = new FileStorageRepository();
var fileService = new FileService(fileRepository, fileStorageRepository);
var fileInfo = await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token);
progressHandler.Invoke(new

View File

@ -16,7 +16,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
where TDto : AsbCloudApp.Data.ITelemetryData
where TModel : class, AsbCloudDb.Model.ITelemetryData
{
private readonly IAsbCloudDbContext db;
protected readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
protected readonly CacheTable<Telemetry> cacheTelemetry;
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
@ -134,25 +134,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
if (fullDataCount > 1.75 * approxPointsCount)
{
var m = (int)Math.Round(1d * fullDataCount / approxPointsCount);
switch (m)
{
//case var i when i <= 1: // тут для полноты, но никогда не сработает из-за условия выше
// break;
case var i when i < 10:
query = query.Where((d) => d.DateTime.Second % m == 0);
break;
case var i when i < 30:
query = query.Where((d) => (d.DateTime.Minute * 60 + d.DateTime.Second) % m == 0);
break;
case var i when i < 600:
query = query.Where((d) => ((d.DateTime.Hour * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
break;
default:
query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
break;
}
if (m > 1)
query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
}
@ -189,5 +170,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
return offset;
}
}
}

View File

@ -2,7 +2,12 @@
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using DocumentFormat.OpenXml.Drawing.Charts;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.SAUB
{

View File

@ -3,6 +3,8 @@ using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using Mapster;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services.SAUB
{

View File

@ -145,8 +145,8 @@ namespace AsbCloudInfrastructure.Services.Subsystems
SumDepthInterval = periodGroupDepth,
OperationCount = g.Count()
};
if(subsystemStat.KUsage > 100)
subsystemStat.KUsage = 100;
if(subsystemStat.KUsage > 1)
subsystemStat.KUsage = 1;
return subsystemStat;
});

View File

@ -1,7 +1,9 @@
using AsbCloudApp.Data;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -21,7 +23,7 @@ namespace AsbCloudInfrastructure.Services
public class WellFinalDocumentsService : IWellFinalDocumentsService
{
private readonly IAsbCloudDbContext context;
private readonly IFileService fileService;
private readonly FileService fileService;
private readonly IUserService userService;
private readonly IWellService wellService;
private readonly IConfiguration configuration;
@ -31,7 +33,7 @@ namespace AsbCloudInfrastructure.Services
private const int FileServiceThrewException = -1;
public WellFinalDocumentsService(IAsbCloudDbContext context,
IFileService fileService,
FileService fileService,
IUserService userService,
IWellService wellService,
IConfiguration configuration,
@ -95,7 +97,7 @@ namespace AsbCloudInfrastructure.Services
.Select(g => g.Key);
var files = (await fileService
.GetInfosByWellIdAsync(idWell, token)
.GetInfosAsync(new FileRequest { IdWell = idWell}, token)
.ConfigureAwait(false))
.Where(f => categoriesIds.Contains(f.IdCategory))
.ToArray();
@ -161,7 +163,12 @@ namespace AsbCloudInfrastructure.Services
public async Task<WellFinalDocumentsHistoryDto> GetFilesHistoryByIdCategory(int idWell, int idCategory, CancellationToken token)
{
var files = await fileService.GetInfosByCategoryAsync(idWell, idCategory, token).ConfigureAwait(false);
var request = new FileRequest
{
IdWell = idWell,
IdCategory = idCategory,
};
var files = await fileService.GetInfosAsync(request, token).ConfigureAwait(false);
return new WellFinalDocumentsHistoryDto {
IdWell = idWell,

View File

@ -0,0 +1,9 @@
# Создание репозитория для сервися
1. Создать интерфейс репозитория в AsbCloudApp.Services
2. Создать репозиторий в AsbCloudInfrastructure.Repository, наследоваться от созданного интерфейса, в нем добавить работу с БД
3. Добавить репозиторий в AsbCloudInfrastructure.DependencyInjection
4. Добавить в конструктор сервиса новый репозиторий и использовать его методы
5. Перенести сервис из AsbCloudInfrastructure.Services в AsbCloudApp.Services
6. Добавить или поправить тесты на изменяемый сервис используя AsbCloudWebApi.Tests.RepositoryFactory
7. В тестах сделать мок данных для репозитория

View File

@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Linq;
namespace AsbCloudInfrastructure
{

View File

@ -4,6 +4,8 @@
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Tests
{
public interface IRepositoryFactory<TDto>
{
Task<int> DeleteAsync(int id, CancellationToken token);
Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token);
TDto? GetOrDefault(int id);
Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token);
Task<int> InsertAsync(TDto newItem, CancellationToken token);
Task<int> InsertRangeAsync(IEnumerable<TDto> newItems, CancellationToken token);
Task<int> UpdateAsync(TDto item, CancellationToken token);
}
}

View File

@ -0,0 +1,42 @@
using AsbCloudApp.Services;
using Moq;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Tests
{
public class RepositoryFactory
{
public static Mock<TRepository> Make<TRepository, TDto>(ICollection<TDto> data)
where TDto : AsbCloudApp.Data.IId
where TRepository : class, ICrudService<TDto>
{
var repositoryMock = new Mock<TRepository>();
repositoryMock.Setup(x => x.InsertAsync(It.IsAny<TDto>(), It.IsAny<CancellationToken>()))
.Returns((TDto dto, CancellationToken token) => {
var id = data.Max(x => x.Id);
dto.Id = ++id;
data.Add(dto);
return Task.FromResult(dto.Id);
});
repositoryMock.Setup(x => x.DeleteAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns((int idFile, CancellationToken token) => {
var cnt = data.Count;
var dto = data.FirstOrDefault(x => x.Id == idFile);
data.Remove(dto);
return Task.FromResult(cnt - data.Count);
});
repositoryMock.Setup(x => x.GetAllAsync(It.IsAny<CancellationToken>())).ReturnsAsync(data);
repositoryMock.Setup(x => x.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns((int idFile, CancellationToken token) => {
return Task.FromResult(data.FirstOrDefault(x => x.Id == idFile));
});
return repositoryMock;
}
}
}

View File

@ -1,6 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Repository;
using AsbCloudInfrastructure.Services.DrillingProgram;
using Mapster;
using Microsoft.Extensions.Configuration;
@ -77,7 +78,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
new RelationCompanyWell { IdCompany = 3003, IdWell = 3002, },
};
private readonly Mock<IFileService> fileServiceMock;
private readonly Mock<FileService> fileServiceMock;
private readonly Mock<IUserService> userServiceMock;
private readonly Mock<IWellService> wellServiceMock;
private readonly Mock<IConfiguration> configurationMock;
@ -96,7 +97,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
db.RelationCompaniesWells.AddRange(relationsCompanyWell);
db.SaveChanges();
fileServiceMock = new Mock<IFileService>();
fileServiceMock = new Mock<FileService>();
userServiceMock = new Mock<IUserService>();
wellServiceMock = new Mock<IWellService>();
configurationMock = new Mock<IConfiguration>();
@ -219,7 +220,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{
ConfigureNotApproved();
fileServiceMock
.Setup(s => s.GetInfoAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(file1002.Adapt<FileInfoDto>()));
fileServiceMock
@ -250,7 +251,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{
ConfigureNotApproved();
fileServiceMock
.Setup(s => s.GetInfoAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(file1002.Adapt<FileInfoDto>()));
fileServiceMock

View File

@ -0,0 +1,200 @@
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using Moq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace AsbCloudWebApi.Tests.ServicesTests
{
public class FileServiceTest
{
private FileService fileService;
private static UserDto Author = new UserDto {
Id = 1,
IdCompany = 1
};
private static List<FileMarkDto> FileMarks = new List<FileMarkDto> {
new FileMarkDto
{
Id = 132,
IdFile = 1742,
User = Author,
Comment = "qqq",
IdMarkType = 1,
DateCreated = DateTime.Now,
IsDeleted = false
},
new FileMarkDto
{
Id = 133,
IdFile = 1742,
User = Author,
Comment = "qqq3",
IdMarkType = 1,
DateCreated = DateTime.Now,
IsDeleted = false
}
};
private static List<FileInfoDto> Files = new List<FileInfoDto> {
new FileInfoDto {
Id = 1742,
IdAuthor = 1,
Author = Author,
IdWell = 90,
IdCategory = 10040,
Name = "test.txt",
Size = 0,
UploadDate = DateTime.Now,
FileMarks = FileMarks
},
new FileInfoDto
{
Id = 1743,
IdAuthor = 1,
Author = Author,
IdWell = 90,
IdCategory = 10021,
Name = "test1.txt",
Size = 0,
UploadDate = DateTime.Now
}
};
public FileServiceTest()
{
var repositoryMock = RepositoryFactory.Make<IFileRepository, FileInfoDto>(Files);
repositoryMock.Setup(x => x.GetByMarkId(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns((int idMark, CancellationToken token) => {
var data = Files.FirstOrDefault(x => x.FileMarks.Any(m => m.Id == idMark));
return Task.FromResult(data);
});
repositoryMock.Setup(x => x.GetInfoByIdsAsync(It.IsAny<IEnumerable<int>>(), It.IsAny<CancellationToken>()))
.Returns((int[] idsFile, CancellationToken token) => {
var data = Files.Where(x => idsFile.Contains(x.Id));
return Task.FromResult(data);
});
repositoryMock.Setup(x => x.DeleteAsync(It.IsAny<IEnumerable<int>>(), It.IsAny<CancellationToken>()))
.Returns((int[] idsFile, CancellationToken token) => {
var dtos = Files.Where(x => idsFile.Contains(x.Id)).ToArray();
Files.RemoveAll(x => dtos.Select(d => d.Id).Contains(x.Id));
return Task.FromResult(dtos.AsEnumerable());
});
repositoryMock.Setup(x => x.MarkFileMarkAsDeletedAsync(It.IsAny<IEnumerable<int>>(), It.IsAny<CancellationToken>()))
.Returns((int[] idsMarks, CancellationToken token) => {
var data = FileMarks.Where(m => idsMarks.Contains(m.Id));
foreach (var fileMark in data)
fileMark.IsDeleted = true;
var result = data.All(x => x.IsDeleted) ? 1 : 0;
return Task.FromResult(result);
});
repositoryMock.Setup(x => x.MarkAsDeletedAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns((int idFile, CancellationToken token) => {
var result = Files.Where(x => x.Id == idFile).Any() ? 1 : 0;
return Task.FromResult(result);
});
repositoryMock.Setup(x => x.GetInfosAsync(It.IsAny<FileRequest>(), It.IsAny<CancellationToken>()))
.Returns((FileRequest request, CancellationToken token) => {
var data = Files.Where(x => x.IdWell == request.IdWell);
return Task.FromResult(data);
});
repositoryMock.Setup(x => x.CreateFileMarkAsync(It.IsAny<FileMarkDto>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
.Returns((FileMarkDto dto, int idUser, CancellationToken token) => {
dto.Id = FileMarks.Max(x => x.Id) + 1;
dto.DateCreated = DateTime.UtcNow;
dto.User = null;
FileMarks.Add(dto);
var result = FileMarks.Any(x => x.Id == dto.Id) ? 1 : 0;
return Task.FromResult(result);
});
var storageRepositoryMock = new Mock<IFileStorageRepository>();
storageRepositoryMock.Setup(x => x.GetUrl(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>()))
.Returns((int idWell, int idCategory, int idFile, string dotExtention) => {
return Path.Combine("files", idWell.ToString(), idCategory.ToString(), $"{idFile}{dotExtention}");
});
fileService = new FileService(repositoryMock.Object, storageRepositoryMock.Object);
}
[Fact]
public async Task GetByMarkId_returns_FileInfo_by_idMark()
{
var data = await fileService.GetByMarkId(133, CancellationToken.None);
Assert.NotNull(data);
}
[Fact]
public async Task GetOrDefaultAsync_returns_FileInfo()
{
var data = await fileService.GetOrDefaultAsync(1742, CancellationToken.None);
Assert.NotNull(data);
}
[Fact]
public async Task GetInfoByIdsAsync_returns_FileInfo()
{
var data = await fileService.GetInfoByIdsAsync(new int[] { 1742, 1743 }, CancellationToken.None);
Assert.NotNull(data);
}
[Fact]
public async Task SaveAsync_returns_FileInfo()
{
using var stream = new MemoryStream(Array.Empty<byte>());
var data = await fileService.SaveAsync(90, 1, 10040, "test.txt", stream, CancellationToken.None);
Assert.NotNull(data);
}
[Fact]
public async Task DeleteAsync()
{
var result = await fileService.DeleteAsync(new int[] { 1743 }, CancellationToken.None);
Assert.True(result > 0);
}
[Fact]
public async Task MarkFileMarkAsDeletedAsync()
{
var result = await fileService.MarkFileMarkAsDeletedAsync(new int[] { 132, 133 }, CancellationToken.None);
Assert.True(result > 0);
}
[Fact]
public async Task MarkAsDeletedAsync()
{
var result = await fileService.MarkAsDeletedAsync(1742, CancellationToken.None);
Assert.True(result > 0);
}
[Fact]
public async Task CreateFileMarkAsync()
{
var dto = new FileMarkDto {
Comment = "test",
IdFile = 1742,
IdMarkType = 1
};
var result = await fileService.CreateFileMarkAsync(dto, 1, CancellationToken.None);
Assert.True(result > 0);
}
}
}

View File

@ -17,7 +17,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{
private readonly AsbCloudDbContext context;
private WellFinalDocumentsService service;
private readonly Mock<IFileService> fileServiceMock;
private readonly Mock<FileService> fileServiceMock;
private readonly Mock<IUserService> userServiceMock;
private readonly Mock<IWellService> wellServiceMock;
private readonly Mock<IConfiguration> configurationMock;
@ -44,7 +44,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
context = TestHelpter.MakeTestContext();
context.SaveChanges();
fileServiceMock = new Mock<IFileService>();
fileServiceMock = new Mock<FileService>();
userServiceMock = new Mock<IUserService>();
userServiceMock.Setup(x => x.GetAllAsync(CancellationToken.None)).Returns(Task.Run(() => users.Select(x => (UserExtendedDto)x)));

View File

@ -1,4 +1,5 @@
using AsbCloudDb.Model;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

View File

@ -1,15 +1,17 @@
using AsbCloudApp.Data;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudDb.Model;
namespace AsbCloudWebApi.Controllers
{
#nullable enable
/// <summary>
/// Хранение файлов
/// </summary>
@ -18,10 +20,10 @@ namespace AsbCloudWebApi.Controllers
[Authorize]
public class FileController : ControllerBase
{
private readonly IFileService fileService;
private readonly FileService fileService;
private readonly IWellService wellService;
public FileController(IFileService fileService, IWellService wellService)
public FileController(FileService fileService, IWellService wellService)
{
this.fileService = fileService;
this.wellService = wellService;
@ -68,38 +70,27 @@ namespace AsbCloudWebApi.Controllers
/// <summary>
/// Возвращает информацию о файлах для скважины в выбраной категории
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="idCategory">id категории файла</param>
/// <param name="companyName">id компаний для фильтрации возвращаемых файлов</param>
/// <param name="fileName">часть имени файла для поиска</param>
/// <param name="begin">дата начала</param>
/// <param name="end">дата окончания</param>
/// <param name="skip">для пагинации кол-во записей пропустить</param>
/// <param name="take">для пагинации кол-во записей взять </param>
/// <param name="request"> </param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Список информации о файлах в этой категории</returns>
[HttpGet]
[Route("/api/files")]
[Permission]
[ProducesResponseType(typeof(PaginationContainer<FileInfoDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetFilesInfoAsync(
[FromRoute] int idWell,
int idCategory = default,
string companyName = default,
string fileName = default,
DateTime begin = default,
DateTime end = default,
int skip = 0,
int take = 32,
[FromQuery] FileRequest request,
CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
if (request.IdCategory is null || idCompany is null)
return Forbid();
var filesInfo = await fileService.GetInfosAsync(idWell, idCategory,
companyName, fileName, begin, end, skip, take, token).ConfigureAwait(false);
if (!await wellService.IsCompanyInvolvedInWellAsync(idCompany.Value,
request.IdWell, token).ConfigureAwait(false))
return Forbid();
var filesInfo = await fileService.GetInfosPaginatedAsync(request, token).ConfigureAwait(false);
return Ok(filesInfo);
}
@ -108,36 +99,33 @@ namespace AsbCloudWebApi.Controllers
/// Возвращает файл с диска на сервере
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="fileId">id запрашиваемого файла</param>
/// <param name="idFile">id запрашиваемого файла</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet]
[Route("{fileId}")]
[Route("{idFile}")]
[Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetFileAsync([FromRoute] int idWell,
int fileId, CancellationToken token = default)
int idFile, CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
var fileInfo = await fileService.GetOrDefaultAsync(idFile, token);
if (fileInfo is null)
return NotFound(idFile);
if (!await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
fileInfo.IdWell, token).ConfigureAwait(false))
return Forbid();
try
{
var fileInfo = await fileService.GetInfoAsync(fileId, token);
var fileStream = fileService.GetFileStream(fileInfo);
var relativePath = fileService.GetUrl(fileInfo);
return PhysicalFile(Path.GetFullPath(relativePath), "application/octet-stream", fileInfo.Name);
}
catch (FileNotFoundException ex)
{
return NotFound(ex.FileName);
}
return File(fileStream, "application/octet-stream", fileInfo.Name);
}
/// <summary>
@ -159,13 +147,16 @@ namespace AsbCloudWebApi.Controllers
int? idCompany = User.GetCompanyId();
if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
if (idUser is null || idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
idWell, token).ConfigureAwait(false))
return Forbid();
var file = await fileService.GetInfoAsync((int)idFile, token);
var fileInfo = await fileService.GetOrDefaultAsync(idFile, token);
if (!userService.HasPermission((int)idUser, $"File.edit{file.IdCategory}"))
if (fileInfo is null)
return NotFound(idFile);
if (!userService.HasPermission((int)idUser, $"File.edit{fileInfo?.IdCategory}"))
return Forbid();
var result = await fileService.MarkAsDeletedAsync(idFile, token);
@ -223,5 +214,34 @@ namespace AsbCloudWebApi.Controllers
return Ok(result);
}
/// <summary>
/// Возвращает информацию о файле
/// </summary>
/// <param name="idFile">id запрашиваемого файла</param>
/// <param name="token"> Токен отмены задачи </param>
/// <returns>Запрашиваемый файл</returns>
[HttpGet]
[Route("/api/files/{idFile}")]
[Permission]
[ProducesResponseType(typeof(FileInfoDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetFileInfoAsync([FromRoute] int idFile, CancellationToken token = default)
{
int? idCompany = User.GetCompanyId();
if (idCompany is null)
return Forbid();
try
{
var fileInfo = await fileService.GetOrDefaultAsync(idFile, token).ConfigureAwait(false);
return Ok(fileInfo);
}
catch (FileNotFoundException ex)
{
return NotFound(ex.FileName);
}
}
}
#nullable disable
}

View File

@ -0,0 +1,78 @@
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using System.Linq;
using AsbCloudWebApi.SignalR;
using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.Controllers
{
/// <summary>
/// Редактор кустов для админки
/// </summary>
[Route("api/admin/[controller]")]
[ApiController]
[Authorize]
public class ReduceSamplingController: ControllerBase
{
private readonly IReduceSamplingService service;
private readonly IHubContext<TelemetryHub> telemetryHubContext;
private const string sirnalRGroupName = "ReduceSampling";
private const string sirnalRMethodOnProgress = "OnProgress";
public ReduceSamplingController(
IReduceSamplingService service,
IHubContext<TelemetryHub> telemetryHubContext )
{
this.service = service;
this.telemetryHubContext = telemetryHubContext;
}
/// <summary>
/// Получить все задания. Задания удаляются минимум через 10 сек после выполнения, возможно позднее.
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
[HttpGet]
public virtual ActionResult<IEnumerable<JobDto>> GetAll(int idTelemetry)
{
var result = service.GetJobs();
if (result.Any())
return Ok(result);
else
return NoContent();
}
/// <summary>
/// Получить состояние определенной задачи
/// </summary>
/// <param name="idTelemetry"></param>
/// <returns></returns>
[HttpGet("{idTelemetry}")]
public virtual ActionResult<JobDto> GetOrDefault(int idTelemetry)
{
var result = service.GetOrDefaultState(idTelemetry);
return Ok(result);
}
/// <summary>
/// Создать задачу прореживанию архива и добавить её в очередь на выполнение.
/// Если задача есть в очереди, она же и возвращается, но подписка не происходит.
/// </summary>
[HttpPost]
[Permission]
public virtual ActionResult<JobDto> Enqueue(int idTelemetry)
{
void onProgress(JobDto job) =>
Task.Run(async () =>
await telemetryHubContext.Clients.Group(sirnalRGroupName)
.SendAsync(sirnalRMethodOnProgress, job));
service.TryEnqueueRediceSamplingJob(idTelemetry, onProgress, out JobDto job);
return Ok(job);
}
}
}

View File

@ -18,12 +18,12 @@ namespace AsbCloudWebApi.Controllers
public class ReportController : ControllerBase
{
private readonly IReportService reportService;
private readonly IFileService fileService;
private readonly FileService fileService;
private readonly IWellService wellService;
private readonly IHubContext<ReportsHub> reportsHubContext;
public ReportController(IReportService reportService, IWellService wellService,
IFileService fileService, IHubContext<ReportsHub> reportsHubContext)
FileService fileService, IHubContext<ReportsHub> reportsHubContext)
{
this.reportService = reportService;
this.fileService = fileService;

View File

@ -1,3 +1,4 @@
using DocumentFormat.OpenXml.InkML;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -25,7 +26,10 @@ namespace AsbCloudWebApi
{
var connectionStringName = "DefaultConnection";
AsbCloudInfrastructure.DependencyInjection.MakeContext(configuration.GetConnectionString(connectionStringName));
var context = AsbCloudInfrastructure.DependencyInjection.MakeContext(configuration.GetConnectionString(connectionStringName));
context.Database.SetCommandTimeout(TimeSpan.FromSeconds(5 * 60));
context.Database.Migrate();
Console.WriteLine("Óñïåøíî âûïîëíåíî.");
return;
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\publishLinux\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net6.0</TargetFramework>
<ProjectGuid>a2768702-47cb-4127-941c-e339d5efcffe</ProjectGuid>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
</PropertyGroup>
</Project>

View File

@ -296,69 +296,16 @@ namespace AsbCloudWebApi
RuntimeTypeModel.Default.Add(type, false)
.Add(1, nameof(TelemetryDataSpinDto.IdTelemetry))
.Add(2, nameof(TelemetryDataSpinDto.DateTime))
.Add(3, nameof(TelemetryDataSpinDto.TopDriveSpeed))
.Add(4, nameof(TelemetryDataSpinDto.TopDriveSpeedMin))
.Add(5, nameof(TelemetryDataSpinDto.TopDriveSpeedMax))
.Add(6, nameof(TelemetryDataSpinDto.TopDriveSpeedOffset))
.Add(7, nameof(TelemetryDataSpinDto.TopDriveSpeedErr))
.Add(8, nameof(TelemetryDataSpinDto.TopDriveTorque))
.Add(9, nameof(TelemetryDataSpinDto.TopDriveTorqueMin))
.Add(10, nameof(TelemetryDataSpinDto.TopDriveTorqueMax))
.Add(11, nameof(TelemetryDataSpinDto.TopDriveTorqueOffset))
.Add(12, nameof(TelemetryDataSpinDto.TopDriveTorqueErr))
.Add(13, nameof(TelemetryDataSpinDto.TopDriveSpeedSpFrom))
.Add(14, nameof(TelemetryDataSpinDto.TopDriveSpeedSpFromMin))
.Add(15, nameof(TelemetryDataSpinDto.TopDriveSpeedSpFromMax))
.Add(16, nameof(TelemetryDataSpinDto.TopDriveSpeedSpFromOffset))
.Add(17, nameof(TelemetryDataSpinDto.TopDriveSpeedSpFromErr))
.Add(18, nameof(TelemetryDataSpinDto.TopDriveTorqueSpFrom))
.Add(19, nameof(TelemetryDataSpinDto.TopDriveTorqueSpFromMin))
.Add(20, nameof(TelemetryDataSpinDto.TopDriveTorqueSpFromMax))
.Add(21, nameof(TelemetryDataSpinDto.TopDriveTorqueSpFromOffset))
.Add(22, nameof(TelemetryDataSpinDto.TopDriveTorqueSpFromErr))
.Add(23, nameof(TelemetryDataSpinDto.TopDriveSpeedSpTo))
.Add(24, nameof(TelemetryDataSpinDto.TopDriveSpeedSpToMin))
.Add(25, nameof(TelemetryDataSpinDto.TopDriveSpeedSpToMax))
.Add(26, nameof(TelemetryDataSpinDto.TopDriveSpeedSpToOffset))
.Add(27, nameof(TelemetryDataSpinDto.TopDriveSpeedSpToErr))
.Add(28, nameof(TelemetryDataSpinDto.TopDriveTorqueSpTo))
.Add(29, nameof(TelemetryDataSpinDto.TopDriveTorqueSpToMin))
.Add(30, nameof(TelemetryDataSpinDto.TopDriveTorqueSpToMax))
.Add(31, nameof(TelemetryDataSpinDto.TopDriveTorqueSpToOffset))
.Add(32, nameof(TelemetryDataSpinDto.TopDriveTorqueSpToErr))
.Add(33, nameof(TelemetryDataSpinDto.W2800))
.Add(34, nameof(TelemetryDataSpinDto.W2810))
.Add(35, nameof(TelemetryDataSpinDto.Mode))
.Add(36, nameof(TelemetryDataSpinDto.W2808))
.Add(37, nameof(TelemetryDataSpinDto.TorqueStarting))
.Add(38, nameof(TelemetryDataSpinDto.RotorTorqueAvg))
.Add(39, nameof(TelemetryDataSpinDto.EncoderResolution))
.Add(40, nameof(TelemetryDataSpinDto.Ratio))
.Add(41, nameof(TelemetryDataSpinDto.TorqueRightLimit))
.Add(42, nameof(TelemetryDataSpinDto.TorqueLeftLimit))
.Add(43, nameof(TelemetryDataSpinDto.RevolsRightLimit))
.Add(44, nameof(TelemetryDataSpinDto.RevolsLeftLimit))
.Add(45, nameof(TelemetryDataSpinDto.SpeedRightSp))
.Add(46, nameof(TelemetryDataSpinDto.SpeedLeftSp))
.Add(47, nameof(TelemetryDataSpinDto.RevolsRightTotal))
.Add(48, nameof(TelemetryDataSpinDto.RevolsLeftTotal))
.Add(49, nameof(TelemetryDataSpinDto.TurnRightOnceByTorque))
.Add(50, nameof(TelemetryDataSpinDto.TurnLeftOnceByTorque))
.Add(51, nameof(TelemetryDataSpinDto.TurnRightOnceByAngle))
.Add(52, nameof(TelemetryDataSpinDto.TurnLeftOnceByAngle))
.Add(53, nameof(TelemetryDataSpinDto.TurnRightOnceByRevols))
.Add(54, nameof(TelemetryDataSpinDto.TurnLeftOnceByRevols))
.Add(55, nameof(TelemetryDataSpinDto.BreakAngleK))
.Add(56, nameof(TelemetryDataSpinDto.ReverseKTorque))
.Add(57, nameof(TelemetryDataSpinDto.PositionZero))
.Add(58, nameof(TelemetryDataSpinDto.PositionRight))
.Add(59, nameof(TelemetryDataSpinDto.TorqueRampTime))
.Add(60, nameof(TelemetryDataSpinDto.Ver))
.Add(61, nameof(TelemetryDataSpinDto.ReverseSpeedSpZeroTime))
.Add(62, nameof(TelemetryDataSpinDto.UnlockBySectorOut))
.Add(63, nameof(TelemetryDataSpinDto.PidMuxTorqueLeftLimit))
.Add(64, nameof(TelemetryDataSpinDto.State))
.Add(65, nameof(TelemetryDataSpinDto.BreakAngleLeft));
.Add(64, nameof(TelemetryDataSpinDto.State));
}
static void EnshureRegisteredDataSaub()

View File

@ -1,50 +0,0 @@
{
"files": {
"main.css": "/static/css/main.c2a82e71.chunk.css",
"main.js": "/static/js/main.01e9ada9.chunk.js",
"main.js.map": "/static/js/main.01e9ada9.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.8da12c69.js",
"runtime-main.js.map": "/static/js/runtime-main.8da12c69.js.map",
"static/js/2.f196b75b.chunk.js": "/static/js/2.f196b75b.chunk.js",
"static/js/2.f196b75b.chunk.js.map": "/static/js/2.f196b75b.chunk.js.map",
"static/css/3.f8ac3883.chunk.css": "/static/css/3.f8ac3883.chunk.css",
"static/js/3.31b66021.chunk.js": "/static/js/3.31b66021.chunk.js",
"static/js/3.31b66021.chunk.js.map": "/static/js/3.31b66021.chunk.js.map",
"static/css/4.f8ac3883.chunk.css": "/static/css/4.f8ac3883.chunk.css",
"static/js/4.1f09e89e.chunk.js": "/static/js/4.1f09e89e.chunk.js",
"static/js/4.1f09e89e.chunk.js.map": "/static/js/4.1f09e89e.chunk.js.map",
"static/js/5.ef929bfe.chunk.js": "/static/js/5.ef929bfe.chunk.js",
"static/js/5.ef929bfe.chunk.js.map": "/static/js/5.ef929bfe.chunk.js.map",
"static/js/6.88051835.chunk.js": "/static/js/6.88051835.chunk.js",
"static/js/6.88051835.chunk.js.map": "/static/js/6.88051835.chunk.js.map",
"static/js/7.4f3c315a.chunk.js": "/static/js/7.4f3c315a.chunk.js",
"static/js/7.4f3c315a.chunk.js.map": "/static/js/7.4f3c315a.chunk.js.map",
"static/js/8.8e9a1dc7.chunk.js": "/static/js/8.8e9a1dc7.chunk.js",
"static/js/8.8e9a1dc7.chunk.js.map": "/static/js/8.8e9a1dc7.chunk.js.map",
"static/js/9.71667cac.chunk.js": "/static/js/9.71667cac.chunk.js",
"static/js/9.71667cac.chunk.js.map": "/static/js/9.71667cac.chunk.js.map",
"static/js/10.e5247b1b.chunk.js": "/static/js/10.e5247b1b.chunk.js",
"static/js/10.e5247b1b.chunk.js.map": "/static/js/10.e5247b1b.chunk.js.map",
"static/js/11.70112c8f.chunk.js": "/static/js/11.70112c8f.chunk.js",
"static/js/11.70112c8f.chunk.js.map": "/static/js/11.70112c8f.chunk.js.map",
"static/js/12.2265b74f.chunk.js": "/static/js/12.2265b74f.chunk.js",
"static/js/12.2265b74f.chunk.js.map": "/static/js/12.2265b74f.chunk.js.map",
"static/js/13.063a16c9.chunk.js": "/static/js/13.063a16c9.chunk.js",
"static/js/13.063a16c9.chunk.js.map": "/static/js/13.063a16c9.chunk.js.map",
"static/js/14.50a284b1.chunk.js": "/static/js/14.50a284b1.chunk.js",
"static/js/14.50a284b1.chunk.js.map": "/static/js/14.50a284b1.chunk.js.map",
"index.html": "/index.html",
"static/css/3.f8ac3883.chunk.css.map": "/static/css/3.f8ac3883.chunk.css.map",
"static/css/4.f8ac3883.chunk.css.map": "/static/css/4.f8ac3883.chunk.css.map",
"static/css/main.c2a82e71.chunk.css.map": "/static/css/main.c2a82e71.chunk.css.map",
"static/js/2.f196b75b.chunk.js.LICENSE.txt": "/static/js/2.f196b75b.chunk.js.LICENSE.txt",
"static/media/ClusterIcon.f85713df.svg": "/static/media/ClusterIcon.f85713df.svg",
"static/media/DepositIcon.9688e406.svg": "/static/media/DepositIcon.9688e406.svg"
},
"entrypoints": [
"static/js/runtime-main.8da12c69.js",
"static/js/2.f196b75b.chunk.js",
"static/css/main.c2a82e71.chunk.css",
"static/js/main.01e9ada9.chunk.js"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

View File

@ -1 +1 @@
<!doctype html><html lang="ru"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="white"/><meta name="theme-color" media="(prefers-color-scheme: light)" content="white"/><meta name="theme-color" media="(prefers-color-scheme: dark)" content="black"/><meta name="description" content="Онлайн мониторинг процесса бурения в реальном времени в офисе заказчика"/><title>АСБ Vision</title><script defer="defer" src="/vendors.5c0d0b53.js"></script><script defer="defer" src="/main.05a81b59.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="ru"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="white"/><meta name="theme-color" media="(prefers-color-scheme: light)" content="white"/><meta name="theme-color" media="(prefers-color-scheme: dark)" content="black"/><meta name="description" content="Онлайн мониторинг процесса бурения в реальном времени в офисе заказчика"/><title>DDrilling</title><script defer="defer" src="/vendors.1920da1d.js"></script><script defer="defer" src="/main.101601f2.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -1,15 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<StartupObject>ConsoleApp1.Program</StartupObject>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -1,72 +1,39 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.DailyReport;
using AsbCloudDb;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.DailyReport;
using ClosedXML.Excel;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.EntityFrameworkCore;
using Org.BouncyCastle.Utilities.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
private static AsbCloudDbContext db = ServiceFactory.Context;
// use ServiceFactory to make services
static void Main(/*string[] args*/)
{
var h = new Hashtable();
h.Add("name", 1);
h.Add("name2", "66");
var v = h["v"];
var block = new HeadDto()
{
AzimuthAngle = 12,
WellName = "WellName",
ClusterName = "clusterName",
Customer = "customer",
Contractor = "Contractor",
ReportDate = DateTime.Now,
WellDepthIntervalFinishDate = 27.5,
WellDepthIntervalStartDate = 26.5,
BottomholeDepth = 66.6
};
var block2 = new BhaDto()
{
BHADescription = "sadasdasdasdasdasdjlaskjdaksjdlasdlalskdklj"
};
var block3 = new SaubDto();
var bloks = new DailyReportDto()
{
Head = block,
Saub = block3
};
var s = System.Text.Json.JsonSerializer.Serialize(h);
var service = new DailyReportMakerExcel();
var stream = service.MakeReportFromBlocks(bloks);
var filename = "____.xlsx";
if (File.Exists(filename))
File.Delete(filename);
using var fileStream = File.OpenWrite(filename);
stream.CopyTo(fileStream);
return;
//var ms = MakeReportFromBlocks(block,block3);
////File.Create("", MakeReportFromBlocks(block));
//using var file = new FileStream("file.xlsx", FileMode.Create, System.IO.FileAccess.Write);
//byte[] bytes = new byte[ms.Length];
//ms.Read(bytes, 0, (int)ms.Length);
//file.Write(bytes, 0, bytes.Length);
//ms.Close();
Console.WriteLine($"total time: ms");
Console.ReadLine();
}
}
}