using AutoMapper; using MailKit.Search; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using MimeKit; using PARR.AIHIT.Context; using PARR.AIHIT.Settings; using PARR.DAL.Contracts; using PARR.DAL.Extensions; using PARR.DAL.Models.AIHIT; using PARR.DAL.Models.V1; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.AIHIT; using PARR.Mail.Services; using System.Text; using System.Xml; namespace PARR.AIHIT { internal class Syncher : ISyncher { private readonly ILogger logger; private readonly IMailService mailService; private readonly SyncherSettings syncherSettings; private readonly IHostService hostService; private readonly IMapper mapper; private readonly IApplicationService appService; private readonly IApplicationTypeService appTypeService; private readonly IApplicationInHostService appInHostService; private readonly IRawDataEKService rawDataEKService; public List AppTypes { get; private set; } = new List(); public Syncher( ILogger logger, IMailService mailService, SyncherSettings syncherSettings, IHostService hostService, IMapper mapper, IApplicationService appService, IApplicationTypeService appTypeService, IApplicationInHostService appInHostService, IRawDataEKService rawDataEKService ) { this.hostService = hostService; this.mapper = mapper; this.appService = appService; this.appTypeService = appTypeService; this.appInHostService = appInHostService; this.rawDataEKService = rawDataEKService; this.logger = logger; this.mailService = mailService; this.syncherSettings = syncherSettings; } private async Task GetAppTypesAsync() { AppTypes = await appTypeService.Get().ToListAsync(); } public async Task InvokeAsync() { await GetAppTypesAsync(); var messages = await mailService.CheckMailAsync(SearchQuery.NotSeen); if (!messages.Any()) { return; } var filtered = messages.Where(m => syncherSettings.IncludeAddressesArray.Any(i => m.Envelope.From.Mailboxes.FirstOrDefault()?.Address == i)).ToList(); var lastMessage = filtered.OrderByDescending(f => f.Date).First(); var attachments = await mailService.GetAttachmentsAsync(lastMessage); foreach (var attachment in attachments) { if (attachment is MessagePart) { continue; } else { using var stream = new MemoryStream(); ((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(); var linkEK = vm!.Attributes!["СВЯЗАННЫЙ_ЭК"]!.Value.Trim(); if (!linkEK.StartsWith("ВРТ")) continue; // var foundHost = await hostService.GetHostAsync(ip, linkEK, regionalEK); var foundHost = await hostService.GetHostWithAppsAsync(ip, linkEK, regionalEK); var mappedHost = mapper.Map(vm); var hostApplications = await GetAndFillApplicationsAsync(vm); if (foundHost == null) { // создаем if (!await hostService.CreateAsync(mappedHost) || !await hostService.CommitAsync()) { logger.LogError($"Не удалось создать узел {mappedHost.IP} {mappedHost.RegionalEK}"); continue; } else logger.LogInformation($"----- Создан Host: {mappedHost.Id}, {mappedHost.LinkEK} -----"); // Синхронизация Applications await SyncApplicationAndHostAsync(foundHost, hostApplications); } else { // обновляем 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; } //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) { foundHost.DateModified = DateTimeOffset.UtcNow; if (!await hostService.CommitAsync()) logger.LogError($"Не удалось обновить узел {mappedHost.IP} {mappedHost.RegionalEK}"); else logger.LogInformation($"----- Обновлён Host: {mappedHost.Id}, {mappedHost.LinkEK} -----"); } // Синхронизация Applications await SyncApplicationAndHostAsync(foundHost, hostApplications, true); } //host.DateModified = ... //var host = new PARR.DAL.Models.Host //{ // HostName = "", // IP = vm!.Attributes["IP_АДРЕС"]!.Value, // RegionalEK = vm?.Attributes?["РЕГИОНАЛЬНЫЙ_ЭК"]?.Value, // LinkEK = vm?.Attributes?["СВЯЗАННЫЙ_ЭК"]?.Value, // Status = vm?.Attributes?["СТАТУС"]?.Value, // WorkGroup = vm?.Attributes?["РАБОЧАЯ_ГР_ОТВ_ЗА_ЭК"]?.Value, // Responsible = vm?.Attributes?["ОТВЕТСТВЕННЫЙ_ЗА_ЭК"]?.Value, // OS = vm?.Attributes?["ОС"]?.Value, // DB = vm?.Attributes?["СУБД"]?.Value, // APP = vm?.Attributes?["СП"]?.Value, //}; //logger.LogInformation($"Запись сервера {mappedHost.IP}, региональный ЭК {mappedHost.RegionalEK}"); //if (String.IsNullOrEmpty(host.Status) || !host.Status.Equals("3-В эксплуатации")) continue; //if (String.IsNullOrEmpty(host.IP)) continue; } } break; } } //прочитано для всех foreach (var message in filtered) { await mailService.SetAsSeenAsync(message); } } public async Task InvokeFromDatabase() { var eksFromAIHIT = new List(); //call procedure using (AIHContext db = new AIHContext()) { var zo = new Microsoft.Data.SqlClient.SqlParameter { ParameterName = "@зо", SqlDbType = System.Data.SqlDbType.NVarChar, Direction = System.Data.ParameterDirection.Input, Size = 60, Value = "96-ДВС" }; eksFromAIHIT = db.EKs.FromSqlRaw($"EXEC mao2.dbo.sp_IPP_PARR_PTK_get_EK @зо", zo).ToList(); } if (!eksFromAIHIT.Any()) { logger.LogWarning($"Процедура sp_IPP_PARR_PTK_get_EK вурнула пустой список ЭК"); return; } rawDataEKService.DeleteAll(); foreach (var ek in eksFromAIHIT) { // создаем var mappedEK = mapper.Map(ek); if (!await rawDataEKService.CreateAsync(mappedEK) || !await rawDataEKService.CommitAsync()) { logger.LogError($"Не удалось создать запись rawDataEK {mappedEK.ShortName}({mappedEK.IP})"); continue; } else logger.LogInformation($"----- Создана запись rawDataEK {mappedEK.ShortName}({mappedEK.IP}) -----"); } //get raw data //save data } private async Task SyncApplicationAndHostAsync(V1_Host? host, List hostApplications, bool isUpdateDateModified = false) { 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 appInHostService.CreateAsync(newAppHost)) 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 appInHostService.Get().FirstOrDefaultAsync(t => t.ApplicationId == app.Id && t.HostId == host.Id); if (obj != null) { logger.LogInformation($"Host: {host.Id}, {host.LinkEK} удаление неактуального приложения 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.LinkEK}, {host.Id}"); logger.LogInformation($"=== Host: {host.Id}, {host.LinkEK} конец синхронизации приложений ==="); } private async Task> GetAndFillApplicationsAsync(XmlNode vm) { logger.LogInformation($"--- Начало парсинга данных о программном обеспечении(СП, БД, ОС) из Xml документа от АИХ ИТ ---"); var applications = new List(); //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 CreateAppIfNotExistAsync(app, ApplicationTypesEnum.APP); if (created != null) applications.Add(created); } var dbList = GetAppFromXML(vm?.Attributes?["СУБД"]?.Value); foreach (var db in dbList) { var created = await CreateAppIfNotExistAsync(db, ApplicationTypesEnum.DB); if (created != null) applications.Add(created); } var osList = GetAppFromXML(vm?.Attributes?["ОС"]?.Value); foreach (var os in appList) { var created = await CreateAppIfNotExistAsync(os, ApplicationTypesEnum.OS); if (created != null) applications.Add(created); } logger.LogInformation($"=== Конец парсинга данных о программном обеспечении(СП, БД, ОС) из Xml документа от АИХ ИТ ==="); return applications; } private List GetAppFromXML(string? appField) { if (string.IsNullOrEmpty(appField)) return new List(); var appList = appField.Split(";").Distinct().ToList(); //appList.ForEach(item => item.Trim()); return appList; } private List GetDBFromXML(string? dbField) { if (string.IsNullOrEmpty(dbField)) return new List(); var dbList = dbField.Split(";").Distinct().ToList(); //dbList.ForEach(item => item.Trim()); return dbList; } private List GetOSFromXML(string? osField) { if (string.IsNullOrEmpty(osField)) return new List(); var osList = osField.Split(";").Distinct().ToList(); //osList.ForEach(item => item.Trim()); return osList; } private async Task CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type)//Application application) { if (string.IsNullOrEmpty(appName) || string.IsNullOrWhiteSpace(appName)) return null; var existApp = await 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 DAL.Models.V1.V1_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); } private V1_ApplicationType? GetAppTypeByName(ApplicationTypesEnum type) { var existType = AppTypes.FirstOrDefault(t => t.Name == type.ToString()); if (existType == null) logger.LogError($"Не найден AppType: {type}"); return existType; } //private bool IsChanged(Host host, Host mappedHost) //{ // if (host == null) return true; // if (mappedHost == null) return true; // if (!host.IP.Equals(mappedHost.IP)) return true; // if (!host.RegionalEK!.Equals(mappedHost.RegionalEK)) return true; // if (!host.LinkEK!.Equals(mappedHost.LinkEK)) return true; // if (!host.Status!.Equals(mappedHost.Status)) return true; // if (!host.WorkGroup!.Equals(mappedHost.WorkGroup)) return true; // if (!host.Responsible!.Equals(mappedHost.Responsible)) return true; // return false; //} 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; } } }