using AutoMapper; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PARR.AIHIT.Services; using PARR.DAL.Contracts; using PARR.DAL.Extensions; using PARR.DAL.Models; using PARR.DAL.Models.AIHIT; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.AIHIT; using System.Text; namespace PARR.AIHIT { internal class Syncher : ISyncher { private readonly ILogger logger; private readonly IHostService hostService; private readonly IMapper mapper; private readonly IApplicationService appService; private readonly IApplicationTypeService appTypeService; private readonly IApplicationInHostService appInHostService; private readonly IRawDataEKService rawDataEKService; private readonly ISettingService settingService; private readonly IAIHITService aihitService; public List AppTypes { get; private set; } = new List(); public Syncher( ILogger logger, IHostService hostService, IMapper mapper, IApplicationService appService, IApplicationTypeService appTypeService, IApplicationInHostService appInHostService, IRawDataEKService rawDataEKService, ISettingService settingService, IAIHITService aihitService ) { this.hostService = hostService; this.mapper = mapper; this.appService = appService; this.appTypeService = appTypeService; this.appInHostService = appInHostService; this.rawDataEKService = rawDataEKService; this.settingService = settingService; this.aihitService = aihitService; this.logger = logger; } private async Task GetAppTypesAsync() { AppTypes = await appTypeService.Get().ToListAsync(); } public async Task InvokeFromDatabase() { await GetAppTypesAsync(); //Получаем зоны ответственности из БД var respAreas = await settingService.Get() .Where(ra => ra.Group == AIHTITSettings.RespAreaGroupName) .ToListAsync(); #if !DEBUG //Запускаем хранимую процедуру в АИХ ИТ и складываем в таблицу RawDataEKs, предварительно почистив старые данные foreach (var respArea in respAreas) { logger.LogDebug($"-= Получение данных об ЭК зоны ответственности {respArea.Name} =-"); var eksFromAIHIT = aihitService.GetEKList(respArea.Value)?.ToList(); if (eksFromAIHIT == null) continue; //Удаляем текущие данные по зоне ответственности respArea logger.LogDebug($"-= Удаление существующих данных об ЭК зоны ответственности {respArea.Name} =-"); 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; } logger.LogDebug($"-= Создание новых записей об ЭК зоны ответственности {respArea.Name} =-"); foreach (var ek in eksFromAIHIT) { // создаем var mappedEK = mapper.Map(ek); mappedEK.Id = Guid.NewGuid(); mappedEK.DateCreated = DateTimeOffset.UtcNow; //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}"); } logger.LogDebug($"-= Запись в базу данных записей об ЭК зоны ответственности {respArea.Name} "); if (!await rawDataEKService.CommitAsync()) logger.LogError($"Информация о хостах зоны ответственности {respArea.Name} не записана "); logger.LogDebug($"-= Конец синхронизации данных об ЭК зоны ответственности {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())) && e.EKFindCode.StartsWith("ВРТ-")) .ToListAsync(); foreach (var ek in eks) { if (ek.IP == null) continue; var foundHost = await hostService.GetHostWithAppsAsync(ek.IP); var mappedHost = mapper.Map(ek); //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; } else if (mappedHost.WorkGroup != null && (foundHost.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 SyncApplicationAndHostAsync(Host? host, List hostApplications, bool isUpdateDateModified = false) { var isUpdated = false; if (host == null) return; logger.LogDebug($"Host: {host.Ek}({host.IP}), начало синхронизации приложений ({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.Ek}({host.IP}), добавление нового приложения 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.Ek}({host.IP})"); isUpdated = true; } } foreach (var app in host.ApplicationsInHosts) { var appToRemove = hostApplications.FirstOrDefault(a => a.Id == app.ApplicationId); if (appToRemove == null) { //todo remove appToRemove var obj = await appInHostService.Get().FirstOrDefaultAsync(t => t.ApplicationId == app.ApplicationId && t.HostId == host.Id); if (obj != null) { logger.LogInformation($"Host: {host.Ek}({host.IP}), удаление неактуального приложения Application {app.Application?.Name}"); appInHostService.Delete(obj); if (!await hostService.CommitAsync()) logger.LogError($"Не удалось удалить Application {app.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 async Task> GetAndFillApplicationsAsync(RawDataEK vm) { //logger.LogDebug($"Начало парсинга данных о программном обеспечении(СП, БД, ОС) из АИХ ИТ"); var applications = new List(); 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.LogDebug($"Конец парсинга данных о программном обеспечении(СП, БД, ОС) из АИХ ИТ"); 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(); return dbList; } private List GetOSFromXML(string? osField) { if (string.IsNullOrEmpty(osField)) return new List(); var osList = osField.Split(";").Distinct().ToList(); return osList; } private async Task CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type) { 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 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 ApplicationType? GetAppTypeByName(ApplicationTypesEnum type) { var existType = AppTypes.FirstOrDefault(t => t.Name == type.ToString()); if (existType == null) logger.LogError($"Не найден AppType: {type}"); return existType; } 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; } } }