From 8747fea11101e439e28e672ce4244440755d648a Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Tue, 20 Jun 2023 16:54:38 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D1=87=20=D0=B4=D0=BB=D1=8F=20=D0=A5=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B0=20=D0=BF=D0=BE=20Ip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../V1/Requests/Queries/JobGetByIpQuery.cs | 4 + PARR.API/Controllers/V1/JobController.cs | 238 ++++++++++++++++-- PARR.API/Extensions/GeneralExtensions.cs | 15 ++ PARR.DAL/Context/DataContext.cs | 8 +- PARR.DAL/Contracts/JobModeEnum.cs | 8 + PARR.DAL/Contracts/JobStatusEnum.cs | 8 + PARR.DAL/Models/JobJournal.cs | 2 +- PARR.DAL/ParrDalInstaller.cs | 1 + .../Implementations/JobJournalService.cs | 10 + .../Services/Interfaces/IJobJournalService.cs | 9 +- 10 files changed, 274 insertions(+), 29 deletions(-) create mode 100644 PARR.API/Extensions/GeneralExtensions.cs create mode 100644 PARR.DAL/Contracts/JobModeEnum.cs create mode 100644 PARR.DAL/Contracts/JobStatusEnum.cs diff --git a/PARR.API/Contracts/V1/Requests/Queries/JobGetByIpQuery.cs b/PARR.API/Contracts/V1/Requests/Queries/JobGetByIpQuery.cs index 9e110976..8326e9e4 100644 --- a/PARR.API/Contracts/V1/Requests/Queries/JobGetByIpQuery.cs +++ b/PARR.API/Contracts/V1/Requests/Queries/JobGetByIpQuery.cs @@ -4,5 +4,9 @@ { public string? Ip { get; set; } public DateTimeOffset? Date { get; set; } + ///// + ///// Возвращает jobs которые ещё не выполнены + ///// + //public bool? IsPlanned { get; set; } } } diff --git a/PARR.API/Controllers/V1/JobController.cs b/PARR.API/Controllers/V1/JobController.cs index f7445c29..6ac762ab 100644 --- a/PARR.API/Controllers/V1/JobController.cs +++ b/PARR.API/Controllers/V1/JobController.cs @@ -7,7 +7,9 @@ using PARR.API.Contracts.V1.Responses; using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Controllers.V1.Base; using PARR.API.Extensions; +using PARR.API.MappingProfiles; using PARR.API.Services.Interfaces; +using PARR.DAL.Contracts; using PARR.DAL.DomainModels; using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; @@ -23,12 +25,14 @@ namespace PARR.API.Controllers.V1 //private readonly ISchedulerService schedulerService; private readonly IClientService clientService; private readonly IHostService hostService; + private readonly IJobJournalService jobJournalService; public JobController( IMapper mapper, IJobService jobService, IClientService clientService, - IHostService hostService + IHostService hostService, + IJobJournalService jobJournalService ) { this.mapper = mapper; @@ -36,6 +40,7 @@ namespace PARR.API.Controllers.V1 //this.schedulerService = schedulerService; this.clientService = clientService; this.hostService = hostService; + this.jobJournalService = jobJournalService; } @@ -67,7 +72,6 @@ namespace PARR.API.Controllers.V1 return Ok(paginationResponse); } - [HttpGet(ApiRoutes.Jobs.GetByIp)] public async Task GetByClientIP([FromQuery] JobGetByIpQuery requestQuery) { @@ -84,31 +88,229 @@ namespace PARR.API.Controllers.V1 { var jobsHost = await jobService.Get() .Include(a => a.Application).ThenInclude(ah => ah.ApplicationsInHosts)/*.ThenInclude(h => h.Host)*/ - .Include(jm=>jm.JobMode) + .Include(jm => jm.JobMode) .AsSplitQuery() - .Where(j => j.Application != null && j.Application.ApplicationsInHosts.Any(ah => ah.HostId == host.Id)) + .Where(j => j.Application != null && j.Application.ApplicationsInHosts.Any(ah => ah.HostId == host.Id) && j.IsEnabled) .ToListAsync(); - if (jobsHost.Any()) - hostJobsDict.Add(host, jobsHost); - } - //hostJobsDict.Values.Distinct(); - var jobsJoined = new List(); - foreach(var job in hostJobsDict.Values) - { - job.ForEach(item => + if (jobsHost.Any()) { - jobsJoined.Add(item); + hostJobsDict.Add(host, jobsHost); + } + } + + var jobsList = new List(); + var response = new Dictionary(); + foreach (var hostAndJobs in hostJobsDict) + { + hostAndJobs.Value.ForEach(async item => + { + if (!jobsList.Contains(item)) + { + jobsList.Add(item); + + + var plannedJobs = await GetListJobsAsync(item, hostAndJobs.Key, date); + + //todo:!!! эти списки склеивать в один, отсортировать по дате и перегнать в дикт + + //var baseTime = new DateTimeOffset(date.Year, date.Year, 01, 0, 0, 0, new TimeSpan(0)); + ////если более суток то идём в JobJournal и получаем дату последнегно запуска. Если нет то приравниваем к StartAt + //var freq = item.Frequency; + //if (true) + //{ + + //} + //var curTimeCreation = baseTime; + + //while(curTimeCreation <= curTimeCreation.EndOfDay()) + //{ + + // curTimeCreation=curTimeCreation.DateTime.AddMinutes(freq); + //} + + + + + + //kaskjdhaskjkjasklhd + } }); } - if (!jobsJoined.Any()) - return NoContent(); - - var jobResponse = mapper.Map>(jobsJoined.Distinct()); + // var jobListForResponse = new - return Ok(new Response>(jobResponse, true, new List(), $"{ip},{date}")); + + //var dic = new Dictionary(); + //dic.Add("sss1", "222"); + //dic.Add("sss2", "333"); + return Ok(); } + + private async Task> GetListJobsAsync(Job job, DAL.Models.Host host, DateTimeOffset queryDate) + { + var jobs = new List(); + + + // freaq > суток или нет? + + //----------- + // меньше суток + //фрек=10 мин + // старт эт = 17:00 и != сегодня + + //цикл 17:00 -10мин пока не начнется вчерашний день + //цикл 17:00 +10мин пока не начентся завтрашний день + + // елси страт эт == сегодня + //цикл 17:00 +10мин пока не начентся завтрашний день + + //----------- + + // ------freaq больше суток-------- + // журнал берем последнее событие (че там со статусами? не надо пока), к нему пребавляем фрек, и смотрим == сегодня или нет, если сегодня то добавляем + // -------------- + + + var allDayMinutes = 1440; + if (job.Frequency >= allDayMinutes) + { + //больше или = суток + + var lastJournalItem = await jobJournalService.GetLastAsync(job.Id, host.Id, queryDate); + if (lastJournalItem == null) + { + // если в истории нет записей, то запускаем сегодня в стартЭт + // берем квери дэйт и ем задаем время из Джобс СтартЭт + var startDateTimeNext = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, job.StartAt.Hour, job.StartAt.Minute, job.StartAt.Second, new TimeSpan(0)); + //todo: + var jobToAdded = new Job { StartAt = startDateTimeNext }; + jobs.Add(jobToAdded); + } + else + { + var startDateNext = lastJournalItem.DateOper.DateTime.AddMinutes(job.Frequency); + if (startDateNext.Date == queryDate.DateTime.Date) + { + // если берем прошлую последнюю операцию из журнала, и к ней прибавить фрекунси, то время следующего старта сдвинется на время выполнения прошлого задания + // чтобы это избежать, берем квери дэйт и ем задаем время из Джобс СтартЭт + var startDateTimeNext = new DateTimeOffset(queryDate.Year, queryDate.Month, queryDate.Day, job.StartAt.Hour, job.StartAt.Minute, job.StartAt.Second, new TimeSpan(0)); + //todo: + var jobToAdded = new Job { StartAt = startDateTimeNext }; + jobs.Add(jobToAdded); + } + } + } + else + { + //меньше суток + var startAtMinutes = (job.StartAt - job.StartAt.StartOfDay()).TotalMinutes; + + // если дата старта != queryDate + if (job.StartAt.DateTime.Date != queryDate.DateTime.Date) + { + // отнимаем пока не наступили прошлые стуки + var min = startAtMinutes; + while (min > 0) + { + //TODO + var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) }; + jobs.Add(jobToAdded); + min = min - job.Frequency; + } + + // прибавляем пока не наступят след сутки + while (min <= allDayMinutes) + { + //TODO + var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) }; + jobs.Add(jobToAdded); + min = min + job.Frequency; + } + } + else + { + // = queryDate + // прибавляем пока не наступят след сутки + var min = startAtMinutes; + while (min <= allDayMinutes) + { + //TODO + var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) }; + jobs.Add(jobToAdded); + min = min + job.Frequency; + } + } + } + + return jobs; + } + + + //[HttpGet(ApiRoutes.Jobs.GetByIp)] + //public async Task GetByClientIP([FromQuery] JobGetByIpQuery requestQuery) + //{ + // var ip = requestQuery.Ip ?? clientService.GetClientIp()?.ToString(); + // if (string.IsNullOrEmpty(ip)) + // return BadRequest(new Response(false, new List { new ErrorModel { Message = "Client IP address is null." } })); + + // var date = requestQuery.Date ?? DateTimeOffset.Now; + + // // С одним IP может быть несколько информационных систем, соответственного а таблице храниться несколько записей хостов с одинаковым IP + // var hosts = await hostService.Get().Where(h => h.IP == ip).ToListAsync(); + // var hostJobsDict = new Dictionary>(); + // foreach (var host in hosts) + // { + // var jobsHostQuery = jobService.Get() + // .Include(a => a.Application).ThenInclude(ah => ah.ApplicationsInHosts)/*.ThenInclude(h => h.Host)*/ + // .Include(jm => jm.JobMode) + // .AsSplitQuery() + // .Where(j => j.Application != null && j.Application.ApplicationsInHosts.Any(ah => ah.HostId == host.Id)); + + // if (requestQuery.IsPlanned == true) + // { + // // ототбражем только включенные + // jobsHostQuery = jobsHostQuery.Where(t => t.IsEnabled == true); + // } + + // var jobsHost = await jobsHostQuery.ToListAsync(); + + + // if (requestQuery.IsPlanned == true) + // { + // // смотрим в истории, если задание уже было запущено, то его не отображаем + // foreach (var jobItem in jobsHost) + // { + // var journalItem = await jobJournalService.GetLastAsync(jobItem.Id, host.Id, date); + // if (JobStatusEnum.started) { } + // } + // } + + // if (jobsHost.Any()) + // { + // //Проверяем Job вк + // hostJobsDict.Add(host, jobsHost); + // } + // } + // //hostJobsDict.Values.Distinct(); + + // var jobsJoined = new List(); + // foreach (var job in hostJobsDict.Values) + // { + // job.ForEach(item => + // { + // jobsJoined.Add(item); + // }); + // } + + // if (!jobsJoined.Any()) + // return NoContent(); + + // var jobResponse = mapper.Map>(jobsJoined.Distinct()); + + // return Ok(new Response>(jobResponse, true, new List(), $"{ip},{date}")); + //} + } } diff --git a/PARR.API/Extensions/GeneralExtensions.cs b/PARR.API/Extensions/GeneralExtensions.cs new file mode 100644 index 00000000..46c941e6 --- /dev/null +++ b/PARR.API/Extensions/GeneralExtensions.cs @@ -0,0 +1,15 @@ +namespace PARR.API.Extensions +{ + public static class GeneralExtensions + { + public static DateTimeOffset EndOfDay(this DateTimeOffset date) + { + return new DateTimeOffset(date.Year, date.Month, date.Day, 23, 59, 59, 999, new TimeSpan(0)); + } + + public static DateTimeOffset StartOfDay(this DateTimeOffset date) + { + return new DateTimeOffset(date.Year, date.Month, date.Day, 0, 0, 0, 0, new TimeSpan(0)); + } + } +} diff --git a/PARR.DAL/Context/DataContext.cs b/PARR.DAL/Context/DataContext.cs index 704c0357..96c0fa77 100644 --- a/PARR.DAL/Context/DataContext.cs +++ b/PARR.DAL/Context/DataContext.cs @@ -31,16 +31,16 @@ namespace PARR.DAL.Context modelBuilder.Entity(f => { f.HasData( - new() { Id = new Guid("FBA4202C-5BAD-49C4-B076-D1CA6E1FB158"), DateCreated = dateCreated, DateModified = null, Name = "auto" }, - new() { Id = new Guid("7516B952-510D-4AAA-971C-A14B184FC1D5"), DateCreated = dateCreated, DateModified = null, Name = "manual" } + new() { Id = new Guid("FBA4202C-5BAD-49C4-B076-D1CA6E1FB158"), DateCreated = dateCreated, DateModified = null, Name = JobModeEnum.auto.ToString() }, + new() { Id = new Guid("7516B952-510D-4AAA-971C-A14B184FC1D5"), DateCreated = dateCreated, DateModified = null, Name = JobModeEnum.manual.ToString() } ); }); modelBuilder.Entity(f => { f.HasData( - new() { Id = new Guid("EDEF6DC3-ADAD-4C77-8AD1-63BB9052355A"), DateCreated = dateCreated, DateModified = null, Name = "started", Description = "Задание запущено" }, - new() { Id = new Guid("7B945EB6-D885-4570-AFF5-8866F1F75FF2"), DateCreated = dateCreated, DateModified = null, Name = "finished", Description = "Задание выполнено" } + new() { Id = new Guid("EDEF6DC3-ADAD-4C77-8AD1-63BB9052355A"), DateCreated = dateCreated, DateModified = null, Name = JobStatusEnum.started.ToString(), Description = "Задание запущено" }, + new() { Id = new Guid("7B945EB6-D885-4570-AFF5-8866F1F75FF2"), DateCreated = dateCreated, DateModified = null, Name = JobStatusEnum.finished.ToString(), Description = "Задание выполнено" } ); }); diff --git a/PARR.DAL/Contracts/JobModeEnum.cs b/PARR.DAL/Contracts/JobModeEnum.cs new file mode 100644 index 00000000..98bc70b7 --- /dev/null +++ b/PARR.DAL/Contracts/JobModeEnum.cs @@ -0,0 +1,8 @@ +namespace PARR.DAL.Contracts +{ + public enum JobModeEnum + { + auto, + manual + } +} diff --git a/PARR.DAL/Contracts/JobStatusEnum.cs b/PARR.DAL/Contracts/JobStatusEnum.cs new file mode 100644 index 00000000..456cf3f2 --- /dev/null +++ b/PARR.DAL/Contracts/JobStatusEnum.cs @@ -0,0 +1,8 @@ +namespace PARR.DAL.Contracts +{ + public enum JobStatusEnum + { + started, + finished + } +} diff --git a/PARR.DAL/Models/JobJournal.cs b/PARR.DAL/Models/JobJournal.cs index 40c60982..4f2d7c94 100644 --- a/PARR.DAL/Models/JobJournal.cs +++ b/PARR.DAL/Models/JobJournal.cs @@ -11,7 +11,7 @@ namespace PARR.DAL.Models public Guid Id { get; set; } public DateTimeOffset DateCreated { get; set; } public DateTimeOffset? DateModified { get; set; } - public string? DateOper { get; set; } + public DateTimeOffset DateOper { get; set; } public string? Other { get; set; } //Возможно нужно перенести в Job public int? TimeOut { get; set; } diff --git a/PARR.DAL/ParrDalInstaller.cs b/PARR.DAL/ParrDalInstaller.cs index 949db860..5bd3117f 100644 --- a/PARR.DAL/ParrDalInstaller.cs +++ b/PARR.DAL/ParrDalInstaller.cs @@ -20,6 +20,7 @@ namespace PARR.DAL services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); //services.AddTransient(); //services.AddTransient(); diff --git a/PARR.DAL/Services/Implementations/JobJournalService.cs b/PARR.DAL/Services/Implementations/JobJournalService.cs index 8519208d..e007f059 100644 --- a/PARR.DAL/Services/Implementations/JobJournalService.cs +++ b/PARR.DAL/Services/Implementations/JobJournalService.cs @@ -20,5 +20,15 @@ namespace PARR.DAL.Services.Implementations protected override DbSet EntitySet => dataContext.JobJournals; protected override DataContext EntitiContext => dataContext; + + public async Task GetLastAsync(Guid jobId, Guid hostId, DateTimeOffset date) + { + var opers = await EntitySet + .Where(j => j.JobId == jobId && j.HostId == hostId && j.DateOper.DateTime.Date == date.DateTime.Date) + .OrderBy(t => t.DateOper) + .LastOrDefaultAsync(); + + return opers; + } } } diff --git a/PARR.DAL/Services/Interfaces/IJobJournalService.cs b/PARR.DAL/Services/Interfaces/IJobJournalService.cs index 523b38bb..e6876f3d 100644 --- a/PARR.DAL/Services/Interfaces/IJobJournalService.cs +++ b/PARR.DAL/Services/Interfaces/IJobJournalService.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using PARR.DAL.Models; namespace PARR.DAL.Services.Interfaces { - internal interface IJobJournalService + public interface IJobJournalService { + Task GetLastAsync(Guid jobId, Guid hostId, DateTimeOffset date); } }