using AsbCloudApp.Data; 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; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services { public class ReportService : IReportService { private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; private readonly FileService fileService; private readonly IWellService wellService; private readonly BackgroundWorker backgroundWorkerService; public int ReportCategoryId { get; private set; } public ReportService(IAsbCloudDbContext db, ITelemetryService telemetryService, IWellService wellService, FileService fileService, BackgroundWorker backgroundWorkerService) { this.db = db; this.wellService = wellService; 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) { 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 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); backgroundWorkerService.Enqueue(work); progressHandler.Invoke(new ReportProgressDto { Operation = "Ожидает начала в очереди.", Progress = 0f, }, workId); return workId; } public int GetReportPagesCount(int idWell, DateTime begin, DateTime end, int stepSeconds, int format) { var timezoneOffset = wellService.GetTimezone(idWell).Hours; var beginRemote = begin.ToTimeZoneOffsetHours(timezoneOffset); var endRemote = end.ToTimeZoneOffsetHours(timezoneOffset); var generator = GetReportGenerator(idWell, beginRemote, endRemote, stepSeconds, format, db); var pagesCount = generator.GetPagesCount(); return pagesCount; } public DatesRangeDto? GetDatesRangeOrDefault(int idWell) { var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); if (telemetry is null) return null; var range = telemetryService.GetDatesRange(telemetry.Id); return range; } public async Task> GetAllReportsByWellAsync(int idWell, CancellationToken token) { var timezoneOffset = wellService.GetTimezone(idWell).Hours; var propertiesQuery = db.ReportProperties.Include(r => r.File) .Where(p => p.IdWell == idWell) .OrderBy(o => o.File.UploadDate) .AsNoTracking() .Take(1024); var entities = await propertiesQuery.ToListAsync(token); var dtos = entities.Select(p => new ReportPropertiesDto { Id = p.Id, Name = p.File.Name, File = new FileInfoDto { Id = p.File.Id, Author = null, IdAuthor = p.File.IdAuthor ?? 0, IdCategory = p.File.IdCategory, IdWell = p.File.IdWell, Name = p.File.Name, Size = p.File.Size, UploadDate = p.File.UploadDate.ToRemoteDateTime(timezoneOffset), }, IdWell = p.IdWell, Date = p.File.UploadDate.ToRemoteDateTime(timezoneOffset), Begin = p.Begin.ToRemoteDateTime(timezoneOffset), End = p.End.ToRemoteDateTime(timezoneOffset), Step = p.Step, Format = p.Format == 0 ? ".pdf" : ".las" }); return dtos; } private static IReportGenerator GetReportGenerator(int idWell, DateTime begin, DateTime end, int stepSeconds, int format, IAsbCloudDbContext context) { var dataSource = new ReportDataSourcePgCloud(context, idWell); IReportGenerator generator = format switch { //LAS 1 => new AsbSaubReportLas.ReprotGeneratorLas(dataSource), //PDF _ => new AsbSaubReportPdf.ReprotGeneratorPdf(dataSource), }; if(begin == default || end == default) { var analyzeResult = dataSource.Analyze(); begin = begin == default ? analyzeResult.MinDate : begin; end = end == default ? begin.AddDays(1) : end; } generator.Begin = begin; generator.End = end; generator.Step = TimeSpan.FromSeconds(stepSeconds); generator.WithCharts = true; generator.WithEvents = true; return generator; } public async Task DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token) { var lifeTimeStartDate = DateTime.UtcNow.Date - lifetime; var fileIds = await db.ReportProperties .Where(r => r.File.UploadDate.Date < lifeTimeStartDate) .Select(r => r.IdFile) .ToArrayAsync(token); return await fileService.DeleteAsync(fileIds, token); } } }