Files
parr_api/PARR.API/Controllers/V1/JobController.cs

253 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests.Queries;
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.Services.Interfaces;
using PARR.DAL.DomainModels;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
namespace PARR.API.Controllers.V1
{
public class JobController : BaseApiController
{
private readonly IMapper mapper;
private readonly IJobService jobService;
//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,
IJobJournalService jobJournalService
)
{
this.mapper = mapper;
this.jobService = jobService;
//this.schedulerService = schedulerService;
this.clientService = clientService;
this.hostService = hostService;
this.jobJournalService = jobJournalService;
}
/// <summary>
/// Список всех jobов постранично в соотвествии с фильтрами
/// </summary>
/// <param name="paginationQuery"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Jobs.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobGetAllQuery filter)
{
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<Job> query = jobService.Get().Include(t => t.JobMode).OrderBy(s => s.StartAt);
if (filter.IsEnabled.HasValue)
query = query.Where(t => t.IsEnabled == filter.IsEnabled);
if (filter.StartDatePlanned.HasValue)
query = query.Where(t => t.StartAt.DateTime.Date <= filter.StartDatePlanned.Value.DateTime.Date); ;
var jobs = await jobService.GetPage(query, paginationFilter).ToListAsync();
if (!jobs.Any())
return NoContent();
var jobResponse = mapper.Map<List<JobGetAllResponse>>(jobs);
var paginationResponse = new PagedResponse<JobGetAllResponse>(jobResponse, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse);
}
/// <summary>
/// Список заданий на запуск по IP-адресу клиента исполнения
/// </summary>
/// <param name="requestQuery"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Jobs.GetByIp)]
public async Task<IActionResult> GetByClientIP([FromQuery] JobGetByIpQuery requestQuery)
{
var ip = requestQuery.Ip ?? clientService.GetClientIp()?.ToString();
if (string.IsNullOrEmpty(ip))
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Client IP address is null." } }));
var date = requestQuery.Date ?? DateTimeOffset.UtcNow;
// С одним IP может быть несколько информационных систем, соответственного а таблице храниться несколько записей хостов с одинаковым IP
var hosts = await hostService.Get().Where(h => h.IP == ip).ToListAsync();
var hostJobsDict = new Dictionary<DAL.Models.Host, List<Job>>();
foreach (var host in hosts)
{
var jobsHost = await 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) && j.IsEnabled && j.StartAt <= date)
.ToListAsync();
if (jobsHost.Any())
{
hostJobsDict.Add(host, jobsHost);
}
}
var jobsList = new List<Job>();
var jobsToResponse = new List<Job>();
foreach (var hostAndJobs in hostJobsDict)
{
foreach (var item in hostAndJobs.Value)
{
if (!jobsList.Contains(item))
{
jobsList.Add(item);
var plannedJobs = await GetListJobsAsync(item, hostAndJobs.Key, date);
jobsToResponse.AddRange(plannedJobs);
}
}
}
jobsToResponse = jobsToResponse.OrderBy(t => t.StartAt).ToList();
if (!jobsToResponse.Any())
return NoContent();
if (requestQuery.IsFullResponse == true)
{
// возврат самого полного ответа
var jobResponse = mapper.Map<List<JobGetAllResponse>>(jobsToResponse);
return Ok(new Response<List<JobGetAllResponse>>(jobResponse, true));
}
// возврат минимального ответа
try
{
return Ok(jobsToResponse.ToDictionary(t => t.ScriptName, d => d.StartAt));
}
catch (ArgumentException ex)
{
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не могу создать json объект с одинаковым значением ключа (ScriptName). {ex.Message}" } }));
}
}
private async Task<List<Job>> GetListJobsAsync(Job job, DAL.Models.Host host, DateTimeOffset queryDate)
{
var jobs = new List<Job>();
#region description
// freaq > суток или нет?
//-----------
// меньше суток
//фрек=10 мин
// старт эт = 17:00 и != сегодня
//цикл 17:00 -10мин пока не начнется вчерашний день
//цикл 17:00 +10мин пока не начентся завтрашний день
// елси страт эт == сегодня
//цикл 17:00 +10мин пока не начентся завтрашний день
//-----------
// ------freaq больше суток--------
// журнал берем последнее событие (че там со статусами? не надо пока), к нему пребавляем фрек, и смотрим == сегодня или нет, если сегодня то добавляем
// --------------
#endregion
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));
var jobToAdded = mapper.Map<Job>(job);//new Job { StartAt = startDateTimeNext };
jobToAdded.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));
var jobToAdded = mapper.Map<Job>(job);
jobToAdded.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)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min - job.Frequency;
}
// прибавляем пока не наступят след сутки
min = startAtMinutes + job.Frequency;
while (min < allDayMinutes)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min + job.Frequency;
}
}
else
{
// = queryDate
// прибавляем пока не наступят след сутки
var min = startAtMinutes;
while (min < allDayMinutes)
{
//var jobToAdded = new Job { StartAt = queryDate.StartOfDay().AddMinutes(min) };
var jobToAdded = mapper.Map<Job>(job);
jobToAdded.StartAt = queryDate.StartOfDay().AddMinutes(min);
jobs.Add(jobToAdded);
min = min + job.Frequency;
}
}
}
return jobs;
}
}
}