Files
parr_api/PARR.AIHITSyncer/Services/SyncerService.cs

450 lines
18 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 Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using PARR.DAL.Contracts;
using PARR.DAL.Extensions;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using System.Text.RegularExpressions;
namespace PARR.AIHITSyncer.Services
{
internal class SyncerService : ISyncerService
{
private readonly ILogger<SyncerService> logger;
private readonly IHostService hostService;
private readonly IApplicationService appService;
private readonly IApplicationInHostService appInHostService;
private readonly IApplicationTypeService appTypeService;
private readonly ITransformService transformService;
private readonly IWorkGroupService workGroupService;
public List<ApplicationType> AppTypes { get; private set; } = new List<ApplicationType>();
public SyncerService(
ILogger<SyncerService> logger,
IHostService hostService,
IApplicationService appService,
IApplicationInHostService appInHostService,
IApplicationTypeService appTypeService,
ITransformService transformService,
IWorkGroupService workGroupService
)
{
this.logger = logger;
this.hostService = hostService;
this.appService = appService;
this.appInHostService = appInHostService;
this.appTypeService = appTypeService;
this.transformService = transformService;
this.workGroupService = workGroupService;
}
public async Task SyncAsync(string msg)
{
await GetAppTypesAsync();
var objFromQuery = transformService.GetModelFromJson<AihitDataMq>(msg);
if (objFromQuery == null)
return;
await SyncHostAsync(objFromQuery);
}
private async Task SyncHostAsync(AihitDataMq objFromQuery)
{
//ищем существующий хост в БД
//var host = await hostService.GetHostWithAppsByIpAsync(objFromQuery.IP);
var host = await hostService.GetHostWithAppsByEkAsync(objFromQuery.EK);
var isNew = false;
//если не нашли - создаём
if (host == null)
{
isNew = true;
host = await CreateHostAsync(objFromQuery);
}
else
{
logger.LogDebug($"Найден хост в БД: {host!.Ek}({host.IP})");
//проверям и обновляем поля
await SyncHostFieldsAsync(host, objFromQuery);
}
//получаем лист ПО из объекта
var appsInObj = await GetAppsInObjectAsync(host, objFromQuery);
await SyncApplicationInHostAsync(host, appsInObj, !isNew);
}
private async Task<Host?> CreateHostAsync(AihitDataMq objFromQuery)
{
var id = Guid.NewGuid();
int responseAreaCode = GetResponseAreaCodeFromStr(objFromQuery.ResponseArea) ?? 0;
if (responseAreaCode == 0)
return null;
var host = new Host
{
Id = id,
Ek = objFromQuery.EK,
IP = objFromQuery.IP,
EkStatusCode = ResolveCode(objFromQuery.Status),
//WorkGroup = objFromQuery.WorkGroup,
WorkGroup = await CreateWorkGroupIfNotExistAsync(objFromQuery.WorkGroup, objFromQuery.WorkGroupResponseArea),
// ResponseAreaCode = ((ResolveCode(objFromQuery.ResponseArea) == 0) ? 99 : ResolveCode(objFromQuery.ResponseArea))
ResponseAreaCode = responseAreaCode
};
if (!await hostService.CreateAsync(host) || !await hostService.CommitAsync())
logger.LogError($"Не удалось создать узел {host.Ek}({host.IP})");
else
logger.LogInformation($"----- Создан узел: {host.Id} -----");
//return await hostService.GetHostWithAppsByIpAsync(host.IP);
return await hostService.GetHostWithAppsByEkAsync(host.Ek);
}
private async Task<WorkGroup?> CreateWorkGroupIfNotExistAsync(string? workGroupName, string wgResponseArea)
{
if (string.IsNullOrEmpty(workGroupName) || string.IsNullOrWhiteSpace(workGroupName))
return null;
if (string.IsNullOrEmpty(wgResponseArea) || string.IsNullOrWhiteSpace(wgResponseArea))
return null;
int wgCode = GetResponseAreaCodeFromStr(wgResponseArea) ?? 0;
if (wgCode == 0)
return null;
var existWorkGroup = await workGroupService.GetByNameAsync(workGroupName);
if (existWorkGroup != null)
{
//проверяем, соответствует ли рабочая группа
if (existWorkGroup.ResponseAreaCode != wgCode)
{
logger.LogDebug($"У рабочей группы {existWorkGroup.Name} не совпадают ЗО, обновляем, текущее значение: {existWorkGroup.ResponseAreaCode}, новое: {wgCode}");
existWorkGroup.ResponseAreaCode = wgCode;
if (!await workGroupService.CommitAsync())
{
logger.LogError($"Ошибка при обновлении ЗО рабочей группы {existWorkGroup.Name}");
}
}
return existWorkGroup;
}
var workGroup = new WorkGroup
{
Id = Guid.NewGuid(),
Name = workGroupName.Trim(),
ResponseAreaCode = wgCode
};
if (!await workGroupService.CreateAsync(workGroup) || !await workGroupService.CommitAsync())
logger.LogError($"Не удалось создать запись в таблице WorkGroups: {workGroupName}, {workGroup.ToJson()}");
else
logger.LogInformation($"Создана запись а таблице WorkGroups: {workGroupName}, {workGroup.ToJson()}");
return await workGroupService.GetAsync(workGroup.Id); ;
}
private async Task SyncHostFieldsAsync(Host host, AihitDataMq objFromQuery)
{
var isChanged = false;
if (host.IP != objFromQuery.IP)
{
host.IP = objFromQuery.IP;
isChanged = true;
}
if (host.EkStatusCode != ResolveCode(objFromQuery.Status))
{
host.EkStatusCode = ResolveCode(objFromQuery.Status);
isChanged = true;
}
//TODO Удалить после перехода на самостоятельный объект WorkGroup
//if (objFromQuery.WorkGroup != null && (host.WorkGroup == null || !host.WorkGroup!.Equals(objFromQuery.WorkGroup)))
//{
// host.WorkGroup = objFromQuery.WorkGroup;
// isChanged = true;
//}
if (objFromQuery.WorkGroup != null && (host.WorkGroup == null || !host.WorkGroup!.Name.Equals(objFromQuery.WorkGroup)))
{
host.WorkGroup = await CreateWorkGroupIfNotExistAsync(objFromQuery.WorkGroup, objFromQuery.WorkGroupResponseArea);
isChanged = true;
}
int responseAreaCode = GetResponseAreaCodeFromStr(objFromQuery.ResponseArea) ?? 0;
if (responseAreaCode == 0) {
logger.LogWarning($"Ошибка при получении ЗО хоста: {objFromQuery.EK}, ЗО: {objFromQuery.ResponseArea}");
return;
}
//if (host.ResponseAreaCode != ((ResolveCode(objFromQuery.ResponseArea) == 0) ? 99 : ResolveCode(objFromQuery.ResponseArea)))
if (host.ResponseAreaCode != responseAreaCode)
{//TODO Возможно проще выгружать с помощью INCLUDE зону ответственности и сравнивать string
//host.ResponseAreaCode = ((ResolveCode(objFromQuery.ResponseArea) == 0) ? 99 : ResolveCode(objFromQuery.ResponseArea));
host.ResponseAreaCode = responseAreaCode;
isChanged = true;
}
if (isChanged)
{
host.DateModified = DateTimeOffset.UtcNow;
if (!await hostService.CommitAsync())
logger.LogError($"Не удалось обновить узел {host.Ek}({host.IP})");
else
logger.LogInformation($"Обновлён Host: {host.Ek}({host.Id})");
}
}
private async Task<List<Application>> GetAppsInObjectAsync(Host? host, AihitDataMq objFromQuery)
{
var applications = new List<Application>();
if (objFromQuery.APP != null)
{
var appList = ParseAppsList(objFromQuery.APP);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.APP);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.DB != null)
{
var appList = ParseAppsList(objFromQuery.DB);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.DB);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.CKBS != null)
{
var appList = ParseAppsList(objFromQuery.CKBS);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.CKBS);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.IB != null)
{
var appList = ParseAppsList(objFromQuery.IB);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.IB);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.SI != null)
{
var appList = ParseAppsList(objFromQuery.SI);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.SI);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.SM != null)
{
var appList = ParseAppsList(objFromQuery.SM);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.SM);
if (created != null)
applications.Add(created);
}
}
if (objFromQuery.OS != null)
{
var appList = ParseAppsList(objFromQuery.OS);
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.OS);
if (created != null)
applications.Add(created);
}
}
return applications;
}
private List<string> ParseAppsList(string appStr)
{
var regex = new Regex("\\([^)]*\\)");
if (regex.IsMatch(appStr))
foreach (var parenthesis in regex.Matches(appStr))
{
if (!string.IsNullOrEmpty(parenthesis.ToString()))
{
var newParenthesis = parenthesis.ToString()!.Replace(",", "<|>").Replace(";", "<|>");
appStr = appStr.Replace(parenthesis!.ToString()!, newParenthesis);
}
}
return appStr.Split(new char[] { ',', ';' }).Select(a => a.Replace("<|>", ",")).Distinct().ToList();
}
private async Task<Application?> CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type)
{
if (string.IsNullOrEmpty(appName) || string.IsNullOrWhiteSpace(appName)) return null;
var appType = GetAppTypeByName(type);
if (appType == null)
{
logger.LogError($"Не удалось создать запись в таблице Applications: {appName}, так как не получил AppType: {type.ToString()}");
return null;
}
var existApp = await appService.GetByNameAsync(appName, appType.Id);
if (existApp != null)
return existApp;
//Создаем
var app = new Application
{
Id = Guid.NewGuid(),
Name = appName.Trim(),
ApplicationTypeId = appType.Id
};
if (!await appService.CreateAsync(app) || !await appService.CommitAsync())
logger.LogError($"Не удалось создать запись в таблице Application: {appName}, {app.ToJson()}");
else
logger.LogInformation($"Создана запись а таблице Application: {appName}, {app.ToJson()}");
return await appService.GetAsync(app.Id);
}
/// <summary>
/// Метод синхронизации
/// </summary>
/// <param name="host">Хост</param>
/// <param name="hostApplications">Список программного обеспечения</param>
/// <param name="isUpdateDateModified">Признак обновления поля DateModified</param>
/// <returns></returns>
private async Task SyncApplicationInHostAsync(Host? host, List<Application> appsInObject, bool isUpdateDateModified = false)
{
var isUpdated = false;
if (host == null)
return;
logger.LogDebug($"Host: {host.Ek}({host.IP}), начало синхронизации приложений ({appsInObject.Count()}) ");
foreach (var appInObject in appsInObject)
{
var exist = host.ApplicationsInHosts.FirstOrDefault(a => a.ApplicationId == appInObject.Id);
if (exist == null)
{
//add
logger.LogInformation($"Host: {host.Ek}({host.IP}), добавление нового приложения Application {appInObject.Name}");
var newAppHost = new ApplicationInHost { Id = Guid.NewGuid(), ApplicationId = appInObject.Id, HostId = host.Id };
if (!await appInHostService.CreateAsync(newAppHost))
logger.LogError($"Не удалось создать ApplicationInHost {appInObject.Name}, host: {host.Ek}({host.IP})");
isUpdated = true;
}
}
foreach (var appInHost in host.ApplicationsInHosts)
{
var appToRemove = appsInObject.FirstOrDefault(a => a.Id == appInHost.ApplicationId);
if (appToRemove == null)
{
//todo remove appToRemove
var obj = await appInHostService.Get().FirstOrDefaultAsync(t => t.ApplicationId == appInHost.ApplicationId && t.HostId == host.Id);
if (obj != null)
{
logger.LogInformation($"Host: {host.Ek}({host.IP}), удаление неактуального приложения Application {appInHost.Application?.Name}");
appInHostService.Delete(obj);
if (!await appInHostService.CommitAsync())
logger.LogError($"Не удалось удалить Application {appInHost.Application?.Name} узла {host.Ek}({host.IP})");
isUpdated = true;
}
}
}
if (isUpdated && isUpdateDateModified)
host.DateModified = DateTimeOffset.UtcNow;
if (!await appInHostService.CommitAsync())
logger.LogError($"Не удалось обновить ApplicationInHost для Host: {host.Ek}({host.IP})");
logger.LogDebug($"Host: {host.Ek}({host.IP} конец синхронизации приложений");
}
private ApplicationType? GetAppTypeByName(ApplicationTypesEnum type)
{
var existType = AppTypes.FirstOrDefault(t => t.Name == type.ToString());
if (existType == null)
logger.LogError($"Не найден AppType: {type}");
return existType;
}
/// <summary>
/// Возвращает первую цифру из строки, котроая является кодом статуса или зоны ответственности для ЭК
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
private int ResolveCode(string field)
{
var pattern = "\\d+";
var regex = new Regex(pattern);
int.TryParse(regex.Match(field).Value, out int result);
return result;
}
private int? GetResponseAreaCodeFromStr(string responseAreaStr)
{
if (string.IsNullOrEmpty(responseAreaStr) || string.IsNullOrWhiteSpace(responseAreaStr))
return null;
if (responseAreaStr.ToUpper().Trim() == "ОБЩЕЕ")
return (int)ResponseAreaEnum.general;
if (responseAreaStr.ToUpper().Trim() == "00-ГВЦ")
return (int)ResponseAreaEnum.gvc;
return ResolveCode(responseAreaStr);
}
private async Task GetAppTypesAsync()
{
if (AppTypes == null || AppTypes.Count == 0)
AppTypes = await appTypeService.Get().ToListAsync();
}
}
}