Files
parr_api/PARR.AIHITSyncer/AihitSyncer.cs
2024-02-05 14:45:09 +10:00

337 lines
14 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.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.AIHITSyncer.Settings;
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
{
internal class AihitSyncer : IAihitSyncer
{
private readonly ILogger<AihitSyncer> logger;
private readonly WorkerSettings workerSettings;
private readonly IMqService mqService;
private readonly MqSettings mqSettings;
private readonly ITransformService transformService;
private readonly IServiceProvider serviceProvider;
public List<ApplicationType> AppTypes { get; private set; } = new List<ApplicationType>();
public AihitSyncer(
ILogger<AihitSyncer> logger,
WorkerSettings workerSettings,
IMqService mqService,
MqSettings mqSettings,
ITransformService transformService,
IServiceProvider serviceProvider
)
{
this.logger = logger;
this.workerSettings = workerSettings;
this.mqService = mqService;
this.mqSettings = mqSettings;
this.transformService = transformService;
this.serviceProvider = serviceProvider;
}
private async Task GetAppTypesAsync()
{
if (AppTypes == null || AppTypes.Count == 0)
using (var scope = serviceProvider.CreateScope())
{
var appTypesService = scope.ServiceProvider.GetService<IApplicationTypeService>();
if (appTypesService == null)
throw new Exception("Не смог получить серивс IApplicationTypeService, scope.ServiceProvider.GetService<IApplicationTypeService>()");
AppTypes = await appTypesService.Get().ToListAsync();
}
}
public void Start()
{
logger.LogInformation("Запуск сервиса синхронизации данных из АИХИТ и ПАРР.");
var isConnected = mqService.InitConsumer(mqSettings, SyncDataAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
}
public void Stop()
{
mqService.Dispose();
}
private async Task SyncDataAsync(string msg)
{
var objFromQuery = transformService.GetModelFromJson<AihitDataMq>(msg);
if (objFromQuery == null)
return;
using (var scope = serviceProvider.CreateScope())
{
var hostService = scope.ServiceProvider.GetService<IHostService>();
if (hostService == null)
throw new Exception("Не смог получить серивс IHostService, scope.ServiceProvider.GetService<IHostService>()");
await SyncHostToScopeAsync(hostService, objFromQuery);
await GetAppTypesAsync();
}
logger.LogDebug($"Закончил работу с сообщением: {msg}");
//await Task.CompletedTask;
}
private async Task SyncHostToScopeAsync(IHostService hostService, AihitDataMq objFromQuery)
{
//ищем существующий хост в БД
var host = await hostService.GetHostWithAppsAsync(objFromQuery.IP);
var isNew = false;
//если не нашли - создаём
if (host == null)
{
isNew = true;
host = await CreateHostAsync(hostService, objFromQuery);
}
else
{
logger.LogDebug($"Найден хост в БД: {host!.Ek}({host.IP})");
//проверям и обновляем поля
await SyncHostFieldsAsync(hostService, host, objFromQuery);
}
//получаем лист ПО из объекта
var appsInObj = await GetAppInObjectAsync(host, objFromQuery);
await SyncApplicationAndHostAsync(host, appsInObj, !isNew);
}
private async Task<List<Application>> GetAppInObjectAsync(Host? host, AihitDataMq objFromQuery)
{
var applications = new List<Application>();
if (objFromQuery.APPType != null)
{
var appList = objFromQuery.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 (objFromQuery.DBType != null)
{
var appList = objFromQuery.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 (objFromQuery.OSType != null)
{
var appList = objFromQuery.OSType.Split(new char[] { ',', ';' }).Distinct().ToList();
foreach (var app in appList)
{
var created = await CreateAppIfNotExistAsync(app, ApplicationTypesEnum.OS);
if (created != null)
applications.Add(created);
}
}
return applications;
}
private async Task SyncHostFieldsAsync(IHostService hostService, 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;
}
if (objFromQuery.WorkGroup != null && (host.WorkGroup == null || !host.WorkGroup!.Equals(objFromQuery.WorkGroup)))
{
host.WorkGroup = objFromQuery.WorkGroup;
isChanged = true;
}
if (host.ResponseAreaCode != ((ResolveCode(objFromQuery.ResponseArea) == 0) ? 99 : ResolveCode(objFromQuery.ResponseArea)))
{//TODO Возможно проще выгружать с помощью INCLUDE зону ответственности и сравнивать string
host.ResponseAreaCode = ((ResolveCode(objFromQuery.ResponseArea) == 0) ? 99 : ResolveCode(objFromQuery.ResponseArea));
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<Host?> CreateHostAsync(IHostService hostService, AihitDataMq objFromQuery)
{
var id = Guid.NewGuid();
var host = new Host
{
Id = id,
Ek = objFromQuery.EK,
IP = objFromQuery.IP,
EkStatusCode = ResolveCode(objFromQuery.Status),
WorkGroup = objFromQuery.WorkGroup,
ResponseAreaCode = ResolveCode(objFromQuery.ResponseArea)
};
if (!await hostService.CreateAsync(host) || !await hostService.CommitAsync())
logger.LogError($"Не удалось создать узел {host.Ek}({host.IP})");
else
logger.LogInformation($"----- Создан узел: {host.Id} -----");
return await hostService.GetHostWithAppsAsync(host.IP);
}
/// <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 async Task<Application?> CreateAppIfNotExistAsync(string appName, ApplicationTypesEnum type)
{
if (string.IsNullOrEmpty(appName) || string.IsNullOrWhiteSpace(appName)) return null;
using (var scope = serviceProvider.CreateScope())
{
var appService = scope.ServiceProvider.GetService<IApplicationService>();
if (appService == null)
throw new Exception("Не смог получить серивс IApplicationService, scope.ServiceProvider.GetService<IApplicationService>()");
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);
}
}
/// <summary>
/// Метод синхронизации
/// </summary>
/// <param name="host">Хост</param>
/// <param name="hostApplications">Список программного обеспечения</param>
/// <param name="isUpdateDateModified">Признак обновления поля DateModified</param>
/// <returns></returns>
private async Task SyncApplicationAndHostAsync(Host? host, List<Application> appsInObject, bool isUpdateDateModified = false)
{
var isUpdated = false;
if (host == null)
return;
logger.LogDebug($"Host: {host.Ek}({host.IP}), начало синхронизации приложений ({appsInObject.Count()}) ");
using (var scope = serviceProvider.CreateScope())
{
var appInHostService = scope.ServiceProvider.GetService<IApplicationInHostService>();
if (appInHostService == null)
throw new Exception("Не смог получить серивс IApplicationInHostService, scope.ServiceProvider.GetService<IApplicationInHostService>()");
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;
}
}
}