2023-09-22 15:30:57 +10:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.Logging ;
using PARR.BLL.Domain.Mq ;
2023-09-25 11:47:13 +10:00
using PARR.BLL.Helpers ;
2023-11-22 12:04:33 +10:00
using PARR.Constants ;
2023-09-22 15:30:57 +10:00
using PARR.DAL.Contracts ;
2024-03-20 15:26:14 +10:00
using PARR.DAL.Extensions ;
2023-09-25 11:47:13 +10:00
using PARR.DAL.Models ;
2023-09-22 15:30:57 +10:00
using PARR.DAL.Services.Interfaces ;
2024-07-03 12:01:46 +10:00
using PARR.TemplateDistributor ;
2023-09-25 11:47:13 +10:00
using System.Text.Json ;
2023-09-22 15:30:57 +10:00
namespace PARR.GeneratorTemplates.Services
{
internal class TemplateManager : ITemplateManager
{
private readonly ITemplateService templateService ;
2023-09-25 11:47:13 +10:00
private readonly IHostService hostService ;
2023-09-22 15:30:57 +10:00
private readonly ILogger < TemplateManager > logger ;
2023-09-25 11:47:13 +10:00
private readonly SettingsFromDb settingsFromDb ;
2023-10-05 16:56:02 +10:00
private readonly IRobotConfigurationService robotConfigurationService ;
2024-06-04 12:03:15 +10:00
private readonly IApplicationsInWorkService applicationsInWorkService ;
2024-07-03 12:01:46 +10:00
private readonly ITemplateDistributor templateDistributor ;
2023-09-22 15:30:57 +10:00
public TemplateManager (
ITemplateService templateService ,
2023-09-25 11:47:13 +10:00
IHostService hostService ,
ILogger < TemplateManager > logger ,
2023-10-05 16:56:02 +10:00
SettingsFromDb settingsFromDb ,
2024-06-04 12:03:15 +10:00
IRobotConfigurationService robotConfigurationService ,
2024-07-03 12:01:46 +10:00
IApplicationsInWorkService applicationsInWorkService ,
ITemplateDistributor templateDistributor
2023-09-22 15:30:57 +10:00
)
{
this . templateService = templateService ;
2023-09-25 11:47:13 +10:00
this . hostService = hostService ;
2023-09-22 15:30:57 +10:00
this . logger = logger ;
2023-09-25 11:47:13 +10:00
this . settingsFromDb = settingsFromDb ;
2023-10-05 16:56:02 +10:00
this . robotConfigurationService = robotConfigurationService ;
2024-06-04 12:03:15 +10:00
this . applicationsInWorkService = applicationsInWorkService ;
2024-07-03 12:01:46 +10:00
this . templateDistributor = templateDistributor ;
2023-09-22 15:30:57 +10:00
}
public async Task CreateTemplates ( GeneratorTemplateMq query )
{
2024-06-04 12:03:15 +10:00
//В таблице AppInWork находим Р Р , и смотрим е е рабочие группы. Затем по ним будем фильтровать хосты
var appInWorkWg = await applicationsInWorkService . Get ( )
. Include ( t = > t . WorkGroups )
. FirstAsync ( t = > t . ApplicationId = = query . ApplicationId & & t . WorkId = = query . WorkId ) ;
if ( ! appInWorkWg . WorkGroups . Any ( ) )
{
logger . LogWarning ( $"Н е генерирую шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}" ) ;
return ;
}
var workGroups = appInWorkWg . WorkGroups . ToList ( ) ;
2023-09-22 15:30:57 +10:00
//Согласно параметрам, находит все ЭК в таблице Hosts.
2023-09-25 11:47:13 +10:00
//Далее проверяет есть ли такие шаблоны в таблице Templates, если нет, то создает, активирует и ставит статус Creating.
2023-09-22 15:30:57 +10:00
//Если такие шаблоны уже есть, ничего с ними не делает.
2023-09-25 11:47:13 +10:00
string ekPattern = SqlHelpers . RegexToLike ( query . Ek ) ;
// список хостов для создания шаблонов
2023-09-25 15:32:22 +10:00
var queryHosts = hostService . Get ( )
2024-06-04 12:03:15 +10:00
//.Include(t => t.WorkGroupItem)
2023-09-25 11:47:13 +10:00
. Include ( t = > t . ApplicationsInHosts )
. ThenInclude ( t = > t . Application ) . ThenInclude ( t = > t ! . ApplicationsInWorks ) . ThenInclude ( w = > w . Work )
. Include ( t = > t . Templates )
. ThenInclude ( w = > w . ApplicationsInWork )
2024-02-13 13:44:08 +10:00
. Include ( t = > t . ResponseArea )
2023-09-25 11:47:13 +10:00
. Where ( t = >
t . ApplicationsInHosts . Any ( h = >
h . ApplicationId = = query . ApplicationId
& & h . Application ! . ApplicationsInWorks . Any ( w = > w . WorkId = = query . WorkId )
)
& & EF . Functions . Like ( t . Ek . ToLower ( ) , ekPattern )
// смотрим что нет такого шаблона
& & t . Templates . Any ( templ = > templ . ApplicationsInWork ! . WorkId = = query . WorkId & & templ . ApplicationsInWork . ApplicationId = = query . ApplicationId ) = = false
2024-06-04 12:03:15 +10:00
// смотрим что у этих хостов есть нужные группы
//&& workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)
2023-09-25 15:32:22 +10:00
) ;
// статус ЭК
if ( query . StatusEk > 0 )
queryHosts = queryHosts . Where ( t = > t . EkStatusCode = = query . StatusEk ) ;
var hosts = await queryHosts
. AsSplitQuery ( )
. ToListAsync ( ) ;
2023-09-25 11:47:13 +10:00
2024-06-04 12:03:15 +10:00
// Исключаем хосты у которых нет нужных групп
hosts = hosts . Where ( t = > workGroups . Any ( x = > x . WorkGroupId = = t . WorkGroupId ) ) . ToList ( ) ;
2023-09-25 11:47:13 +10:00
if ( ! hosts . Any ( ) )
{
logger . LogInformation ( $"Н е найдено ЭК попадающих под условие: ${JsonSerializer.Serialize(query)}" ) ;
return ;
}
2024-07-03 12:01:46 +10:00
// хосты группируем по РГ, чтоб потом распределить/рассчитать NextRun
var groupingHostByWg = hosts . GroupBy ( t = > t . WorkGroupId ) ;
foreach ( var group in groupingHostByWg )
{
var groupingHosts = group . ToList ( ) ;
var templates = CreateQueryTemplates ( groupingHosts , query ) ;
2024-09-16 09:30:28 +10:00
//проверяем, что нет шаблонов с такими именами, исключаем их
templates = await ExcludeExistTemplatesAsync ( templates ) ;
if ( ! templates . Any ( ) )
continue ;
2024-07-03 12:01:46 +10:00
//заполняем NextRun
2024-07-04 16:44:25 +10:00
templates = await templateDistributor . DistributeTemplateAsync ( templates , appInWorkWg . Id , ( Guid ) group . Key ! ) ;
2024-07-03 12:01:46 +10:00
// сохраняем
foreach ( var template in templates )
{
2024-10-08 10:29:34 +10:00
if ( ! await templateService . CreateAsync ( template ) | | ! await templateService . CommitAsync ( query . HistoryInitiator ) )
2024-07-03 12:01:46 +10:00
{
logger . LogError ( $"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}" ) ;
}
else
{
logger . LogInformation ( $"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
$"HostId: {template.HostId}" ) ;
}
}
}
#region с о з д а в а л и ш а б л о н ы д о т о г о , к а к с т а л и г р у п п и р о в а т ь п о Р Г
////Создаем шаблоны
//foreach (var host in hosts)
//{
// var appInWork = host.ApplicationsInHosts.FirstOrDefault(t => t.ApplicationId == query.ApplicationId)?.Application?.ApplicationsInWorks.FirstOrDefault(a => a.WorkId == query.WorkId);
// if (appInWork == null)
// {
// // такого не может быть, так как выполнился запрос при получении списка хостов, но мало ли
// logger.LogError($"Ошибка при создании шаблона. В таблице ApplicationsInWorks не найден Id согласно запроса WorkId: {query.WorkId}, ApplicationId: {query.ApplicationId}");
// return;
// }
// var template = new Template
// {
// Id = Guid.NewGuid(),
// //Name = TemplateHelpers.GenerateTemplateName("З О " ,settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name),
// //Генерить имя с полным именем работы и подстановкой ЭК
2025-04-16 15:54:50 +10:00
// //Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(host.ResponseArea!.Name, settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)),
2024-07-03 12:01:46 +10:00
// //Вместо полного имени работы, подставляется сокращенный суффикс или полное имя с ЭК если суффикса нет
// Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(
// host.ResponseArea!.Name,
// settingsFromDb.TemplatePrefixName,
// host.Ek,
2025-04-16 15:54:50 +10:00
// appInWork.Work!.TemplateSuffix ?? appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)
2024-07-03 12:01:46 +10:00
// ),
// IsActiveTemplate = query.IsActiveTemplate ?? false,
// IsActiveSchedule = query.IsActiveSchedule ?? false,
// ApplicationInWorkId = appInWork.Id,
// HostId = host.Id,
// //TODO:
// //NextRun = ???,
// LastRun = null
// };
// if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync())
// {
// logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}");
// }
// else
// {
// logger.LogInformation($"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
// $"HostId: {template.HostId}");
// }
//}
#endregion
}
2024-09-16 09:30:28 +10:00
/// <summary>
/// Исключаем существующие шаблоны из запроса на создание
/// </summary>
/// <param name="templates"></param>
/// <returns></returns>
private async Task < List < Template > > ExcludeExistTemplatesAsync ( List < Template > templates )
{
// то ли костыль, то ли нет. Иногда попадают отфильтрованные шаблоны для создания, но они уже есть в БД. Н а всякий проверяем есть они или нет, и если есть, исключаем их из запроса.
// ищмем по имени такие шаблоны в БД и исключаем их
var existTemplates = await templateService . Get ( ) . Where ( t = > templates . Select ( x = > x . Name ) . Any ( x = > x = = t . Name ) ) . ToListAsync ( ) ;
if ( existTemplates . Any ( ) )
{
existTemplates . ForEach ( item = > logger . LogWarning ( $"Исключаем из запроса на создание шаблон, так как он уже есть в БД: {item.Name}" ) ) ;
templates = templates . Where ( t = > ! existTemplates . Any ( x = > x . Name = = t . Name ) ) . ToList ( ) ;
}
return templates ;
}
2024-07-03 12:01:46 +10:00
private List < Template > CreateQueryTemplates ( List < Host > hosts , GeneratorTemplateMq query )
{
var templates = new List < Template > ( ) ;
2023-09-25 11:47:13 +10:00
foreach ( var host in hosts )
{
var appInWork = host . ApplicationsInHosts . FirstOrDefault ( t = > t . ApplicationId = = query . ApplicationId ) ? . Application ? . ApplicationsInWorks . FirstOrDefault ( a = > a . WorkId = = query . WorkId ) ;
if ( appInWork = = null )
{
// такого не может быть, так как выполнился запрос при получении списка хостов, но мало ли
logger . LogError ( $"Ошибка при создании шаблона. В таблице ApplicationsInWorks не найден Id согласно запроса WorkId: {query.WorkId}, ApplicationId: {query.ApplicationId}" ) ;
2024-07-03 12:01:46 +10:00
//return;
return templates ;
2023-09-25 11:47:13 +10:00
}
var template = new Template
{
Id = Guid . NewGuid ( ) ,
2024-02-13 13:44:08 +10:00
//Name = TemplateHelpers.GenerateTemplateName("З О " ,settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name),
2024-06-14 14:27:37 +10:00
//Генерить имя с полным именем работы и подстановкой ЭК
2025-04-16 15:54:50 +10:00
//Name = TemplateHelpers.GenerateTemplateNameWithResponseArea(host.ResponseArea!.Name, settingsFromDb.TemplatePrefixName, host.Ek, appInWork.Work!.Name.ApplyShortcode(Constants.Shortcode.ShortcodeEnum.EK, host.Ek)),
2024-06-14 14:27:37 +10:00
//Вместо полного имени работы, подставляется сокращенный суффикс или полное имя с ЭК если суффикса нет
Name = TemplateHelpers . GenerateTemplateNameWithResponseArea (
2024-07-03 12:01:46 +10:00
host . ResponseArea ! . Name ,
settingsFromDb . TemplatePrefixName ,
host . Ek ,
2025-04-16 15:54:50 +10:00
appInWork . Work ! . TemplateSuffix ? ? appInWork . Work ! . Name . ApplyShortcode ( Constants . Shortcodes . ShortcodeEnum . EK , host . Ek )
2024-06-14 14:27:37 +10:00
) ,
2024-06-13 09:01:02 +10:00
IsActiveTemplate = query . IsActiveTemplate ? ? false ,
IsActiveSchedule = query . IsActiveSchedule ? ? false ,
2023-09-25 11:47:13 +10:00
ApplicationInWorkId = appInWork . Id ,
2024-07-03 12:01:46 +10:00
HostId = host . Id ,
// NextRun не задаем значение, е г о рассчитаем позже
//NextRun = ???,
LastRun = null
2023-09-25 11:47:13 +10:00
} ;
2024-07-03 12:01:46 +10:00
templates . Add ( template ) ;
2023-09-25 11:47:13 +10:00
}
2024-07-03 12:01:46 +10:00
return templates ;
2023-09-22 15:30:57 +10:00
}
2024-07-03 12:01:46 +10:00
2023-09-22 15:30:57 +10:00
public async Task DeactivateTemplates ( GeneratorTemplateMq query )
{
2024-06-13 09:01:02 +10:00
//TODO: !!! тут не учитываются поля query.IsActiveTemplate, query.IsActiveSchedule, просто все деактивируется. !!!
2024-06-04 12:03:15 +10:00
//В таблице AppInWork находим Р Р , и смотрим е е рабочие группы. Затем по ним будем фильтровать хосты
var appInWorkWg = await applicationsInWorkService . Get ( )
. Include ( t = > t . WorkGroups )
. FirstAsync ( t = > t . ApplicationId = = query . ApplicationId & & t . WorkId = = query . WorkId ) ;
if ( ! appInWorkWg . WorkGroups . Any ( ) )
{
logger . LogWarning ( $"Н е деактивируем шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}" ) ;
return ;
}
var workGroups = appInWorkWg . WorkGroups . ToList ( ) ;
2023-09-22 15:30:57 +10:00
//Ищет все активные шаблоны согласно параметрам в таблице Templates, и деактивирует их. Меняем на статус Updating
2023-09-25 11:47:13 +10:00
// делаем sql формат для like из запроса.
string ekPattern = SqlHelpers . RegexToLike ( query . Ek ) ;
2023-09-22 15:30:57 +10:00
2023-09-25 15:32:22 +10:00
var queryTemplates = templateService . Get ( )
2023-09-22 15:30:57 +10:00
. Include ( t = > t . Host )
. Include ( t = > t . ApplicationsInWork )
2023-10-05 16:56:02 +10:00
. Include ( t = > t . RobotConfigurations )
2023-09-22 15:30:57 +10:00
. Where ( t = >
2023-10-05 16:56:02 +10:00
( t . IsActiveTemplate = = true | | t . IsActiveSchedule = = true )
2023-09-22 15:30:57 +10:00
& & t . ApplicationsInWork ! . ApplicationId = = query . ApplicationId
& & t . ApplicationsInWork ! . WorkId = = query . WorkId
2023-09-25 11:47:13 +10:00
& & EF . Functions . Like ( t . Host ! . Ek . ToLower ( ) , ekPattern )
2023-09-25 15:32:22 +10:00
) ;
// статус ЭК
if ( query . StatusEk > 0 )
queryTemplates = queryTemplates . Where ( t = > t . Host ! . EkStatusCode = = query . StatusEk ) ;
var existTemplates = await queryTemplates
. AsSplitQuery ( )
. ToListAsync ( ) ;
2023-09-22 15:30:57 +10:00
2024-06-04 12:03:15 +10:00
// Исключаем хосты у которых нет нужных групп
existTemplates = existTemplates . Where ( t = > workGroups . Any ( x = > x . WorkGroupId = = t . Host . WorkGroupId ) ) . ToList ( ) ;
2023-09-22 15:30:57 +10:00
if ( ! existTemplates . Any ( ) )
{
logger . LogInformation ( "Нет шаблонов для деактивации" ) ;
return ;
}
existTemplates . ForEach ( item = >
{
item . DateModified = DateTimeOffset . UtcNow ;
2023-10-05 16:56:02 +10:00
if ( item . IsActiveTemplate )
{
item . IsActiveTemplate = false ;
//необходимо обновить шаблон
var config = robotConfigurationService . GetFromTemplateByRobotCode ( RobotsEnum . TemplateOrder , ref item ) ;
robotConfigurationService . ChangeTaskStatus ( TaskStatusEnum . Updating , ref config ) ;
}
if ( item . IsActiveSchedule )
{
item . IsActiveSchedule = false ;
//необходимо обновить расписание
var config = robotConfigurationService . GetFromTemplateByRobotCode ( RobotsEnum . ScheduleOrder , ref item ) ;
robotConfigurationService . ChangeTaskStatus ( TaskStatusEnum . Updating , ref config ) ;
}
2023-09-22 15:30:57 +10:00
} ) ;
2024-10-08 10:29:34 +10:00
if ( await templateService . CommitAsync ( query . HistoryInitiator ) )
2023-09-22 15:30:57 +10:00
existTemplates . ForEach ( item = > logger . LogInformation ( $"Деактивирован шаблон: {item.Name}" ) ) ;
else
existTemplates . ForEach ( item = > logger . LogError ( $"Ошибка при дактивации шаблона: {item.Name}" ) ) ;
}
}
}