diff --git a/PARR.AIHIT/AIHIT/SyncherInstaller.cs b/PARR.AIHIT/AIHIT/SyncherInstaller.cs
index 9ded749e..5921eea4 100644
--- a/PARR.AIHIT/AIHIT/SyncherInstaller.cs
+++ b/PARR.AIHIT/AIHIT/SyncherInstaller.cs
@@ -9,7 +9,7 @@ namespace PARR.AIHIT
{
public static class SyncherInstaller
{
- public static void InstallerSyncerServices(this IServiceCollection services, IConfiguration configuration)
+ public static void InstallSyncerServices(this IServiceCollection services, IConfiguration configuration)
{
var syncherSettings = new SyncherSettings();
configuration.GetSection(nameof(SyncherSettings)).Bind(syncherSettings);
diff --git a/PARR.API.sln b/PARR.API.sln
index 09641c6a..099c900c 100644
--- a/PARR.API.sln
+++ b/PARR.API.sln
@@ -22,7 +22,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{AB278172-BFB4-4D54-9022-2D2A5B3338D7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.BLL", "PARR.BLL\PARR.BLL.csproj", "{7BAB9170-743D-4542-8881-9B161EE81BB6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PARR.BLL", "PARR.BLL\PARR.BLL.csproj", "{7BAB9170-743D-4542-8881-9B161EE81BB6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.EsppTemplateSyncWorker", "PARR.EsppTemplateSyncWorker\PARR.EsppTemplateSyncWorker.csproj", "{7FBD65FE-26FE-4E60-AD1F-20AAC6F88C7A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.EsppTemplateSync", "PARR.EsppTemplateSync\PARR.EsppTemplateSync.csproj", "{39FD9AAD-0792-46B2-A935-42486A993C32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -57,6 +61,14 @@ Global
{7BAB9170-743D-4542-8881-9B161EE81BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BAB9170-743D-4542-8881-9B161EE81BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BAB9170-743D-4542-8881-9B161EE81BB6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7FBD65FE-26FE-4E60-AD1F-20AAC6F88C7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FBD65FE-26FE-4E60-AD1F-20AAC6F88C7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FBD65FE-26FE-4E60-AD1F-20AAC6F88C7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FBD65FE-26FE-4E60-AD1F-20AAC6F88C7A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {39FD9AAD-0792-46B2-A935-42486A993C32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {39FD9AAD-0792-46B2-A935-42486A993C32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {39FD9AAD-0792-46B2-A935-42486A993C32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {39FD9AAD-0792-46B2-A935-42486A993C32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/PARR.BLL/Services/Implementations/FileService.cs b/PARR.BLL/Services/Implementations/FileService.cs
index ee42578f..439a6daf 100644
--- a/PARR.BLL/Services/Implementations/FileService.cs
+++ b/PARR.BLL/Services/Implementations/FileService.cs
@@ -99,5 +99,26 @@ namespace PARR.BLL.Services.Implementations
//return false;
}
}
+
+ public bool DeleteFile(string path)
+ {
+ logger.LogInformation($"Удаляю файл: {path}");
+
+ try
+ {
+ if (!File.Exists(path))
+ return true;
+
+ File.Delete(path);
+ logger.LogInformation($"Файл удален: {path}");
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ logger.LogError(e, $"Ошибка при удалении файла {path}");
+ return false;
+ }
+ }
}
}
diff --git a/PARR.BLL/Services/Interfaces/IFileService.cs b/PARR.BLL/Services/Interfaces/IFileService.cs
index 1ffc8563..3d0a36f1 100644
--- a/PARR.BLL/Services/Interfaces/IFileService.cs
+++ b/PARR.BLL/Services/Interfaces/IFileService.cs
@@ -22,5 +22,12 @@ namespace PARR.BLL.Services.Interfaces
///
///
bool IsExtensionAllowed(IFormFile formFile, string[] allowedExtensions);
+
+ ///
+ /// Удалить файл
+ ///
+ /// Полный путь к файлу
+ ///
+ bool DeleteFile(string path);
}
}
diff --git a/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs b/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs
new file mode 100644
index 00000000..6dc8b6f2
--- /dev/null
+++ b/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using PARR.BLL;
+using PARR.DAL;
+using PARR.EsppTemplateSync.Services;
+
+namespace PARR.EsppTemplateSync
+{
+ public static class EsppTemplateSyncInstaller
+ {
+ public static void InstallEsppTemplateSyncServices(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.InstallBllServices(configuration);
+ services.InstallDalServices(configuration);
+
+ services.AddTransient();
+ services.AddTransient();
+ }
+ }
+}
diff --git a/PARR.EsppTemplateSync/ITemplateSyncer.cs b/PARR.EsppTemplateSync/ITemplateSyncer.cs
new file mode 100644
index 00000000..3570eb51
--- /dev/null
+++ b/PARR.EsppTemplateSync/ITemplateSyncer.cs
@@ -0,0 +1,8 @@
+namespace PARR.EsppTemplateSync
+{
+ public interface ITemplateSyncer
+ {
+ void StartWatching();
+ void StopWatching();
+ }
+}
diff --git a/PARR.EsppTemplateSync/PARR.EsppTemplateSync.csproj b/PARR.EsppTemplateSync/PARR.EsppTemplateSync.csproj
new file mode 100644
index 00000000..21190861
--- /dev/null
+++ b/PARR.EsppTemplateSync/PARR.EsppTemplateSync.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/PARR.EsppTemplateSync/Services/IParserService.cs b/PARR.EsppTemplateSync/Services/IParserService.cs
new file mode 100644
index 00000000..118b1f32
--- /dev/null
+++ b/PARR.EsppTemplateSync/Services/IParserService.cs
@@ -0,0 +1,7 @@
+namespace PARR.EsppTemplateSync.Services
+{
+ internal interface IParserService
+ {
+ Task ParseAsync(string path);
+ }
+}
diff --git a/PARR.EsppTemplateSync/Services/ParserService.cs b/PARR.EsppTemplateSync/Services/ParserService.cs
new file mode 100644
index 00000000..f240954f
--- /dev/null
+++ b/PARR.EsppTemplateSync/Services/ParserService.cs
@@ -0,0 +1,15 @@
+namespace PARR.EsppTemplateSync.Services
+{
+ internal class ParserService : IParserService
+ {
+ public async Task ParseAsync(string path)
+ {
+ //TODO:
+
+ bool isSuccess = true;
+
+
+ return isSuccess;
+ }
+ }
+}
diff --git a/PARR.EsppTemplateSync/TemplateSyncer.cs b/PARR.EsppTemplateSync/TemplateSyncer.cs
new file mode 100644
index 00000000..0844928b
--- /dev/null
+++ b/PARR.EsppTemplateSync/TemplateSyncer.cs
@@ -0,0 +1,113 @@
+using Microsoft.Extensions.Logging;
+using PARR.BLL.Services.Interfaces;
+using PARR.BLL.Settings;
+using PARR.EsppTemplateSync.Services;
+
+namespace PARR.EsppTemplateSync
+{
+ internal class TemplateSyncer : ITemplateSyncer
+ {
+ private readonly ILogger logger;
+ private readonly IParserService parserService;
+ private readonly IFileService fileService;
+ private readonly string dirPath;
+ private readonly string filterExtensions;
+
+ private FileSystemWatcher? watcher;
+
+ public TemplateSyncer(
+ StorageSettings storageSettings,
+ ILogger logger,
+ IParserService parserService,
+ IFileService fileService
+ )
+ {
+ this.logger = logger;
+ this.parserService = parserService;
+ this.fileService = fileService;
+
+ if (storageSettings.EsppTemplates == null)
+ {
+ logger.LogError("Нет секции настроек хранилища. StorageSettings, EsppTemplates");
+ throw new Exception("Нет секции настроек хранилища. StorageSettings, EsppTemplates");
+ }
+
+ string dirPath = Path.Combine(storageSettings.EsppTemplates.TemplatePath);
+ this.dirPath = Path.Combine(storageSettings.StoragePath, dirPath);
+
+ filterExtensions = string.Join(",", storageSettings.EsppTemplates!.AllowedExtensions).Replace(".", "*.");
+ }
+
+ public void StartWatching()
+ {
+ //смотрим, доступна ли папка
+ if (!Directory.Exists(dirPath))
+ {
+ logger.LogError($"Не найдена папка: {dirPath}.");
+ throw new Exception($"Не найдена папка: {dirPath}.");
+ }
+
+
+ // сначала обрабатываем существующие файлы, до тех пор пока все не обработаем
+ // после обработки всех файлов, запускаем вотчер
+ GetExistingFilesAsync();
+
+ watcher = new FileSystemWatcher(dirPath);
+ watcher.NotifyFilter = NotifyFilters.FileName;
+ //watcher.Changed += OnChanged;
+ //todo: тут await???
+ watcher.Created += OnChanged;
+
+ watcher.Filter = filterExtensions;
+ watcher.EnableRaisingEvents = true;
+
+ logger.LogInformation($"--- --- --- FileWatcher запущен --- --- ---");
+ }
+
+ public void StopWatching()
+ {
+ watcher?.Dispose();
+ logger.LogInformation($"=== === === FileWatcher остановлен === === ===");
+ }
+
+ private async void OnChanged(object sender, FileSystemEventArgs e)
+ {
+ var path = e.FullPath;
+ await ParseFileAsync(path);
+ }
+
+ private async void GetExistingFilesAsync()
+ {
+ // при первом запуске воркера, обрабатываем существующие файлы
+ var files = Directory.GetFiles(this.dirPath, filterExtensions);
+
+ logger.LogInformation($"Запуск первоначальной загрузки файлов после старта сервиса. (До старта вотчера). Найдено файлов: {files.Length} шт.");
+
+ foreach (var file in files)
+ await ParseFileAsync(file);
+
+ //если были файлы, запустим еще раз ручную обработку, вдруг за это время еще загрузили, а вотчер еще не был запущен
+ //запускаем до тех пор, пока не останется необработанных файлов
+ if (files.Any())
+ GetExistingFilesAsync();
+ }
+
+
+ private async Task ParseFileAsync(string path)
+ {
+ logger.LogInformation($"--- --- Найден файл. Готов для парсинга {path} --- ---");
+ var parseResult = await parserService.ParseAsync(path);
+
+ if (parseResult)
+ {
+ logger.LogInformation($"Парсинг успешно завершен. Удаляю файл {path}");
+ var removeResult = fileService.DeleteFile(path);
+ }
+ else
+ {
+ logger.LogError($"Парсинг завершен c ошибкой. Файл не удален {path}");
+ }
+ }
+
+ }
+}
diff --git a/PARR.EsppTemplateSyncWorker/PARR.EsppTemplateSyncWorker.csproj b/PARR.EsppTemplateSyncWorker/PARR.EsppTemplateSyncWorker.csproj
new file mode 100644
index 00000000..48556f65
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/PARR.EsppTemplateSyncWorker.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net7.0
+ enable
+ enable
+ dotnet-PARR.EsppTemplateSyncWorker-33871a7f-fda7-4371-a369-a7ce886efbec
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PARR.EsppTemplateSyncWorker/Program.cs b/PARR.EsppTemplateSyncWorker/Program.cs
new file mode 100644
index 00000000..d499c455
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/Program.cs
@@ -0,0 +1,20 @@
+using PARR.EsppTemplateSync;
+using PARR.EsppTemplateSyncWorker;
+using Serilog;
+
+IHost host = Host.CreateDefaultBuilder(args)
+ .ConfigureServices((hostContext, services) =>
+ {
+ services.InstallEsppTemplateSyncServices(hostContext.Configuration);
+
+ services.AddHostedService();
+ })
+ .UseSerilog((hostContext, services, config) =>
+ {
+ config
+ .WriteTo.Console()
+ .ReadFrom.Configuration(hostContext.Configuration);
+ })
+ .Build();
+
+host.Run();
diff --git a/PARR.EsppTemplateSyncWorker/Properties/launchSettings.json b/PARR.EsppTemplateSyncWorker/Properties/launchSettings.json
new file mode 100644
index 00000000..96aa315b
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "PARR.EsppTemplateSyncWorker": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/PARR.EsppTemplateSyncWorker/Worker.cs b/PARR.EsppTemplateSyncWorker/Worker.cs
new file mode 100644
index 00000000..6bfa8ed4
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/Worker.cs
@@ -0,0 +1,40 @@
+using PARR.EsppTemplateSync;
+
+namespace PARR.EsppTemplateSyncWorker
+{
+ public class Worker : BackgroundService
+ {
+ private readonly ILogger _logger;
+ private readonly ITemplateSyncer templateSyncer;
+
+ public Worker(ILogger logger, ITemplateSyncer templateSyncer)
+ {
+ _logger = logger;
+ this.templateSyncer = templateSyncer;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ //var task = new Task(() =>
+ //{
+ // templateSyncer.StartWatching();
+ //});
+ //task.Start();
+
+ templateSyncer.StartWatching();
+
+ //while (!stoppingToken.IsCancellationRequested)
+ //{
+ // _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
+ // await Task.Delay(1 * 1000, stoppingToken);
+ //}
+ }
+
+ public override Task StopAsync(CancellationToken cancellationToken)
+ {
+ templateSyncer.StopWatching();
+
+ return base.StopAsync(cancellationToken);
+ }
+ }
+}
\ No newline at end of file
diff --git a/PARR.EsppTemplateSyncWorker/appsettings.Development.json b/PARR.EsppTemplateSyncWorker/appsettings.Development.json
new file mode 100644
index 00000000..58b8d3f6
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/appsettings.Development.json
@@ -0,0 +1,11 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "StorageSettings": {
+ "StoragePath": "W:\\"
+ }
+}
diff --git a/PARR.EsppTemplateSyncWorker/appsettings.json b/PARR.EsppTemplateSyncWorker/appsettings.json
new file mode 100644
index 00000000..7fa498f7
--- /dev/null
+++ b/PARR.EsppTemplateSyncWorker/appsettings.json
@@ -0,0 +1,34 @@
+{
+ "DefaultConnection": "Server=10.99.253.184;Database=parr;User Id=app_parr; Password=PosdfkhT&)%sdfligL&%5546;",
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Debug"
+ }
+ },
+ "WriteTo": [
+ {
+ "Name": "File",
+ "Args": {
+ "path": "log/log-.txt",
+ "rollingInterval": "Day"
+ }
+ }
+ ]
+ },
+ "StorageSettings": {
+ "StoragePath": "Data",
+ "EsppTemplates": {
+ "AllowedExtensions": [ ".csv" ],
+ "MaxFileSizeMb": 100
+ }
+ }
+}
diff --git a/PARR.Worker/PARR.Worker/Program.cs b/PARR.Worker/PARR.Worker/Program.cs
index 5a7c906f..c53ae283 100644
--- a/PARR.Worker/PARR.Worker/Program.cs
+++ b/PARR.Worker/PARR.Worker/Program.cs
@@ -18,16 +18,16 @@ IHost host = Host.CreateDefaultBuilder(args)
services.InstallMailServices(hostContext.Configuration);
services.InstallDalServices(hostContext.Configuration);
- services.InstallerSyncerServices(hostContext.Configuration);
+ services.InstallSyncerServices(hostContext.Configuration);
services.AddHostedService();
})
- .UseSerilog((hostContext, services, config) =>
- {
- config
- .WriteTo.Console()
- .ReadFrom.Configuration(hostContext.Configuration);
- })
+ .UseSerilog((hostContext, services, config) =>
+ {
+ config
+ .WriteTo.Console()
+ .ReadFrom.Configuration(hostContext.Configuration);
+ })
.Build();
host.Run();