Files
parr_api/PARR.AIHIT/AIHIT/Syncher.cs

623 lines
28 KiB
C#
Raw Normal View History

2023-06-05 16:28:36 +10:00
using AutoMapper;
using MailKit.Search;
2023-06-01 16:08:25 +10:00
using Microsoft.EntityFrameworkCore;
2023-06-01 12:30:38 +10:00
using Microsoft.Extensions.Logging;
2023-06-05 16:28:36 +10:00
using MimeKit;
2023-08-23 16:57:38 +10:00
using PARR.AIHIT.Services;
2023-06-01 12:30:38 +10:00
using PARR.AIHIT.Settings;
2023-06-13 13:57:55 +10:00
using PARR.DAL.Contracts;
using PARR.DAL.Extensions;
using PARR.DAL.Models;
using PARR.DAL.Models.AIHIT;
using PARR.DAL.Models.V1;
2023-06-01 16:08:25 +10:00
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.AIHIT;
using PARR.DAL.Services.Interfaces.V1;
2023-06-01 12:30:38 +10:00
using PARR.Mail.Services;
2023-06-05 16:28:36 +10:00
using System.Text;
using System.Xml;
2023-06-01 12:30:38 +10:00
namespace PARR.AIHIT
{
2023-06-01 16:08:25 +10:00
internal class Syncher : ISyncher
2023-06-01 12:30:38 +10:00
{
private readonly ILogger<Syncher> logger;
private readonly IMailService mailService;
private readonly SyncherSettings syncherSettings;
private readonly V1_IHostService V1_hostService;
private readonly V1_IApplicationInHostService V1_appInHostService;
private readonly V1_IApplicationService V1_appService;
2023-06-01 16:08:25 +10:00
private readonly IHostService hostService;
2023-06-05 16:28:36 +10:00
private readonly IMapper mapper;
2023-06-13 13:57:55 +10:00
private readonly IApplicationService appService;
private readonly IApplicationTypeService appTypeService;
private readonly IApplicationInHostService appInHostService;
private readonly IRawDataEKService rawDataEKService;
private readonly ISettingService settingService;
2023-08-23 16:57:38 +10:00
private readonly IAIHITService aihitService;
2023-06-13 13:57:55 +10:00
public List<ApplicationType> AppTypes { get; private set; } = new List<ApplicationType>();
2023-06-01 12:30:38 +10:00
2023-06-05 16:28:36 +10:00
public Syncher(
ILogger<Syncher> logger,
IMailService mailService,
SyncherSettings syncherSettings,
V1_IHostService V1_hostService,
V1_IApplicationService V1_appService,
V1_IApplicationTypeService V1_appTypeService,
V1_IApplicationInHostService V1_appInHostService,
2023-06-05 16:28:36 +10:00
IHostService hostService,
2023-06-13 13:57:55 +10:00
IMapper mapper,
IApplicationService appService,
IApplicationTypeService appTypeService,
IApplicationInHostService appInHostService,
IRawDataEKService rawDataEKService,
2023-08-23 16:57:38 +10:00
ISettingService settingService,
IAIHITService aihitService
2023-06-05 16:28:36 +10:00
)
2023-06-01 12:30:38 +10:00
{
2023-06-01 16:08:25 +10:00
this.hostService = hostService;
2023-06-05 16:28:36 +10:00
this.mapper = mapper;
2023-06-13 13:57:55 +10:00
this.appService = appService;
this.appTypeService = appTypeService;
this.appInHostService = appInHostService;
this.rawDataEKService = rawDataEKService;
this.settingService = settingService;
2023-08-23 16:57:38 +10:00
this.aihitService = aihitService;
2023-06-01 12:30:38 +10:00
this.logger = logger;
this.mailService = mailService;
this.syncherSettings = syncherSettings;
this.V1_hostService = V1_hostService;
this.V1_appService = V1_appService;
this.V1_appInHostService = V1_appInHostService;
2023-06-01 12:30:38 +10:00
}
2023-06-13 13:57:55 +10:00
private async Task GetAppTypesAsync()
{
AppTypes = await appTypeService.Get().ToListAsync();
}
2023-06-01 12:30:38 +10:00
public async Task InvokeAsync()
{
2023-06-13 13:57:55 +10:00
await GetAppTypesAsync();
2023-06-15 10:14:27 +10:00
2023-06-01 12:30:38 +10:00
var messages = await mailService.CheckMailAsync(SearchQuery.NotSeen);
if (!messages.Any())
{
return;
}
2023-06-13 13:57:55 +10:00
var filtered = messages.Where(m => syncherSettings.IncludeAddressesArray.Any(i => m.Envelope.From.Mailboxes.FirstOrDefault()?.Address == i)).ToList();
2023-06-05 16:28:36 +10:00
var lastMessage = filtered.OrderByDescending(f => f.Date).First();
var attachments = await mailService.GetAttachmentsAsync(lastMessage);
2023-06-15 10:14:27 +10:00
2023-06-05 16:28:36 +10:00
foreach (var attachment in attachments)
{
if (attachment is MessagePart)
{
continue;
}
else
{
2023-06-13 13:57:55 +10:00
using var stream = new MemoryStream();
2023-06-05 16:28:36 +10:00
((MimePart)attachment).Content.DecodeTo(stream);
if (stream.Position > 0) stream.Position = 0;
var fileName = EncodeString(((MimePart)attachment).FileName);
logger.LogInformation($" Получен файл {fileName}");
if (fileName.Equals("Компонентный состав регионального ЭК.xml"))
{
XmlDocument doc = new XmlDocument();
doc.Load(stream);
var vms = doc.GetElementsByTagName("Сведения");
//var hosts = await hostService.Get().ToListAsync();
foreach (XmlNode vm in vms)
{
var ip = vm?.Attributes?["IP_АДРЕС"]?.Value.Trim();
if (ip == null) continue;
var regionalEK = vm!.Attributes!["РЕГИОНАЛЬНЫЙ_ЭК"]!.Value.Trim();
2023-06-13 13:57:55 +10:00
var linkEK = vm!.Attributes!["СВЯЗАННЫЙ_ЭК"]!.Value.Trim();
if (!linkEK.StartsWith("ВРТ")) continue;
2023-06-05 16:28:36 +10:00
2023-06-13 13:57:55 +10:00
// var foundHost = await hostService.GetHostAsync(ip, linkEK, regionalEK);
var foundHost = await V1_hostService.GetHostWithAppsAsync(ip, linkEK, regionalEK);
var mappedHost = mapper.Map<V1_Host>(vm);
2023-06-05 16:28:36 +10:00
var hostApplications = await V1_GetAndFillApplicationsAsync(vm);
2023-06-13 13:57:55 +10:00
if (foundHost == null)
{
// создаем
if (!await V1_hostService.CreateAsync(mappedHost) || !await V1_hostService.CommitAsync())
2023-06-13 13:57:55 +10:00
{
logger.LogError($"Не удалось создать узел {mappedHost.IP} {mappedHost.RegionalEK}");
continue;
}
else
logger.LogInformation($"----- Создан Host: {mappedHost.Id}, {mappedHost.LinkEK} -----");
// Синхронизация Applications
await V1_SyncApplicationAndHostAsync(foundHost, hostApplications);
2023-06-13 13:57:55 +10:00
}
else
2023-06-05 16:28:36 +10:00
{
2023-06-13 13:57:55 +10:00
// обновляем
2023-06-05 16:28:36 +10:00
var isChanged = false;
if (!foundHost.RegionalEK!.Equals(mappedHost.RegionalEK))
{
foundHost.RegionalEK = mappedHost.RegionalEK; isChanged = true;
}
else if (!foundHost.LinkEK!.Equals(mappedHost.LinkEK))
{
foundHost.LinkEK = mappedHost.LinkEK;
isChanged = true;
}
else if (!foundHost.Status!.Equals(mappedHost.Status))
{
foundHost.Status = mappedHost.Status;
isChanged = true;
}
else if (!foundHost.WorkGroup!.Equals(mappedHost.WorkGroup))
{
foundHost.WorkGroup = mappedHost.WorkGroup;
isChanged = true;
}
else if (!foundHost.Responsible!.Equals(mappedHost.Responsible))
{
foundHost.Responsible = mappedHost.Responsible;
isChanged = true;
}
2023-06-13 13:57:55 +10:00
//else if (!foundHost.OS!.Equals(mappedHost.OS))
//{
// foundHost.OS = mappedHost.OS;
// isChanged = true;
//}
//else if (!foundHost.DB!.Equals(mappedHost.DB))
//{
// foundHost.DB = mappedHost.DB;
// isChanged = true;
//}
//else if (!foundHost.APP!.Equals(mappedHost.APP))
//{
// foundHost.APP = mappedHost.APP;
// isChanged = true;
//}
if (isChanged)
2023-06-05 16:28:36 +10:00
{
2023-06-13 13:57:55 +10:00
foundHost.DateModified = DateTimeOffset.UtcNow;
if (!await V1_hostService.CommitAsync())
2023-06-13 13:57:55 +10:00
logger.LogError($"Не удалось обновить узел {mappedHost.IP} {mappedHost.RegionalEK}");
else
logger.LogInformation($"----- Обновлён Host: {mappedHost.Id}, {mappedHost.LinkEK} -----");
2023-06-05 16:28:36 +10:00
}
2023-06-13 13:57:55 +10:00
// Синхронизация Applications
await V1_SyncApplicationAndHostAsync(foundHost, hostApplications, true);
2023-06-05 16:28:36 +10:00
}
}
}
break;
}
}
//прочитано для всех
2023-06-01 16:08:25 +10:00
foreach (var message in filtered)
2023-06-01 12:30:38 +10:00
{
2023-06-05 16:28:36 +10:00
await mailService.SetAsSeenAsync(message);
2023-06-01 12:30:38 +10:00
}
}
2023-06-05 16:28:36 +10:00
public async Task InvokeFromDatabase()
{
await GetAppTypesAsync();
2023-08-23 15:47:20 +10:00
//Получаем зоны ответственности из БД
var respAreas = await settingService.Get()
.Where(ra => ra.Group == AIHTITSettings.RespAreaGroupName)
.ToListAsync();
#if !DEBUG
//Запускаем хранимую процедуру в АИХ ИТ и складываем в таблицу RawDataEKs, предварительно почистив старые данные
foreach (var respArea in respAreas)
{
var eksFromAIHIT = aihitService.GetEKList(respArea.Value)?.ToList();
if (eksFromAIHIT == null)
continue;
//Удаляем текущие данные по зоне ответственности respArea
var toDelete = rawDataEKService.Get().Where(rd => rd.ResponseArea == respArea.Value).ToList();
toDelete.ForEach(d => rawDataEKService.Delete(d));
if(!await rawDataEKService.CommitAsync())
{
logger.LogError($"Не удалось создать удалить записи в rawDataEK зоны ответственности {respArea.Name}");
continue;
}
foreach (var ek in eksFromAIHIT)
{
// создаем
var mappedEK = mapper.Map<RawDataEK>(ek);
mappedEK.Id = Guid.NewGuid();
mappedEK.DateCreated = DateTimeOffset.UtcNow;
2023-08-23 15:47:20 +10:00
//if (!await rawDataEKService.CreateAsync(mappedEK) || !await rawDataEKService.CommitAsync())
if (!await rawDataEKService.CreateAsync(mappedEK))
{
logger.LogError($"Не удалось создать запись rawDataEK {mappedEK.ShortName}({mappedEK.IP})");
continue;
}
else
logger.LogInformation($"----- Создана запись rawDataEK {mappedEK.ShortName}({mappedEK.IP}), зона ответственности {respArea.Name} -----");
}
if (await rawDataEKService.CommitAsync())
logger.LogError($"Информация о хостах зоны ответственности {respArea.Name} не записана ");
}
#endif
//Разбираем сырые данные
//Получаем интересующие статусы ЭК
var statusList = await settingService.Get()
.Where(s => s.Group == AIHTITSettings.StatusGroupName)
.Select(s => s.Value.Trim())
.ToListAsync();
if (statusList == null || statusList.Count == 0)
return;
//Берём только активные шаблоны
var eks = await rawDataEKService.Get()
.Where(e => e.IsActive == "t" && (e.Status != null && statusList.Contains(e.Status.Trim())))
.ToListAsync();
foreach (var ek in eks)
{
if (ek.IP == null)
continue;
var foundHost = await hostService.GetHostWithAppsAsync(ek.IP);
var mappedHost = mapper.Map<Host>(ek);
2023-09-28 14:59:48 +10:00
//TODO Валидация по внешним связям
var hostApplications = await GetAndFillApplicationsAsync(ek);
if (foundHost == null)
{
// создаем
if (!await hostService.CreateAsync(mappedHost) || !await hostService.CommitAsync())
{
logger.LogError($"Не удалось создать узел {mappedHost.IP}");
continue;
}
else
logger.LogInformation($"----- Создан Host: {mappedHost.Id} -----");
// Синхронизация Applications
await SyncApplicationAndHostAsync(foundHost, hostApplications);
}
else
{
// обновляем
var isChanged = false;
if (!foundHost.EkStatusCode!.Equals(mappedHost.EkStatusCode))
{
foundHost.EkStatusCode = mappedHost.EkStatusCode;
isChanged = true;
}
2023-08-23 16:57:38 +10:00
else if (mappedHost.WorkGroup != null && !foundHost.WorkGroup!.Equals(mappedHost.WorkGroup))
{
foundHost.WorkGroup = mappedHost.WorkGroup;
isChanged = true;
}
if (isChanged)
{
foundHost.DateModified = DateTimeOffset.UtcNow;
if (!await hostService.CommitAsync())
logger.LogError($"Не удалось обновить узел {mappedHost.IP}");
else
logger.LogInformation($"----- Обновлён Host: {mappedHost.Id} -----");
}
// Синхронизация Applications
await SyncApplicationAndHostAsync(foundHost, hostApplications, true);
}
}
}
private async Task V1_SyncApplicationAndHostAsync(V1_Host? host, List<V1_Application> hostApplications, bool isUpdateDateModified = false)
2023-06-05 16:28:36 +10:00
{
2023-06-13 13:57:55 +10:00
var isUpdated = false;
if (host == null)
return;
logger.LogInformation($"--- Host: {host.Id}, {host.LinkEK} начало синхронизации приложений ({hostApplications.Count()}) ---");
foreach (var changedHostApp in hostApplications)
{
var exist = host.ApplicationsInHosts.FirstOrDefault(a => a.ApplicationId == changedHostApp.Id);
if (exist == null)
{
//add
logger.LogInformation($"Host: {host.Id}, {host.LinkEK} добавление нового приложения Application {changedHostApp.Name}");
var newAppHost = new V1_ApplicationInHost { Id = Guid.NewGuid(), ApplicationId = changedHostApp.Id, HostId = host.Id };
if (!await V1_appInHostService.CreateAsync(newAppHost))
2023-06-13 13:57:55 +10:00
logger.LogError($"Не удалось создать ApplicationInHost {changedHostApp.Name}, host: {host.Id}, {host.LinkEK}");
isUpdated = true;
}
}
foreach (var app in host.ApplicationsInHosts)
{
var appToRemove = hostApplications.FirstOrDefault(a => a.Id == app.Id);
if (appToRemove == null)
{
//todo remove appToRemove
var obj = await V1_appInHostService.Get().FirstOrDefaultAsync(t => t.ApplicationId == app.Id && t.HostId == host.Id);
2023-06-13 13:57:55 +10:00
if (obj != null)
{
logger.LogInformation($"Host: {host.Id}, {host.LinkEK} удаление неактуального приложения Application {app.Application?.Name}");
V1_appInHostService.Delete(obj);
2023-06-13 13:57:55 +10:00
isUpdated = true;
}
}
}
if (isUpdated && isUpdateDateModified)
host.DateModified = DateTimeOffset.UtcNow;
if (!await appInHostService.CommitAsync())
logger.LogError($"Не удалось обновить ApplicationInHost для Host: {host.LinkEK}, {host.Id}");
logger.LogInformation($"=== Host: {host.Id}, {host.LinkEK} конец синхронизации приложений ===");
}
private async Task<List<V1_Application>> V1_GetAndFillApplicationsAsync(XmlNode vm)
2023-06-13 13:57:55 +10:00
{
logger.LogInformation($"--- Начало парсинга данных о программном обеспечении(СП, БД, ОС) из Xml документа от АИХ ИТ ---");
var applications = new List<V1_Application>();
2023-06-13 13:57:55 +10:00
//TODO GetAppFromXML(vm?.Attributes?["СП"]?.Value).ForEach(async item => await CreateAppIfNotExistAsync(item, ApplicationTypesEnum.APP));
//GetDBFromXML(vm?.Attributes?["СУБД"]?.Value).ForEach(async item => await CreateAppIfNotExistAsync(item, ApplicationTypesEnum.DB));
//GetOSFromXML(vm?.Attributes?["ОС"]?.Value).ForEach(async item => await CreateAppIfNotExistAsync(item, ApplicationTypesEnum.OS));
var appList = GetAppFromXML(vm?.Attributes?["СП"]?.Value);
foreach (var app in appList)
{
var created = await V1_CreateAppIfNotExistAsync(app, ApplicationTypesEnum.APP);
2023-06-13 13:57:55 +10:00
if (created != null)
applications.Add(created);
}
var dbList = GetAppFromXML(vm?.Attributes?["СУБД"]?.Value);
foreach (var db in dbList)
{
var created = await V1_CreateAppIfNotExistAsync(db, ApplicationTypesEnum.DB);
2023-06-13 13:57:55 +10:00
if (created != null)
applications.Add(created);
}
var osList = GetAppFromXML(vm?.Attributes?["ОС"]?.Value);
foreach (var os in appList)
{
var created = await V1_CreateAppIfNotExistAsync(os, ApplicationTypesEnum.OS);
2023-06-13 13:57:55 +10:00
if (created != null)
applications.Add(created);
}
logger.LogInformation($"=== Конец парсинга данных о программном обеспечении(СП, БД, ОС) из Xml документа от АИХ ИТ ===");
return applications;
}
private async Task SyncApplicationAndHostAsync(Host? host, List<Application> hostApplications, bool isUpdateDateModified = false)
{
var isUpdated = false;
if (host == null)
return;
logger.LogInformation($"--- Host: {host.Id}, начало синхронизации приложений ({hostApplications.Count()}) ---");
foreach (var changedHostApp in hostApplications)
{
var exist = host.ApplicationsInHosts.FirstOrDefault(a => a.ApplicationId == changedHostApp.Id);
if (exist == null)
{
//add
logger.LogInformation($"Host: {host.Id}, добавление нового приложения Application {changedHostApp.Name}");
var newAppHost = new ApplicationInHost { Id = Guid.NewGuid(), ApplicationId = changedHostApp.Id, HostId = host.Id };
if (!await appInHostService.CreateAsync(newAppHost))
logger.LogError($"Не удалось создать ApplicationInHost {changedHostApp.Name}, host: {host.Id}");
isUpdated = true;
}
}
foreach (var app in host.ApplicationsInHosts)
{
var appToRemove = hostApplications.FirstOrDefault(a => a.Id == app.Id);
if (appToRemove == null)
{
//todo remove appToRemove
var obj = await appInHostService.Get().FirstOrDefaultAsync(t => t.ApplicationId == app.Id && t.HostId == host.Id);
if (obj != null)
{
logger.LogInformation($"Host: {host.Id}, удаление неактуального приложения Application {app.Application?.Name}");
appInHostService.Delete(obj);
isUpdated = true;
}
}
}
if (isUpdated && isUpdateDateModified)
host.DateModified = DateTimeOffset.UtcNow;
if (!await appInHostService.CommitAsync())
logger.LogError($"Не удалось обновить ApplicationInHost для Host: {host.Id}");
logger.LogInformation($"=== Host: {host.Id} конец синхронизации приложений ===");
}
private async Task<List<Application>> GetAndFillApplicationsAsync(RawDataEK vm)
{
logger.LogInformation($"--- Начало парсинга данных о программном обеспечении(СП, БД, ОС) из АИХ ИТ ---");
var applications = new List<Application>();
if (vm.APPType != null)
{
var appList = vm.APPType.Split(new char[] { ',', ';' }).Distinct().ToList();
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.APP);
if (created != null)
applications.Add(created);
}
}
if (vm.DBType != null)
{
var appList = vm.DBType.Split(new char[] { ',', ';' }).Distinct().ToList();
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.DB);
if (created != null)
applications.Add(created);
}
}
if (vm.OSType != null)
{
var appList = vm.OSType.Split(new char[] { ',', ';' }).Distinct().ToList();
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.OS);
if (created != null)
applications.Add(created);
}
}
logger.LogInformation($"=== Конец парсинга данных о программном обеспечении(СП, БД, ОС) из АИХ ИТ ===");
return applications;
}
2023-06-13 13:57:55 +10:00
private List<string> GetAppFromXML(string? appField)
{
if (string.IsNullOrEmpty(appField))
return new List<string>();
var appList = appField.Split(";").Distinct().ToList();
//appList.ForEach(item => item.Trim());
return appList;
2023-06-05 16:28:36 +10:00
}
2023-06-13 13:57:55 +10:00
private List<string> GetDBFromXML(string? dbField)
{
if (string.IsNullOrEmpty(dbField))
return new List<string>();
var dbList = dbField.Split(";").Distinct().ToList();
//dbList.ForEach(item => item.Trim());
return dbList;
}
private List<string> GetOSFromXML(string? osField)
{
if (string.IsNullOrEmpty(osField))
return new List<string>();
var osList = osField.Split(";").Distinct().ToList();
//osList.ForEach(item => item.Trim());
return osList;
}
private async Task<V1_Application?> V1_CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type)//Application application)
{
if (string.IsNullOrEmpty(appName) || string.IsNullOrWhiteSpace(appName)) return null;
var existApp = await V1_appService.GetByNameAsync(appName);
if (existApp != null)
return existApp;
//Создаем
var appType = GetAppTypeByName(type);
if (appType == null)
{
logger.LogError($"Не удалось создать запись в таблице Applications: {appName}, так как не получил AppType: {type.ToString()}");
return null;
}
var app = new V1_Application
{
Id = Guid.NewGuid(),
Name = appName.Trim(),
ApplicationTypeId = appType.Id
};
if (!await V1_appService.CreateAsync(app) || !await V1_appService.CommitAsync())
logger.LogError($"Не удалось создать запись в таблице Application: {appName}, {app.ToJson()}");
else
logger.LogInformation($"Создана запись а таблице Application: {appName}, {app.ToJson()}");
return await V1_appService.GetAsync(app.Id);
}
private async Task<Application?> CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type)//Application application)
2023-06-13 13:57:55 +10:00
{
2023-06-20 13:51:00 +10:00
if (string.IsNullOrEmpty(appName) || string.IsNullOrWhiteSpace(appName)) return null;
2023-06-13 13:57:55 +10:00
var existApp = await appService.GetByNameAsync(appName);
2023-06-13 13:57:55 +10:00
if (existApp != null)
return existApp;
//Создаем
var appType = GetAppTypeByName(type);
if (appType == null)
{
logger.LogError($"Не удалось создать запись в таблице Applications: {appName}, так как не получил AppType: {type.ToString()}");
return null;
}
var app = new Application
2023-06-13 13:57:55 +10:00
{
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);
}
private ApplicationType? GetAppTypeByName(ApplicationTypesEnum type)
2023-06-13 13:57:55 +10:00
{
var existType = AppTypes.FirstOrDefault(t => t.Name == type.ToString());
if (existType == null)
logger.LogError($"Не найден AppType: {type}");
return existType;
}
2023-06-05 16:28:36 +10:00
private static string EncodeString(string str)
{
byte[] bStr = Encoding.GetEncoding("koi8r").GetBytes(str);
Encoding encoding = Encoding.GetEncoding("koi8r");
str = encoding.GetString(bStr, 0, bStr.Length);
return str;
}
2023-06-01 12:30:38 +10:00
}
}