diff --git a/AsbCloudApp/Data/Progress/ProgressDto.cs b/AsbCloudApp/Data/Progress/ProgressDto.cs new file mode 100644 index 00000000..3ad2c50a --- /dev/null +++ b/AsbCloudApp/Data/Progress/ProgressDto.cs @@ -0,0 +1,18 @@ +namespace AsbCloudApp.Data.Progress; + +/// +/// DTO прогресса +/// +public class ProgressDto +{ + /// + /// прогресс 0 - 100% + /// + public float Progress { get; set; } + + /// + /// название текущей операции генерации + /// + public string? Operation { get; set; } + +} diff --git a/AsbCloudApp/Data/Progress/ProgressExceptionDto.cs b/AsbCloudApp/Data/Progress/ProgressExceptionDto.cs new file mode 100644 index 00000000..cb264178 --- /dev/null +++ b/AsbCloudApp/Data/Progress/ProgressExceptionDto.cs @@ -0,0 +1,29 @@ +using System; + +namespace AsbCloudApp.Data.Progress; + +/// +/// DTO прогресса с ошибкой +/// +public class ProgressExceptionDto +{ + /// + /// прогресс 0 - 100% + /// + public float Progress { get; set; } + + /// + /// название текущей операции генерации + /// + public string? Operation { get; set; } + + /// + /// Отображаемый текст ошибки + /// + public string Message { get; set; } = null!; + + /// + /// Инфо об исключении + /// + public Exception Exception { get; set; } = null!; +} \ No newline at end of file diff --git a/AsbCloudApp/Data/Progress/ReportProgressDto.cs b/AsbCloudApp/Data/Progress/ReportProgressDto.cs new file mode 100644 index 00000000..b14166e9 --- /dev/null +++ b/AsbCloudApp/Data/Progress/ReportProgressDto.cs @@ -0,0 +1,12 @@ +namespace AsbCloudApp.Data.Progress; + +/// +/// DTO завершенного прогресса генерации рапорта-диаграммы +/// +public class ReportProgressFinalDto : ReportProgressDto +{ + /// + /// файл + /// + public FileInfoDto file { get; set; } +} diff --git a/AsbCloudApp/Data/Progress/ReportProgressFinalDto.cs b/AsbCloudApp/Data/Progress/ReportProgressFinalDto.cs new file mode 100644 index 00000000..b5ce965a --- /dev/null +++ b/AsbCloudApp/Data/Progress/ReportProgressFinalDto.cs @@ -0,0 +1,17 @@ +namespace AsbCloudApp.Data.Progress; + +/// +/// DTO прогресса генерации рапорта-диаграммы +/// +public class ReportProgressDto : ProgressDto +{ + /// + /// номер текущей страницы + /// + public int CurrentPage { get; set; } + + /// + /// предполагаемое суммарное количество страниц + /// + public int TotalPages { get; set; } +} diff --git a/AsbCloudApp/Data/ReportProgressDto.cs b/AsbCloudApp/Data/ReportProgressDto.cs deleted file mode 100644 index c7bf4cbb..00000000 --- a/AsbCloudApp/Data/ReportProgressDto.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace AsbCloudApp.Data -{ - /// - /// DTO прогресса генерации рапорта-диаграммы - /// - public class ReportProgressDto - { - /// - /// прогресс 0 - 100% - /// - public float Progress { get; set; } - - /// - /// название текущей операции генерации - /// - public string? Operation { get; set; } - - /// - /// номер текущей страницы - /// - public int CurrentPage { get; set; } - - /// - /// предполагаемое суммарное количество страниц - /// - public int TotalPages { get; set; } - } -} diff --git a/AsbCloudApp/Services/IReportService.cs b/AsbCloudApp/Services/IReportService.cs index 85d72020..5f992a20 100644 --- a/AsbCloudApp/Services/IReportService.cs +++ b/AsbCloudApp/Services/IReportService.cs @@ -1,4 +1,6 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.Progress; +using AsbCloudApp.Requests; using System; using System.Collections.Generic; using System.Threading; @@ -11,26 +13,30 @@ namespace AsbCloudApp.Services /// public interface IReportService { - /// - /// категория рапорта - /// - int ReportCategoryId { get; } /// /// Поставить рапорт в очередь на формирование /// /// /// - /// - /// - /// - /// + /// /// /// - string EnqueueCreateReportWork(int idWell, int idUser, int stepSeconds, - int format, DateTime begin, DateTime end, + string EnqueueCreateReportWork(int idWell, int idUser, ReportParametersRequest request, Action handleReportProgress); + /// + /// Создание отчета + /// + /// + /// + /// + /// + /// + /// + /// + Task CreateReportAsync(string workId, int idWell, int idUser, ReportParametersRequest request, Action progressHandler, CancellationToken token); + /// /// Получить предполагаемый список страниц рапорта /// diff --git a/AsbCloudInfrastructure/Background/WorkToCreateReport.cs b/AsbCloudInfrastructure/Background/WorkToCreateReport.cs new file mode 100644 index 00000000..f07e7f85 --- /dev/null +++ b/AsbCloudInfrastructure/Background/WorkToCreateReport.cs @@ -0,0 +1,41 @@ +using AsbCloudApp.Data.Progress; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Background; + +/// +/// Класс для создания отчета +/// +internal class WorkToCreateReport : Work +{ + private readonly int idWell; + private readonly int idUser; + private readonly ReportParametersRequest request; + private readonly Action progressHandler; + + public WorkToCreateReport(int idWell, int idUser, ReportParametersRequest request, Action progressHandler) : base("") + { + this.idWell = idWell; + this.idUser = idUser; + this.request = request; + this.progressHandler = progressHandler; + + Id = $"create report by wellid:{idWell} for userid:{idUser} requested at {DateTime.Now}"; + } + + protected override async Task Action(string id, IServiceProvider services, Action onProgress, CancellationToken token) + { + var reportService = services.GetRequiredService(); + void handler(ProgressDto state, string workId) + { + onProgress(state.Operation ?? string.Empty, state.Progress); + progressHandler(state, workId); + } + await reportService.CreateReportAsync(Id, idWell, idUser, request, handler, token); + } +} diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index e1cd558a..3b7199a9 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -1,11 +1,12 @@ using AsbCloudApp.Data; +using AsbCloudApp.Data.Progress; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using AsbCloudInfrastructure.Background; using AsbSaubReport; using Mapster; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.IO; @@ -23,8 +24,6 @@ public class ReportService : IReportService private readonly IWellService wellService; private readonly BackgroundWorker backgroundWorkerService; - public int ReportCategoryId { get; private set; } - public ReportService(IAsbCloudDbContext db, ITelemetryService telemetryService, IWellService wellService, @@ -36,68 +35,14 @@ public class ReportService : IReportService this.backgroundWorkerService = backgroundWorkerService; this.telemetryService = telemetryService; this.fileService = fileService; - ReportCategoryId = db.FileCategories - .AsNoTracking() - .First(c => c.Name.Equals("Рапорт")) - .Id; } - public string EnqueueCreateReportWork(int idWell, int idUser, int stepSeconds, int format, DateTime begin, - DateTime end, Action progressHandler) + public string EnqueueCreateReportWork(int idWell, int idUser, ReportParametersRequest request, Action progressHandler) { - var timezoneOffset = wellService.GetTimezone(idWell).Hours; - var beginUtc = begin.ToUtcDateTimeOffset(timezoneOffset); - var endUtc = end.ToUtcDateTimeOffset(timezoneOffset); - var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset); - var endRemote = end.ToTimeZoneOffsetHours(timezoneOffset); + var work = new WorkToCreateReport(idWell, idUser, request, progressHandler); - var workId = $"create report by wellid:{idWell} for userid:{idUser} requested at {DateTime.Now}"; - - var workAction = async (string id, IServiceProvider serviceProvider, Action onProgress, CancellationToken token) => - { - using var context = serviceProvider.GetRequiredService(); - var fileService = serviceProvider.GetRequiredService(); - - var tempDir = Path.Combine(Path.GetTempPath(), "report"); - - var generator = GetReportGenerator(idWell, beginRemote, endRemote, stepSeconds, format, context); - var reportFileName = Path.Combine(tempDir, generator.GetReportDefaultFileName()); - var totalPages = generator.GetPagesCount(); - - generator.OnProgress += (s, e) => - { - var arg = e.Adapt(); - onProgress(arg.Operation?? string.Empty, arg.Progress); - progressHandler.Invoke(arg, id); - }; - generator.Make(reportFileName); - - var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!; - - progressHandler.Invoke(new - { - Operation = "done", - Progress = 100f, - TotalPages = totalPages, - CurrentPage = totalPages, - file = fileInfo, - }, id); - - var newReportProperties = new ReportProperty - { - IdWell = idWell, - IdFile = fileInfo.Id, - Begin = beginUtc, - End = endUtc, - Step = stepSeconds, - Format = format - }; - context.ReportProperties.Add(newReportProperties); - context.SaveChanges(); - }; - - var work = Work.CreateByDelegate(workId, workAction); - work.OnErrorAsync = (message, exception, token) => Task.Run(() => progressHandler.Invoke(new + work.OnErrorAsync = (message, exception, token) => Task.Run(() => { + var state = new ProgressExceptionDto { Operation = "error", Progress = 100f, @@ -105,8 +50,9 @@ public class ReportService : IReportService ? exception.Message : message, Exception = exception, - }, workId) - , token); + }; + progressHandler.Invoke(state, work.Id); + }, token); backgroundWorkerService.Enqueue(work); @@ -114,8 +60,8 @@ public class ReportService : IReportService { Operation = "Ожидает начала в очереди.", Progress = 0f, - }, workId); - return workId; + }, work.Id); + return work.Id; } public int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int stepSeconds, int format) @@ -172,6 +118,62 @@ public class ReportService : IReportService return dtos; } + public async Task CreateReportAsync( + string workId, + int idWell, + int idUser, + ReportParametersRequest request, + Action progressHandler, + CancellationToken token) + { + var timezoneOffset = wellService.GetTimezone(idWell).Hours; + var beginRemote = request.Begin.ToTimeZoneOffsetHours(timezoneOffset); + var endRemote = request.End.ToTimeZoneOffsetHours(timezoneOffset); + var beginUtc = request.Begin.ToUtcDateTimeOffset(timezoneOffset); + var endUtc = request.End.ToUtcDateTimeOffset(timezoneOffset); + + var tempDir = Path.Combine(Path.GetTempPath(), "report"); + + var generator = GetReportGenerator(idWell, beginRemote, endRemote, request.StepSeconds, request.Format, db); + var reportFileName = Path.Combine(tempDir, generator.GetReportDefaultFileName()); + var totalPages = generator.GetPagesCount(); + + generator.OnProgress += (s, e) => + { + var arg = e.Adapt(); + progressHandler(arg, workId); + }; + generator.Make(reportFileName); + + var ReportCategoryId = db.FileCategories + .AsNoTracking() + .First(c => c.Name.Equals("Рапорт")) + .Id; + + var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!; + + progressHandler(new ReportProgressFinalDto() + { + Operation = "done", + Progress = 100f, + TotalPages = totalPages, + CurrentPage = totalPages, + file = fileInfo, + }, workId); + + var newReportProperties = new ReportProperty + { + IdWell = idWell, + IdFile = fileInfo.Id, + Begin = beginUtc, + End = endUtc, + Step = request.StepSeconds, + Format = request.Format + }; + db.ReportProperties.Add(newReportProperties); + db.SaveChanges(); + } + private static IReportGenerator GetReportGenerator(int idWell, DateTime begin, DateTime end, int stepSeconds, int format, IAsbCloudDbContext context) { @@ -184,7 +186,7 @@ public class ReportService : IReportService _ => new AsbSaubReportPdf.ReprotGeneratorPdf(dataSource), }; - if(begin == default || end == default) + if (begin == default || end == default) { var analyzeResult = dataSource.Analyze(); begin = begin == default ? analyzeResult.MinDate : begin; diff --git a/AsbCloudWebApi/Controllers/ReportController.cs b/AsbCloudWebApi/Controllers/ReportController.cs index ffcc8b9b..ec1b7228 100644 --- a/AsbCloudWebApi/Controllers/ReportController.cs +++ b/AsbCloudWebApi/Controllers/ReportController.cs @@ -65,8 +65,7 @@ namespace AsbCloudWebApi.Controllers .GetReportProgress(progress, token); }, token); - var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser, - request.StepSeconds, request.Format, request.Begin, request.End, HandleReportProgressAsync); + var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser, request, HandleReportProgressAsync); return Ok(id); } diff --git a/AsbCloudWebApi/SignalR/ReportsHub.cs b/AsbCloudWebApi/SignalR/ReportsHub.cs index 5b9aec9b..2bf098f8 100644 --- a/AsbCloudWebApi/SignalR/ReportsHub.cs +++ b/AsbCloudWebApi/SignalR/ReportsHub.cs @@ -54,8 +54,7 @@ namespace AsbCloudWebApi.SignalR .GetReportProgress(progress, CancellationToken.None); }, CancellationToken.None); - var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser, - request.StepSeconds, request.Format, request.Begin, request.End, HandleReportProgressAsync); + var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser, request, HandleReportProgressAsync); } } }