diff --git a/AsbCloudApp/Data/ReportPropertiesDto.cs b/AsbCloudApp/Data/ReportPropertiesDto.cs deleted file mode 100644 index 0da8a6bf..00000000 --- a/AsbCloudApp/Data/ReportPropertiesDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.IO; - -namespace AsbCloudApp.Data -{ - public class ReportPropertiesDto - { - public FileStream Filestream { get; set; } - public string ContentType { get; set; } - public string FileName { get; set; } - } -} diff --git a/AsbCloudApp/Services/IBackgroundQueue.cs b/AsbCloudApp/Services/IBackgroundQueue.cs new file mode 100644 index 00000000..ae99317b --- /dev/null +++ b/AsbCloudApp/Services/IBackgroundQueue.cs @@ -0,0 +1,11 @@ +using System; + +namespace AsbCloudApp.Services +{ + public interface IBackgroundQueue + { + int EnqueueTask(Action action); + + bool TryDequeue(out (Action action, int id) item); + } +} diff --git a/AsbCloudApp/Services/IReportService.cs b/AsbCloudApp/Services/IReportService.cs index 916f7d89..ee759b8d 100644 --- a/AsbCloudApp/Services/IReportService.cs +++ b/AsbCloudApp/Services/IReportService.cs @@ -5,8 +5,9 @@ namespace AsbCloudApp.Services { public interface IReportService { + string RootPath { get; } + int CreateReport(int wellId, int stepSeconds, int format, DateTime begin, DateTime end); int GetReportPagesCount(int wellId, DateTime begin, DateTime end, int stepSeconds, int format); - ReportPropertiesDto GetReportFileProperties(string reportName, string rootPath); DatesRangeDto GetReportsDatesRange(int wellId); } } diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj index ab446ac9..a934217c 100644 --- a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj +++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj @@ -7,6 +7,7 @@ + @@ -21,4 +22,19 @@ + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index a7a1fd65..b7b4ef6f 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -19,9 +19,12 @@ namespace AsbCloudInfrastructure services.AddScoped(provider => provider.GetService()); + services.AddHostedService(); + services.AddSingleton(new MapperConfiguration(AutoMapperConfig)); services.AddSingleton(new CacheDb()); services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Services/BackgroundQueue.cs b/AsbCloudInfrastructure/Services/BackgroundQueue.cs new file mode 100644 index 00000000..a182bdcd --- /dev/null +++ b/AsbCloudInfrastructure/Services/BackgroundQueue.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Concurrent; +using AsbCloudApp.Services; + +namespace AsbCloudInfrastructure.Services +{ + class BackgroundQueue : IBackgroundQueue + { + private ConcurrentQueue<(Action action, int id)> tasks = + new ConcurrentQueue<(Action action, int id)>(); + + private int id = 0; + + public int EnqueueTask(Action action) + { + if (action == null) + throw new ArgumentNullException(nameof(action)); + + tasks.Enqueue(new(action, id++)); + return id; + } + + public bool TryDequeue(out (Action action, int id) item) + => tasks.TryDequeue(out item); + } +} diff --git a/AsbCloudInfrastructure/Services/BackgroundWorkerService.cs b/AsbCloudInfrastructure/Services/BackgroundWorkerService.cs new file mode 100644 index 00000000..7510cbb8 --- /dev/null +++ b/AsbCloudInfrastructure/Services/BackgroundWorkerService.cs @@ -0,0 +1,40 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using AsbCloudApp.Services; + +namespace AsbCloudInfrastructure.Services +{ + public class BackgroundWorkerService : BackgroundService + { + private readonly IBackgroundQueue tasksQueue; + + public BackgroundWorkerService(IBackgroundQueue tasksQueue) + { + this.tasksQueue = tasksQueue; + } + + protected override async Task ExecuteAsync(CancellationToken token) + { + try + { + while (!token.IsCancellationRequested) + { + if (tasksQueue.TryDequeue(out var item)) + await Task.Run(item.action); + else + await Task.Delay(100, token); + } + } + catch + { + //logger ? + } + } + + public override async Task StopAsync(CancellationToken token) + { + await base.StopAsync(token); + } + } +} diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index c0e26168..bd4cc08c 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -3,6 +3,8 @@ using AsbCloudApp.Data; using AsbCloudDb.Model; using System; using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using AsbSaubReport; namespace AsbCloudInfrastructure.Services @@ -10,35 +12,46 @@ namespace AsbCloudInfrastructure.Services public class ReportService : IReportService { private readonly IAsbCloudDbContext db; + private readonly IConfiguration configuration; private readonly ITelemetryService telemetryService; + private readonly IServiceProvider serviceProvider; + private readonly IBackgroundQueue queue; - public ReportService(IAsbCloudDbContext db, ITelemetryService telemetryService) + public ReportService(IAsbCloudDbContext db, IConfiguration configuration, ITelemetryService telemetryService, IServiceProvider serviceProvider, IBackgroundQueue queue) { this.db = db; + this.configuration = configuration; this.telemetryService = telemetryService; + this.queue = queue; + this.serviceProvider = serviceProvider; + RootPath = "reports"; + } + + public string RootPath { get ; private set; } + + public int CreateReport(int wellId, int stepSeconds, int format, DateTime begin, DateTime end) + { + var newReportId = queue.EnqueueTask(() => + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection")); + + using (var context = new AsbCloudDbContext(optionsBuilder.Options)) + { + var generator = GetReportGenerator(wellId, begin, end, stepSeconds, format, context); + generator.Make(); + } + }); + return newReportId; } public int GetReportPagesCount(int wellId, DateTime begin, DateTime end, int stepSeconds, int format) { - var generator = GetReportGenerator(wellId, begin, end, stepSeconds, format); + var generator = GetReportGenerator(wellId, begin, end, stepSeconds, format, (AsbCloudDbContext)db); return generator.GetPagesCount(); } - public ReportPropertiesDto GetReportFileProperties(string reportName, string rootPath) - { - string path = Path.Combine(rootPath, reportName); - FileStream fs = new FileStream(path, FileMode.Open); - string contentType = Path.GetExtension(path); - string fileName = Path.GetFileName(path); - - return new ReportPropertiesDto { - Filestream = fs, - ContentType = contentType, - FileName = fileName - }; - } - public DatesRangeDto GetReportsDatesRange(int wellId) { var telemetry = telemetryService.GetTelemetryByWellId(wellId); @@ -51,11 +64,11 @@ namespace AsbCloudInfrastructure.Services return new DatesRangeDto { From = result.From, To = result.To }; } - private IReportGenerator GetReportGenerator(int wellId,DateTime begin, DateTime end, int stepSeconds, int format) + private IReportGenerator GetReportGenerator(int wellId, DateTime begin, DateTime end, int stepSeconds, int format, AsbCloudDbContext context) { - var dataSource = new ReportDataSourcePgCloud((AsbCloudDbContext)db, wellId); + var dataSource = new ReportDataSourcePgCloud(context, wellId); var generator = new PdfGenerator(dataSource); - + generator.ReportDirectory = Path.Combine(RootPath, $"{wellId}"); generator.Begin = begin; generator.End = end; generator.Step = TimeSpan.FromSeconds(stepSeconds); diff --git a/AsbCloudWebApi/Controllers/ReportController.cs b/AsbCloudWebApi/Controllers/ReportController.cs index 4f24c98e..118f136e 100644 --- a/AsbCloudWebApi/Controllers/ReportController.cs +++ b/AsbCloudWebApi/Controllers/ReportController.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using System.IO; using Microsoft.AspNetCore.Mvc; using AsbCloudApp.Data; @@ -35,15 +34,13 @@ namespace AsbCloudWebApi.Controllers /// id скважины /// дата начала интервала /// дата окончания интервала - /// шаг интервала + /// шаг интервала /// формат отчета (0-PDF, 1-LASS) /// id фоновой задачи формирования отчета [HttpPost] [Route("{wellId}/report")] [ProducesResponseType(typeof(string), (int)System.Net.HttpStatusCode.OK)] - - // ЭТОТ МЕТОД ПОКА НЕ РЕАЛИЗОВАН - public async Task CreateReportAsync(int wellId, int stepSeconds, int format, DateTime begin = default, DateTime end = default) + public IActionResult CreateReport(int wellId, int stepSeconds, int format, DateTime begin = default, DateTime end = default) { int? idCustomer = User.GetCustomerId(); @@ -53,17 +50,9 @@ namespace AsbCloudWebApi.Controllers if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); - return await Task.Run(() => - { - // создаем отчет. Это заготовка, пока еще не перенесена в сервис. + var id = reportService.CreateReport(wellId, stepSeconds, format, begin, end); - var taskId = Task.CurrentId; - - if (taskId is null) - throw new NullReferenceException("Не удалось получить id задачи"); - - return Ok(taskId.ToString()); - }); + return Ok(id); } /// @@ -86,14 +75,12 @@ namespace AsbCloudWebApi.Controllers if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); - - var options = reportService.GetReportFileProperties(reportName, appEnvironment.ContentRootPath); - - return File(options.Filestream, options.ContentType, options.FileName); + // TODO: словарь content typoв + return PhysicalFile(Path.Combine(reportService.RootPath, $"{wellId}", reportName), "application/pdf", reportName); } catch (FileNotFoundException ex) { - return NotFound("Файл не найден"); + return NotFound($"Файл не найден. Текст ошибки: {ex.Message}"); } } @@ -103,7 +90,7 @@ namespace AsbCloudWebApi.Controllers /// id скважины /// дата начала интервала /// дата окончания интервала - /// шаг интервала + /// шаг интервала /// формат отчета (0-PDF, 1-LASS) /// прогнозируемое кол-во страниц отчета [HttpGet]