From c35dfd58d900054ca2ebb1c0828a47ecc7a06d93 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Wed, 20 Sep 2023 15:27:13 +1000 Subject: [PATCH] =?UTF-8?q?generator=20templates,=20=D0=BE=D1=82=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20=D0=B2=20MQ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../V1/GeneratorTemplateController.cs | 34 ++++++++- PARR.API/Installers/ApiServicesInstaller.cs | 1 + PARR.API/Installers/SettingsInstaller.cs | 5 ++ PARR.API/PARR.API.csproj | 1 + .../MqGeneratorTemplateService.cs | 74 +++++++++++++++++++ .../Interfaces/IMqGeneratorTemplateService.cs | 7 ++ PARR.API/Settings/MqSettings.cs | 23 ++++++ .../GeneratorTemplateRequestValidator.cs | 25 ++++++- PARR.API/appsettings.Development.json | 9 ++- PARR.API/appsettings.json | 8 ++ PARR.BLL/Domain/Mq/GeneratorTemplateMq.cs | 25 +++++++ 11 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 PARR.API/Services/Implementations/MqGeneratorTemplateService.cs create mode 100644 PARR.API/Services/Interfaces/IMqGeneratorTemplateService.cs create mode 100644 PARR.API/Settings/MqSettings.cs create mode 100644 PARR.BLL/Domain/Mq/GeneratorTemplateMq.cs diff --git a/PARR.API/Controllers/V1/GeneratorTemplateController.cs b/PARR.API/Controllers/V1/GeneratorTemplateController.cs index 9901e7aa..37567e1f 100644 --- a/PARR.API/Controllers/V1/GeneratorTemplateController.cs +++ b/PARR.API/Controllers/V1/GeneratorTemplateController.cs @@ -1,21 +1,32 @@ -using FluentValidation; +using AutoMapper; +using FluentValidation; using Microsoft.AspNetCore.Mvc; using PARR.API.Contracts.V1; using PARR.API.Contracts.V1.Requests; using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Controllers.V1.Base; +using PARR.API.Services.Interfaces; +using PARR.BLL.Domain.Mq; +using PARR.DAL.Services.Interfaces; +using System.Text.Json; namespace PARR.API.Controllers.V1 { public class GeneratorTemplateController : BaseApiController { private readonly IValidator validator; + private readonly IMqGeneratorTemplateService mqGeneratorTemplateService; + private readonly IUriService uriService; public GeneratorTemplateController( - IValidator validator + IValidator validator, + IMqGeneratorTemplateService mqGeneratorTemplateService, + IUriService uriService ) { this.validator = validator; + this.mqGeneratorTemplateService = mqGeneratorTemplateService; + this.uriService = uriService; } /// @@ -29,9 +40,26 @@ namespace PARR.API.Controllers.V1 if (!resultValidate.IsValid) return BadRequest(new Response(resultValidate.Errors)); + // Todo: проверить есть ли в бд такие ворк и апп + var obj = new GeneratorTemplateMq + { + Action = request.Action, + ApplicationId = request.ApplicationId, + Ek = request.Ek, + WorkId = request.WorkId + }; - return Ok(); + var msg = JsonSerializer.Serialize(obj); + + var result = mqGeneratorTemplateService.SendMsg(msg); + + if (!result) + return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при отправке данных." } })); + + var createdUri = uriService.GetAllUri(ApiRoutes.Template.GetAll); + + return Created(createdUri, new Response(null, true, new List(), "Отправлен запрос на генерацию шаблонов.")); } } } diff --git a/PARR.API/Installers/ApiServicesInstaller.cs b/PARR.API/Installers/ApiServicesInstaller.cs index 4ff3bc14..a097cd3a 100644 --- a/PARR.API/Installers/ApiServicesInstaller.cs +++ b/PARR.API/Installers/ApiServicesInstaller.cs @@ -20,6 +20,7 @@ namespace PARR.API.Installers }); services.AddTransient(); + services.AddTransient(); diff --git a/PARR.API/Installers/SettingsInstaller.cs b/PARR.API/Installers/SettingsInstaller.cs index b63bbf70..ad96399f 100644 --- a/PARR.API/Installers/SettingsInstaller.cs +++ b/PARR.API/Installers/SettingsInstaller.cs @@ -9,6 +9,11 @@ namespace PARR.API.Installers { public static void InstallSettings(this IServiceCollection services, IConfiguration configuration) { + var mqSettings = new MqSettings(); + configuration.GetSection(nameof(MqSettings)).Bind(mqSettings); + services.AddSingleton(mqSettings); + + //var storageSettings = new StorageSettings(); //configuration.GetSection(nameof(StorageSettings)).Bind(storageSettings); //services.AddSingleton(storageSettings); diff --git a/PARR.API/PARR.API.csproj b/PARR.API/PARR.API.csproj index 6ace2662..d1fd5b8d 100644 --- a/PARR.API/PARR.API.csproj +++ b/PARR.API/PARR.API.csproj @@ -26,6 +26,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/PARR.API/Services/Implementations/MqGeneratorTemplateService.cs b/PARR.API/Services/Implementations/MqGeneratorTemplateService.cs new file mode 100644 index 00000000..245efa0d --- /dev/null +++ b/PARR.API/Services/Implementations/MqGeneratorTemplateService.cs @@ -0,0 +1,74 @@ +using PARR.API.Services.Interfaces; +using PARR.API.Settings; +using RabbitMQ.Client; +using System.Text; + +namespace PARR.API.Services.Implementations +{ + public class MqGeneratorTemplateService : IMqGeneratorTemplateService + { + private readonly MqSettings mqSettings; + private readonly ILogger logger; + + public MqGeneratorTemplateService(MqSettings mqSettings, ILogger logger) + { + this.mqSettings = mqSettings; + this.logger = logger; + } + + public bool SendMsg(string msg) + { + var factory = new ConnectionFactory + { + HostName = mqSettings.GenerateTemplates.HostName, + UserName = mqSettings.GenerateTemplates.User, + Password = mqSettings.GenerateTemplates.Password + }; + + try + { + using (var connection = factory.CreateConnection()) + using (var channel = connection.CreateModel()) + { + //https://www.rabbitmq.com/lazy-queues.html + //Рекомендовано при работе порциями использовать ленивые очереди. сообщения не используют память + //Формируем соответствующий аргумент + var args = new Dictionary { { "x-queue-mode", "lazy" } }; + + //Объявляем очередь с которой будем работать. + //Если такой очереди ещё нет, то создатся. + //Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка. + //В целом эти параметры можно посмотреть в админке RabbitMQ + + channel.QueueDeclare( + queue: mqSettings.GenerateTemplates.QueueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: args + ); + + var body = Encoding.UTF8.GetBytes(msg); + + var props = channel.CreateBasicProperties(); + //храним на диске + props.DeliveryMode = 2; + //время жизни, мс + //props.Expiration = "60000"; + + channel.BasicPublish(exchange: "", routingKey: mqSettings.GenerateTemplates.QueueName, basicProperties: props, body: body); + } + + logger.LogDebug($"Отправлено сообщение в очередь: {mqSettings.GenerateTemplates.QueueName}, {msg}"); + + return true; + } + catch (Exception ex) + { + logger.LogError(ex, $"Ошибка при отправке сообщения в очередь {mqSettings.GenerateTemplates.QueueName}, {msg}"); + + return false; + } + } + } +} diff --git a/PARR.API/Services/Interfaces/IMqGeneratorTemplateService.cs b/PARR.API/Services/Interfaces/IMqGeneratorTemplateService.cs new file mode 100644 index 00000000..51d3361c --- /dev/null +++ b/PARR.API/Services/Interfaces/IMqGeneratorTemplateService.cs @@ -0,0 +1,7 @@ +namespace PARR.API.Services.Interfaces +{ + public interface IMqGeneratorTemplateService + { + bool SendMsg(string msg); + } +} diff --git a/PARR.API/Settings/MqSettings.cs b/PARR.API/Settings/MqSettings.cs new file mode 100644 index 00000000..db4d8e7e --- /dev/null +++ b/PARR.API/Settings/MqSettings.cs @@ -0,0 +1,23 @@ +namespace PARR.API.Settings +{ + public class MqSettings + { + public MqGenerateTemplates GenerateTemplates { get; set; } = new MqGenerateTemplates(); + } + + public class MqGenerateTemplates : IMqSettings + { + public string HostName { get; set; } = string.Empty; + public string QueueName { get; set; } = string.Empty; + public string User { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + } + + public interface IMqSettings + { + string HostName { get; set; } + string QueueName { get; set; } + string User { get; set; } + string Password { get; set; } + } +} diff --git a/PARR.API/Validators/GeneratorTemplateRequestValidator.cs b/PARR.API/Validators/GeneratorTemplateRequestValidator.cs index 44ebc03e..09e18c86 100644 --- a/PARR.API/Validators/GeneratorTemplateRequestValidator.cs +++ b/PARR.API/Validators/GeneratorTemplateRequestValidator.cs @@ -1,18 +1,37 @@ using FluentValidation; using PARR.API.Contracts.V1.Requests; using PARR.BLL.Contracts; +using PARR.DAL.Services.Interfaces; namespace PARR.API.Validators { public class GeneratorTemplateRequestValidator : AbstractValidator { - public GeneratorTemplateRequestValidator() + private readonly IApplicationService applicationService; + + public GeneratorTemplateRequestValidator(IApplicationService applicationService) { + this.applicationService = applicationService; + RuleFor(t => t.WorkId).NotEmpty(); - RuleFor(t => t.ApplicationId).NotEmpty(); + + RuleFor(t => t.ApplicationId) + .MustAsync(async (entity, value, c) => await IsExistApplication(entity, value)) + .WithMessage("Нет приложения с таким Id."); + RuleFor(t => t.Ek).NotEmpty(); - RuleFor(t => t.Action).Must(t => t.ToLower() == GenerateTemplateActionsEnum.create.ToString() || t.ToLower() == GenerateTemplateActionsEnum.deactivate.ToString()) + + RuleFor(t => t.Action) + .Must(t => t.ToLower() == GenerateTemplateActionsEnum.create.ToString() || t.ToLower() == GenerateTemplateActionsEnum.deactivate.ToString()) .WithMessage($"Допустимые значения: {GenerateTemplateActionsEnum.create}, {GenerateTemplateActionsEnum.deactivate}"); + + } + + //todo: сделать валидацию в тбл AppInWorks + + private async Task IsExistApplication(GeneratorTemplateRequest request, Guid applicationId) + { + return await applicationService.GetAsync(applicationId) != null; } } } diff --git a/PARR.API/appsettings.Development.json b/PARR.API/appsettings.Development.json index 8121164b..2efe829c 100644 --- a/PARR.API/appsettings.Development.json +++ b/PARR.API/appsettings.Development.json @@ -1,11 +1,16 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Default": "Debug", + "Microsoft.AspNetCore": "Debug" } }, "StorageSettings": { "StoragePath": "W:\\" + }, + "MqSettings": { + "GenerateTemplates": { + "HostName": "10.99.253.216" + } } } diff --git a/PARR.API/appsettings.json b/PARR.API/appsettings.json index 82b28a51..513c496c 100644 --- a/PARR.API/appsettings.json +++ b/PARR.API/appsettings.json @@ -36,5 +36,13 @@ "AllowedExtensions": [ ".csv" ], "MaxFileSizeMb": 100 } + }, + "MqSettings": { + "GenerateTemplates": { + "HostName": "parr-rabbitmq", + "QueueName": "parr-generate-templates", + "User": "generate_templates_api", + "Password": "DHhjgdsf*&%95" + } } } diff --git a/PARR.BLL/Domain/Mq/GeneratorTemplateMq.cs b/PARR.BLL/Domain/Mq/GeneratorTemplateMq.cs new file mode 100644 index 00000000..386600cc --- /dev/null +++ b/PARR.BLL/Domain/Mq/GeneratorTemplateMq.cs @@ -0,0 +1,25 @@ +namespace PARR.BLL.Domain.Mq +{ + public class GeneratorTemplateMq + { + /// + /// Id работы + /// + public Guid WorkId { get; set; } + + /// + /// Id приложения + /// + public Guid ApplicationId { get; set; } + + /// + /// Действие: create, deactivate + /// + public required string Action { get; set; } + + /// + /// ЭК, принимает регулярное выражение. Например: *, ВРТ-*-ДВС + /// + public required string Ek { get; set; } + } +}