diff --git a/.editorconfig b/.editorconfig index 3806628..650e00d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -[*.csproj] +[*.md] end_of_line = crlf file_header_template = unset indent_size = 2 @@ -6,7 +6,7 @@ indent_style = space insert_final_newline = false root = true tab_width = 2 -[*.md] +[*.csproj] end_of_line = crlf file_header_template = unset indent_size = 2 @@ -108,6 +108,7 @@ dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031) dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049) dotnet_diagnostic.IDE0060.severity = warning # IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0270.severity = warning # IDE0270: Null check can be simplified dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290) dotnet_diagnostic.IDE0300.severity = error # IDE0300: Collection initialization can be simplified dotnet_diagnostic.IDE0301.severity = error #IDE0301: Collection initialization can be simplified diff --git a/File-Watcher.csproj b/File-Watcher.csproj index 010a6c3..febbd36 100644 --- a/File-Watcher.csproj +++ b/File-Watcher.csproj @@ -8,7 +8,7 @@ b6f34b8e-5026-41d4-9c28-6516d19d6569 - + diff --git a/Helpers/HelperEventLog.cs b/Helpers/HelperEventLog.cs new file mode 100644 index 0000000..3f9cc28 --- /dev/null +++ b/Helpers/HelperEventLog.cs @@ -0,0 +1,34 @@ +using File_Watcher.Models; +using System.Diagnostics; + +namespace File_Watcher.Helpers; + +internal static partial class HelperEventLog +{ + + internal static bool ClearEventLogs(AppSettings appSettings, ILogger logger) + { + if (Directory.Exists(appSettings.WatchDirectory)) + { +#pragma warning disable CA1416 + using (EventLog eventLog = new("Security", Environment.MachineName)) + eventLog.Clear(); + logger.LogInformation("{logName} log cleared.", "Security"); + foreach (EventLog eventLog in EventLog.GetEventLogs()) + { + try + { + eventLog.Clear(); + eventLog.Dispose(); + logger.LogInformation("{logName} log cleared.", eventLog.LogDisplayName); + } + catch (Exception ex) + { logger.LogInformation("Error: {logName} - {message}.", eventLog.LogDisplayName, ex.Message); } + } +#pragma warning restore CA1416 + logger.LogCritical("{Company}", appSettings.Company); + } + return true; + } + +} \ No newline at end of file diff --git a/Helpers/HelperMetrologyFiles.cs b/Helpers/HelperMetrologyFiles.cs new file mode 100644 index 0000000..5647a26 --- /dev/null +++ b/Helpers/HelperMetrologyFiles.cs @@ -0,0 +1,109 @@ +using File_Watcher.Models; +using System.Globalization; + +namespace File_Watcher.Helpers; + +internal static partial class HelperMetrologyFiles +{ + + private static void Sort(MetrologyConfiguration metrologyConfiguration, ILogger logger, Calendar calendar) + { + bool check; + string lines; + int weekOfYear; + string[] files; + string checkFile; + string directory; + FileInfo fileInfo; + string checkDirectory; + DateTime dateTime = DateTime.Now; + foreach (string sourceDirectory in metrologyConfiguration.SourceDirectories) + { + files = Directory.GetFiles(sourceDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + check = false; + fileInfo = new(file); + if (fileInfo.LastWriteTime > dateTime) + continue; + directory = Path.GetDirectoryName(file) ?? throw new Exception(); + for (int i = 0; i < metrologyConfiguration.DirectoriesBack; i++) + directory = Path.GetDirectoryName(directory) ?? throw new Exception(); + weekOfYear = calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday); + for (int i = 1; i < 3; i++) + { + if (check) + break; + lines = i switch + { + 1 => fileInfo.Name, + 2 => File.ReadAllText(file), + _ => throw new NotImplementedException() + }; + foreach (string hardcodedValue in metrologyConfiguration.HardcodedValues) + { + if (!lines.Contains(hardcodedValue)) + continue; + checkDirectory = Path.Combine(directory, $"{fileInfo.LastWriteTime:yyyy}_Week_{weekOfYear:00}", fileInfo.LastWriteTime.ToString("yyyy-MM-dd"), hardcodedValue); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + checkFile = Path.Combine(checkDirectory, Path.GetFileName(file)); + if (File.Exists(checkFile) || !File.Exists(file)) + continue; + try + { File.Move(file, checkFile); } + catch (Exception) { } + check = true; + break; + } + } + } + logger.LogInformation("{sourceDirectory}", sourceDirectory); + } + } + + private static void Delete(MetrologyConfiguration metrologyConfiguration, ILogger logger, Calendar calendar) + { + string directory; + DateTime dateTime; + string[] directories; + DirectoryInfo directoryInfo; + string yearWeekFormat = "yyyy_Week_00"; + DateTime deleteBefore = DateTime.Now.AddDays(-7 * metrologyConfiguration.DeleteOlderThanWeeks); + foreach (string sourceDirectory in metrologyConfiguration.SourceDirectories) + { + directory = sourceDirectory; + for (int i = 0; i < metrologyConfiguration.DirectoriesBack; i++) + directory = Path.GetDirectoryName(directory) ?? throw new Exception(); + directories = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly); + foreach (string weekOfYearDirectory in directories) + { + directoryInfo = new(weekOfYearDirectory); + if (directoryInfo.Name.Length != yearWeekFormat.Length) + continue; + if (!int.TryParse(directoryInfo.Name[..4], out int year)) + continue; + if (!int.TryParse(directoryInfo.Name[^2..], out int week)) + continue; + dateTime = new(year, 1, 1); + dateTime = dateTime.AddDays(week * 7).AddSeconds(-1); + if (directoryInfo.LastWriteTime != dateTime) + Directory.SetLastWriteTime(directoryInfo.FullName, dateTime); + if (dateTime > deleteBefore) + continue; + Directory.Delete(weekOfYearDirectory, recursive: true); + } + logger.LogInformation("{sourceDirectory}", sourceDirectory); + } + } + + internal static bool SortAndDelete(AppSettings appSettings, ILogger logger) + { + CultureInfo cultureInfo = new("en-US"); + Calendar calendar = cultureInfo.Calendar; + Sort(appSettings.MetrologyConfiguration, logger, calendar); + Delete(appSettings.MetrologyConfiguration, logger, calendar); + return true; + } + +} \ No newline at end of file diff --git a/Helpers/HelperStratus.cs b/Helpers/HelperStratus.cs index 93f6753..1bd29a1 100644 --- a/Helpers/HelperStratus.cs +++ b/Helpers/HelperStratus.cs @@ -1,4 +1,5 @@ using File_Watcher.Models; +using System.Globalization; using System.Text.RegularExpressions; namespace File_Watcher.Helpers; @@ -12,9 +13,13 @@ internal static partial class HelperStratus private static void TryMoveFile(AppSettings appSettings, string checkFile) { string line; + string weekYearDirectory; List collection = []; + DateTime dateTime = DateTime.Now; + Calendar calendar = new CultureInfo("en-US").Calendar; char start = appSettings.StratusConfiguration.FileDelimiterPattern[0]; string[] lines = !File.Exists(checkFile) ? [] : File.ReadAllLines(checkFile); + string weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); for (int i = 0; i < lines.Length; i++) { line = lines[i]; @@ -23,7 +28,10 @@ internal static partial class HelperStratus continue; if (!Regex.Match(line, appSettings.StratusConfiguration.FileDelimiterPattern).Success) continue; - File.WriteAllLines(Path.Combine(appSettings.WatchDirectory, $"{DateTime.Now.Ticks}.txt"), collection); + weekYearDirectory = Path.Combine(appSettings.WatchDirectory, $"{dateTime.Year}_Week_{weekOfYear}"); + if (!Directory.Exists(weekYearDirectory)) + _ = Directory.CreateDirectory(weekYearDirectory); + File.WriteAllLines(Path.Combine(weekYearDirectory, $"{dateTime.Ticks}.txt"), collection); collection.Clear(); for (int j = i + 1; j < lines.Length; j++) collection.Add(lines[j]); @@ -35,11 +43,14 @@ internal static partial class HelperStratus internal static bool MoveFile(AppSettings appSettings, ILogger logger) { - string file = Path.Combine(appSettings.WatchDirectory, appSettings.StratusConfiguration.WatchFile); + string checkFile = Path.Combine(appSettings.WatchDirectory, appSettings.StratusConfiguration.WatchFile); try - { TryMoveFile(appSettings, file); } + { TryMoveFile(appSettings, checkFile); } catch (Exception ex) - { logger.LogError(ex, "Inner loop error!"); } + { + logger.LogError(ex, "Inner loop error!"); + Thread.Sleep(appSettings.MillisecondsDelay * 5); + } return true; } diff --git a/Models/AppSettings.cs b/Models/AppSettings.cs index 0b1bde4..b2a3de5 100644 --- a/Models/AppSettings.cs +++ b/Models/AppSettings.cs @@ -4,6 +4,7 @@ using System.Text.Json.Serialization; namespace File_Watcher.Models; public record AppSettings(EAFLogConfiguration EAFLogConfiguration, + MetrologyConfiguration MetrologyConfiguration, StratusConfiguration StratusConfiguration, WaferCounterConfiguration WaferCounterConfiguration, string BuildNumber, diff --git a/Models/Binder/AppSettings.cs b/Models/Binder/AppSettings.cs index a466c08..27068a5 100644 --- a/Models/Binder/AppSettings.cs +++ b/Models/Binder/AppSettings.cs @@ -43,6 +43,7 @@ public class AppSettings private static Models.AppSettings Get(AppSettings? appSettings, Models.EAFLogConfiguration eafLogConfiguration, + Models.MetrologyConfiguration metrologyConfiguration, Models.StratusConfiguration stratusConfiguration, Models.WaferCounterConfiguration waferCounterConfiguration) { @@ -56,6 +57,7 @@ public class AppSettings if (appSettings.WatchDirectory is null) throw new NullReferenceException(nameof(WatchDirectory)); Verify(appSettings); result = new(eafLogConfiguration, + metrologyConfiguration, stratusConfiguration, waferCounterConfiguration, appSettings.BuildNumber, @@ -69,6 +71,7 @@ public class AppSettings public static Models.AppSettings Get(IConfigurationRoot configurationRoot, Models.EAFLogConfiguration eafLogConfiguration, + Models.MetrologyConfiguration metrologyConfiguration, Models.StratusConfiguration stratusConfiguration, Models.WaferCounterConfiguration waferCounterConfiguration) { @@ -79,6 +82,7 @@ public class AppSettings PreVerify(configurationRoot, appSettings); result = Get(appSettings, eafLogConfiguration, + metrologyConfiguration, stratusConfiguration, waferCounterConfiguration); return result; diff --git a/Models/Binder/MetrologyConfiguration.cs b/Models/Binder/MetrologyConfiguration.cs new file mode 100644 index 0000000..bf7ce75 --- /dev/null +++ b/Models/Binder/MetrologyConfiguration.cs @@ -0,0 +1,76 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace File_Watcher.Models.Binder; + +public class MetrologyConfiguration +{ + + public int? DirectoriesBack { get; set; } + public int? DeleteOlderThanWeeks { get; set; } + public string[]? HardcodedValues { get; set; } + public string[]? SourceDirectories { get; set; } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, BinderMetrologyConfigurationSourceGenerationContext.Default.MetrologyConfiguration); + return result; + } + + private static void PreVerify(IConfigurationRoot configurationRoot, MetrologyConfiguration? configuration) + { + if (configuration?.DirectoriesBack is null) + { + foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers) + { + if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider) + continue; + if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider) + continue; + if (!physicalFileProvider.Root.Contains("UserSecrets")) + continue; + throw new NotSupportedException(physicalFileProvider.Root); + } + throw new NotSupportedException("Not Found!"); + } + } + + private static void Verify(MetrologyConfiguration _) + { + } + + private static Models.MetrologyConfiguration Get(MetrologyConfiguration? configuration) + { + Models.MetrologyConfiguration result; + if (configuration is null) throw new NullReferenceException(nameof(configuration)); + if (configuration.DirectoriesBack is null) throw new NullReferenceException(nameof(configuration.DirectoriesBack)); + if (configuration.DeleteOlderThanWeeks is null) throw new NullReferenceException(nameof(configuration.DeleteOlderThanWeeks)); + if (configuration.HardcodedValues is null) throw new NullReferenceException(nameof(configuration.HardcodedValues)); + if (configuration.SourceDirectories is null) throw new NullReferenceException(nameof(configuration.SourceDirectories)); + Verify(configuration); + result = new(configuration.DirectoriesBack.Value, + configuration.DeleteOlderThanWeeks.Value, + configuration.HardcodedValues, + configuration.SourceDirectories); + return result; + } + + public static Models.MetrologyConfiguration Get(IConfigurationRoot configurationRoot) + { + Models.MetrologyConfiguration result; + IConfigurationSection configurationSection = configurationRoot.GetSection(nameof(Models.MetrologyConfiguration)); +#pragma warning disable IL3050, IL2026 + MetrologyConfiguration? configuration = configurationSection.Get(); +#pragma warning restore IL3050, IL2026 + PreVerify(configurationRoot, configuration); + result = Get(configuration); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(MetrologyConfiguration))] +internal partial class BinderMetrologyConfigurationSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Models/MetrologyConfiguration.cs b/Models/MetrologyConfiguration.cs new file mode 100644 index 0000000..eeeac12 --- /dev/null +++ b/Models/MetrologyConfiguration.cs @@ -0,0 +1,24 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace File_Watcher.Models; + +public record MetrologyConfiguration(int DirectoriesBack, + int DeleteOlderThanWeeks, + string[] HardcodedValues, + string[] SourceDirectories) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, MetrologyConfigurationSourceGenerationContext.Default.MetrologyConfiguration); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(MetrologyConfiguration))] +internal partial class MetrologyConfigurationSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index b39e50a..fc408fb 100644 --- a/Program.cs +++ b/Program.cs @@ -15,9 +15,10 @@ public class Program #pragma warning restore IL3050 _ = webApplicationBuilder.Configuration.AddUserSecrets(); EAFLogConfiguration eafLogConfiguration = Models.Binder.EAFLogConfiguration.Get(webApplicationBuilder.Configuration); + MetrologyConfiguration metrologyConfiguration = Models.Binder.MetrologyConfiguration.Get(webApplicationBuilder.Configuration); StratusConfiguration stratusConfiguration = Models.Binder.StratusConfiguration.Get(webApplicationBuilder.Configuration); WaferCounterConfiguration waferCounterConfiguration = Models.Binder.WaferCounterConfiguration.Get(webApplicationBuilder.Configuration); - AppSettings appSettings = Models.Binder.AppSettings.Get(webApplicationBuilder.Configuration, eafLogConfiguration, stratusConfiguration, waferCounterConfiguration); + AppSettings appSettings = Models.Binder.AppSettings.Get(webApplicationBuilder.Configuration, eafLogConfiguration, metrologyConfiguration, stratusConfiguration, waferCounterConfiguration); if (string.IsNullOrEmpty(appSettings.Company)) throw new Exception("Company name must have a value!"); try @@ -38,21 +39,21 @@ public class Program #pragma warning restore }); } - using IHost host = webApplicationBuilder.Build(); - logger = host.Services.GetRequiredService>(); + using WebApplication webApplication = webApplicationBuilder.Build(); + logger = webApplication.Services.GetRequiredService>(); if (string.IsNullOrEmpty(appSettings.Company)) { Environment.ExitCode = -1; - _ = host.StopAsync(); + _ = webApplication.StopAsync(); } logger.LogInformation("Starting Web Application"); logger.LogCritical("{Company}", appSettings.Company); - await host.RunAsync(); + await webApplication.RunAsync(); } catch (Exception ex) { try - { logger?.LogCritical(ex, "Host terminated unexpectedly"); } + { logger?.LogCritical(ex, "WebApplication terminated unexpectedly"); } catch (Exception) { } throw; } diff --git a/Worker.cs b/Worker.cs index 750fcb2..338714b 100644 --- a/Worker.cs +++ b/Worker.cs @@ -33,7 +33,9 @@ public partial class Worker : BackgroundService { nameof(Helpers.HelperEAFLog) => Helpers.HelperEAFLog.DeleteFiles(_AppSettings, _Logger), nameof(Helpers.HelperStratus) => Helpers.HelperStratus.MoveFile(_AppSettings, _Logger), + nameof(Helpers.HelperEventLog) => Helpers.HelperEventLog.ClearEventLogs(_AppSettings, _Logger), nameof(Helpers.HelperWaferCounter) => Helpers.HelperWaferCounter.MoveFile(_AppSettings, _Logger), + nameof(Helpers.HelperMetrologyFiles) => Helpers.HelperMetrologyFiles.SortAndDelete(_AppSettings, _Logger), _ => throw new NotSupportedException() }; }