From f2fd256aac0a82e2e85d574400d9531ef27374aa Mon Sep 17 00:00:00 2001 From: BlueXTX <48766766+BlueXTX@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:05:36 +0300 Subject: [PATCH] Get rid of static and use dependency injection instead (#8) * Improved thread safety and async processing in dump processor components * Removed unused _processedDumps field and simplified variable scope in QueuePipeline * Refactored service registration into dedicated extension methods * Added configuration binding and environment variables support * Refactored collector initialization to use dependency injection * Refactored data storage to use dependency injection * Refactored configuration models to use records and added validation * Refactored static loot configuration to use dependency injection The changes include: - Moved static weapon IDs and forced items from LootDumpProcessorContext to ForcedStatic record - Added ForcedStatic configuration injection in StaticLootProcessor and StaticContainerProcessor - Improved immutability by using read-only collections in ForcedStatic model - Simplified LootDumpProcessorContext by removing unused methods * Refactored configuration access to use dependency injection consistently * Fixed ForcedStatic configuration * Refactored forced items configuration to use async provider pattern The changes introduce a new `IForcedItemsProvider` abstraction to handle loading and caching of forced static and loose loot configurations. This improves the code by: 1. Making configuration loading asynchronous 2. Implementing caching of loaded configurations 3. Centralizing forced items configuration access 4. Removing direct file system dependencies from processors 5. Improving testability through dependency injection The change also updates related processors and interfaces to use async/await pattern consistently. * Refactored loose loot processor to use async forced items provider * Reorganized processor and service components into dedicated namespaces --- source/LootDumpProcessor/GCHandler.cs | 9 -- .../LootDumpProcessor.csproj | 4 + .../LootDumpProcessorContext.cs | 80 -------------- .../Model/Config/CollectorConfig.cs | 14 ++- .../LootDumpProcessor/Model/Config/Config.cs | 26 +++-- .../Model/Config/DataStorageConfig.cs | 12 +- .../Model/Config/DumpProcessorConfig.cs | 12 +- .../Model/Config/ForcedStatic.cs | 13 ++- .../Model/Config/ForcedStaticDto.cs | 13 +++ .../Model/Config/IntakeReaderConfig.cs | 9 +- .../Model/Config/ProcessorConfig.cs | 13 +-- .../Model/Config/ReaderConfig.cs | 17 +-- .../Model/Config/WriterConfig.cs | 9 +- .../Process/Collector/CollectorFactory.cs | 18 --- .../Process/Collector/DumpCollector.cs | 26 +++-- .../Process/IKeyGenerator.cs | 6 - .../{v2 => }/AmmoProcessor/AmmoProcessor.cs | 3 +- .../{v2 => }/AmmoProcessor/IAmmoProcessor.cs | 2 +- .../MultithreadSteppedDumpProcessor.cs | 48 ++++---- .../Processor/FileProcessor/FileProcessor.cs | 45 ++++---- .../Processor/FileProcessor/IFileProcessor.cs | 2 +- .../LooseLootProcessor/ILooseLootProcessor.cs | 8 +- .../LooseLootProcessor/LooseLootProcessor.cs | 34 ++++-- .../IStaticContainersProcessor.cs | 11 ++ .../StaticContainerProcessor.cs | 34 +++--- .../IStaticLootProcessor.cs | 4 +- .../StaticLootProcessor.cs | 14 ++- .../IStaticContainersProcessor.cs | 11 -- .../Process/QueuePipeline.cs | 40 ++++--- .../Reader/Filters/JsonDumpFileFilter.cs | 10 +- .../Reader/Intake/JsonFileIntakeReader.cs | 14 ++- .../ComposedKeyGenerator.cs | 4 +- .../IComposedKeyGenerator.cs | 2 +- .../ForcedItemsProvider.cs | 56 ++++++++++ .../IForcedItemsProvider.cs | 11 ++ .../Services/KeyGenerator/IKeyGenerator.cs | 6 + .../KeyGenerator}/NumericKeyGenerator.cs | 2 +- .../ITarkovItemsProvider.cs | 2 +- .../TarkovItemsProvider.cs | 12 +- .../Process/Writer/FileWriter.cs | 9 +- .../Process/Writer/WriterFactory.cs | 8 -- source/LootDumpProcessor/Program.cs | 34 +----- .../ServiceCollectionExtensions.cs | 103 ++++++++++++++++++ .../Storage/DataStorageFactory.cs | 32 ------ .../Implementations/File/FileDataStorage.cs | 11 +- .../File/Handlers/AbstractStoreHandler.cs | 10 +- .../File/Handlers/FlatStoreHandler.cs | 5 +- .../Handlers/SubdivisionedStoreHandler.cs | 5 +- .../File/StoreHandlerFactory.cs | 15 ++- 49 files changed, 489 insertions(+), 399 deletions(-) delete mode 100644 source/LootDumpProcessor/GCHandler.cs delete mode 100644 source/LootDumpProcessor/LootDumpProcessorContext.cs create mode 100644 source/LootDumpProcessor/Model/Config/ForcedStaticDto.cs delete mode 100644 source/LootDumpProcessor/Process/Collector/CollectorFactory.cs delete mode 100644 source/LootDumpProcessor/Process/IKeyGenerator.cs rename source/LootDumpProcessor/Process/Processor/{v2 => }/AmmoProcessor/AmmoProcessor.cs (93%) rename source/LootDumpProcessor/Process/Processor/{v2 => }/AmmoProcessor/IAmmoProcessor.cs (80%) rename source/LootDumpProcessor/Process/Processor/{v2 => }/LooseLootProcessor/ILooseLootProcessor.cs (62%) rename source/LootDumpProcessor/Process/Processor/{v2 => }/LooseLootProcessor/LooseLootProcessor.cs (88%) create mode 100644 source/LootDumpProcessor/Process/Processor/StaticContainersProcessor/IStaticContainersProcessor.cs rename source/LootDumpProcessor/Process/Processor/{v2 => }/StaticContainersProcessor/StaticContainerProcessor.cs (64%) rename source/LootDumpProcessor/Process/Processor/{v2 => }/StaticLootProcessor/IStaticLootProcessor.cs (65%) rename source/LootDumpProcessor/Process/Processor/{v2 => }/StaticLootProcessor/StaticLootProcessor.cs (85%) delete mode 100644 source/LootDumpProcessor/Process/Processor/v2/StaticContainersProcessor/IStaticContainersProcessor.cs rename source/LootDumpProcessor/Process/{ => Services/ComposedKeyGenerator}/ComposedKeyGenerator.cs (84%) rename source/LootDumpProcessor/Process/{ => Services/ComposedKeyGenerator}/IComposedKeyGenerator.cs (66%) create mode 100644 source/LootDumpProcessor/Process/Services/ForcedItemsProvider/ForcedItemsProvider.cs create mode 100644 source/LootDumpProcessor/Process/Services/ForcedItemsProvider/IForcedItemsProvider.cs create mode 100644 source/LootDumpProcessor/Process/Services/KeyGenerator/IKeyGenerator.cs rename source/LootDumpProcessor/Process/{ => Services/KeyGenerator}/NumericKeyGenerator.cs (79%) rename source/LootDumpProcessor/Process/{ => Services/TarkovItemsProvider}/ITarkovItemsProvider.cs (74%) rename source/LootDumpProcessor/Process/{ => Services/TarkovItemsProvider}/TarkovItemsProvider.cs (91%) delete mode 100644 source/LootDumpProcessor/Process/Writer/WriterFactory.cs create mode 100644 source/LootDumpProcessor/ServiceCollectionExtensions.cs delete mode 100644 source/LootDumpProcessor/Storage/DataStorageFactory.cs diff --git a/source/LootDumpProcessor/GCHandler.cs b/source/LootDumpProcessor/GCHandler.cs deleted file mode 100644 index f4efcb9..0000000 --- a/source/LootDumpProcessor/GCHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace LootDumpProcessor; - -public static class GCHandler -{ - public static void Collect() - { - if (LootDumpProcessorContext.GetConfig().ManualGarbageCollectionCalls) GC.Collect(); - } -} \ No newline at end of file diff --git a/source/LootDumpProcessor/LootDumpProcessor.csproj b/source/LootDumpProcessor/LootDumpProcessor.csproj index 64cb73e..16c0bb7 100644 --- a/source/LootDumpProcessor/LootDumpProcessor.csproj +++ b/source/LootDumpProcessor/LootDumpProcessor.csproj @@ -11,7 +11,11 @@ + + + + diff --git a/source/LootDumpProcessor/LootDumpProcessorContext.cs b/source/LootDumpProcessor/LootDumpProcessorContext.cs deleted file mode 100644 index 9c50f90..0000000 --- a/source/LootDumpProcessor/LootDumpProcessorContext.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Text.Json; -using LootDumpProcessor.Model.Config; -using LootDumpProcessor.Model.Output.StaticContainer; -using LootDumpProcessor.Serializers.Json; -using LootDumpProcessor.Serializers.Yaml; - -namespace LootDumpProcessor; - -public static class LootDumpProcessorContext -{ - private static Config? _config; - private static readonly object _configLock = new(); - private static ForcedStatic? _forcedStatic; - private static readonly object _forcedStaticLock = new(); - private static HashSet? _staticWeaponIds; - private static readonly object _staticWeaponIdsLock = new(); - private static Dictionary>? _forcedItems; - private static readonly object _forcedItemsLock = new(); - private static Dictionary>? _forcedLoose; - private static readonly object _forcedLooseLock = new(); - - public static Config GetConfig() - { - lock (_configLock) - { - if (_config == null) - // This is the only instance where manual selection of the serializer is required - // after this, GetInstance() for the JsonSerializerFactory should used without - // parameters - _config = JsonSerializer.Deserialize(File.ReadAllText("./Config/config.json"), - JsonSerializerSettings.Default); - } - - return _config; - } - - public static ForcedStatic GetForcedStatic() - { - lock (_forcedStaticLock) - { - if (_forcedStatic == null) - _forcedStatic = Yaml.Deserializer - .Deserialize(File.ReadAllText("./Config/forced_static.yaml")); - } - - return _forcedStatic; - } - - public static HashSet GetStaticWeaponIds() - { - lock (_staticWeaponIdsLock) - { - if (_staticWeaponIds == null) _staticWeaponIds = GetForcedStatic().StaticWeaponIds.ToHashSet(); - } - - return _staticWeaponIds; - } - - public static Dictionary> GetForcedItems() - { - lock (_forcedItemsLock) - { - if (_forcedItems == null) _forcedItems = GetForcedStatic().ForcedItems; - } - - return _forcedItems; - } - - public static Dictionary> GetForcedLooseItems() - { - lock (_forcedLooseLock) - { - if (_forcedLoose == null) - _forcedLoose = Yaml.Deserializer.Deserialize>>( - File.ReadAllText("./Config/forced_loose.yaml")); - } - - return _forcedLoose; - } -} \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/CollectorConfig.cs b/source/LootDumpProcessor/Model/Config/CollectorConfig.cs index 9c5d39e..42f8685 100644 --- a/source/LootDumpProcessor/Model/Config/CollectorConfig.cs +++ b/source/LootDumpProcessor/Model/Config/CollectorConfig.cs @@ -1,10 +1,12 @@ +using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; using LootDumpProcessor.Process.Collector; namespace LootDumpProcessor.Model.Config; -public class CollectorConfig -{ - public CollectorType CollectorType { get; set; } - public int MaxEntitiesBeforeDumping { get; set; } - public string DumpLocation { get; set; } -} \ No newline at end of file +[UsedImplicitly] +public record CollectorConfig( + [Required] CollectorType CollectorType, + [Required] int MaxEntitiesBeforeDumping, + [Required] string DumpLocation +); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/Config.cs b/source/LootDumpProcessor/Model/Config/Config.cs index 2d0f9a0..60f93b7 100644 --- a/source/LootDumpProcessor/Model/Config/Config.cs +++ b/source/LootDumpProcessor/Model/Config/Config.cs @@ -1,15 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; + namespace LootDumpProcessor.Model.Config; -public class Config +[UsedImplicitly] +public record Config { - public string ServerLocation { get; set; } = string.Empty; - public bool ManualGarbageCollectionCalls { get; set; } - public DataStorageConfig DataStorageConfig { get; set; } - public ReaderConfig ReaderConfig { get; set; } - public ProcessorConfig ProcessorConfig { get; set; } - public DumpProcessorConfig DumpProcessorConfig { get; set; } - public WriterConfig WriterConfig { get; set; } - public CollectorConfig CollectorConfig { get; set; } - public Dictionary ContainerIgnoreList { get; set; } - public List MapsToProcess { get; set; } + [Required] public string ServerLocation { get; init; } = string.Empty; + [Required] public bool ManualGarbageCollectionCalls { get; init; } + [Required] public DataStorageConfig DataStorageConfig { get; init; } = null!; + [Required] public ReaderConfig ReaderConfig { get; init; } = null!; + [Required] public ProcessorConfig ProcessorConfig { get; init; } = null!; + [Required] public DumpProcessorConfig DumpProcessorConfig { get; init; } = null!; + [Required] public WriterConfig WriterConfig { get; init; } = null!; + [Required] public CollectorConfig CollectorConfig { get; init; } = null!; + [Required] public IReadOnlyDictionary ContainerIgnoreList { get; init; } = null!; + [Required] public IReadOnlyList MapsToProcess { get; init; } = null!; } \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/DataStorageConfig.cs b/source/LootDumpProcessor/Model/Config/DataStorageConfig.cs index a6f9def..612bba4 100644 --- a/source/LootDumpProcessor/Model/Config/DataStorageConfig.cs +++ b/source/LootDumpProcessor/Model/Config/DataStorageConfig.cs @@ -1,10 +1,12 @@ +using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; using LootDumpProcessor.Storage; namespace LootDumpProcessor.Model.Config; -public class DataStorageConfig -{ - public DataStorageTypes DataStorageType { get; set; } = DataStorageTypes.File; - public string? FileDataStorageTempLocation { get; set; } -} \ No newline at end of file +[UsedImplicitly] +public record DataStorageConfig( + [Required] string FileDataStorageTempLocation, + [Required] DataStorageTypes DataStorageType = DataStorageTypes.File +); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/DumpProcessorConfig.cs b/source/LootDumpProcessor/Model/Config/DumpProcessorConfig.cs index 6dfe09a..dc10f48 100644 --- a/source/LootDumpProcessor/Model/Config/DumpProcessorConfig.cs +++ b/source/LootDumpProcessor/Model/Config/DumpProcessorConfig.cs @@ -1,10 +1,12 @@ -using System.Text.Json.Serialization; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using JetBrains.Annotations; using LootDumpProcessor.Serializers.Json.Converters; namespace LootDumpProcessor.Model.Config; -public class DumpProcessorConfig -{ - [JsonConverter(typeof(NetDateTimeConverter))] public DateTime SpawnContainerChanceIncludeAfterDate { get; set; } -} \ No newline at end of file +[UsedImplicitly] +public record DumpProcessorConfig( + [Required] [property: JsonConverter(typeof(NetDateTimeConverter))] DateTime SpawnContainerChanceIncludeAfterDate +); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/ForcedStatic.cs b/source/LootDumpProcessor/Model/Config/ForcedStatic.cs index ef10aff..da32f67 100644 --- a/source/LootDumpProcessor/Model/Config/ForcedStatic.cs +++ b/source/LootDumpProcessor/Model/Config/ForcedStatic.cs @@ -1,11 +1,14 @@ +using System.Collections.Frozen; +using JetBrains.Annotations; using LootDumpProcessor.Model.Output.StaticContainer; -using YamlDotNet.Serialization; namespace LootDumpProcessor.Model.Config; -public class ForcedStatic +[UsedImplicitly] +public class ForcedStatic( + IReadOnlyList staticWeaponIds, FrozenDictionary> forcedItems +) { - [YamlMember(Alias = "static_weapon_ids")] public List StaticWeaponIds { get; set; } - - [YamlMember(Alias = "forced_items")] public Dictionary> ForcedItems { get; set; } + public readonly IReadOnlyList StaticWeaponIds = staticWeaponIds; + public readonly FrozenDictionary> ForcedItems = forcedItems; } \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/ForcedStaticDto.cs b/source/LootDumpProcessor/Model/Config/ForcedStaticDto.cs new file mode 100644 index 0000000..e5aa6b2 --- /dev/null +++ b/source/LootDumpProcessor/Model/Config/ForcedStaticDto.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using LootDumpProcessor.Model.Output.StaticContainer; +using YamlDotNet.Serialization; + +namespace LootDumpProcessor.Model.Config; + +[UsedImplicitly] +public class ForcedStaticDto +{ + [YamlMember(Alias = "static_weapon_ids")] public List StaticWeaponIds { get; set; } + + [YamlMember(Alias = "forced_items")] public Dictionary> ForcedItems { get; set; } +} \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/IntakeReaderConfig.cs b/source/LootDumpProcessor/Model/Config/IntakeReaderConfig.cs index 961f6e5..1db5aec 100644 --- a/source/LootDumpProcessor/Model/Config/IntakeReaderConfig.cs +++ b/source/LootDumpProcessor/Model/Config/IntakeReaderConfig.cs @@ -1,7 +1,6 @@ +using JetBrains.Annotations; + namespace LootDumpProcessor.Model.Config; -public class IntakeReaderConfig -{ - public int MaxDumpsPerMap { get; set; } = 1500; - public List IgnoredDumpLocations { get; set; } = new(); -} \ No newline at end of file +[UsedImplicitly] +public record IntakeReaderConfig(IReadOnlyList IgnoredDumpLocations, int MaxDumpsPerMap = 1500); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/ProcessorConfig.cs b/source/LootDumpProcessor/Model/Config/ProcessorConfig.cs index 0e89f98..ad1a018 100644 --- a/source/LootDumpProcessor/Model/Config/ProcessorConfig.cs +++ b/source/LootDumpProcessor/Model/Config/ProcessorConfig.cs @@ -1,13 +1,6 @@ -using System.Text.Json.Serialization; - +using JetBrains.Annotations; namespace LootDumpProcessor.Model.Config; -public class ProcessorConfig -{ - [JsonPropertyName("spawnPointToleranceForForced")] public double SpawnPointToleranceForForced { get; set; } = 99D; - - - [JsonPropertyName("looseLootCountTolerancePercentage")] - public double LooseLootCountTolerancePercentage { get; set; } = 75D; -} \ No newline at end of file +[UsedImplicitly] +public record ProcessorConfig(double SpawnPointToleranceForForced = 99, double LooseLootCountTolerancePercentage = 75); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/ReaderConfig.cs b/source/LootDumpProcessor/Model/Config/ReaderConfig.cs index 0627b2e..ba4f7db 100644 --- a/source/LootDumpProcessor/Model/Config/ReaderConfig.cs +++ b/source/LootDumpProcessor/Model/Config/ReaderConfig.cs @@ -1,9 +1,12 @@ +using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; + namespace LootDumpProcessor.Model.Config; -public class ReaderConfig -{ - public IntakeReaderConfig? IntakeReaderConfig { get; set; } - public List? DumpFilesLocation { get; set; } - public string? ThresholdDate { get; set; } - public bool ProcessSubFolders { get; set; } -} \ No newline at end of file +[UsedImplicitly] +public record ReaderConfig( + [Required] IntakeReaderConfig IntakeReaderConfig, + [Required] IReadOnlyList DumpFilesLocation, + string? ThresholdDate, + bool ProcessSubFolders = true +); \ No newline at end of file diff --git a/source/LootDumpProcessor/Model/Config/WriterConfig.cs b/source/LootDumpProcessor/Model/Config/WriterConfig.cs index bb19e8f..b12f69f 100644 --- a/source/LootDumpProcessor/Model/Config/WriterConfig.cs +++ b/source/LootDumpProcessor/Model/Config/WriterConfig.cs @@ -1,9 +1,8 @@ -using System.Text.Json.Serialization; +using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; namespace LootDumpProcessor.Model.Config; -public class WriterConfig -{ - [JsonPropertyName("outputLocation")] public string? OutputLocation { get; set; } -} \ No newline at end of file +[UsedImplicitly] +public record WriterConfig([Required] string OutputLocation); \ No newline at end of file diff --git a/source/LootDumpProcessor/Process/Collector/CollectorFactory.cs b/source/LootDumpProcessor/Process/Collector/CollectorFactory.cs deleted file mode 100644 index e5bdd09..0000000 --- a/source/LootDumpProcessor/Process/Collector/CollectorFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace LootDumpProcessor.Process.Collector; - -public static class CollectorFactory -{ - private static ICollector? _collector; - - public static ICollector GetInstance() - { - if (_collector == null) - _collector = LootDumpProcessorContext.GetConfig().CollectorConfig.CollectorType switch - { - CollectorType.Memory => new HashSetCollector(), - CollectorType.Dump => new DumpCollector(), - _ => throw new ArgumentOutOfRangeException() - }; - return _collector; - } -} \ No newline at end of file diff --git a/source/LootDumpProcessor/Process/Collector/DumpCollector.cs b/source/LootDumpProcessor/Process/Collector/DumpCollector.cs index d0a19f4..2895a76 100644 --- a/source/LootDumpProcessor/Process/Collector/DumpCollector.cs +++ b/source/LootDumpProcessor/Process/Collector/DumpCollector.cs @@ -1,16 +1,18 @@ using System.Text.Json; +using LootDumpProcessor.Model.Config; using LootDumpProcessor.Model.Processing; using LootDumpProcessor.Serializers.Json; +using Microsoft.Extensions.Options; namespace LootDumpProcessor.Process.Collector; -public class DumpCollector : ICollector +public class DumpCollector(IOptions config) : ICollector { - private static readonly string DumpLocation = - $"{LootDumpProcessorContext.GetConfig().CollectorConfig.DumpLocation}/collector/"; + private readonly Config _config = (config ?? throw new ArgumentNullException(nameof(config))).Value; - private readonly List processedDumps = - new(LootDumpProcessorContext.GetConfig().CollectorConfig.MaxEntitiesBeforeDumping + 50); + private string DumpLocation => Path.Combine(_config.CollectorConfig.DumpLocation, "collector"); + + private List ProcessedDumps => new(_config.CollectorConfig.MaxEntitiesBeforeDumping + 50); private readonly object lockObject = new(); @@ -25,13 +27,13 @@ public class DumpCollector : ICollector { lock (lockObject) { - processedDumps.Add(parsedDump); - if (processedDumps.Count > LootDumpProcessorContext.GetConfig().CollectorConfig.MaxEntitiesBeforeDumping) + ProcessedDumps.Add(parsedDump); + if (ProcessedDumps.Count > _config.CollectorConfig.MaxEntitiesBeforeDumping) { var fileName = $"collector-{DateTime.Now.ToString("yyyyMMddHHmmssfffff")}.json"; File.WriteAllText($"{DumpLocation}{fileName}", - JsonSerializer.Serialize(processedDumps, JsonSerializerSettings.Default)); - processedDumps.Clear(); + JsonSerializer.Serialize(ProcessedDumps, JsonSerializerSettings.Default)); + ProcessedDumps.Clear(); } } } @@ -39,10 +41,10 @@ public class DumpCollector : ICollector public List Retrieve() { foreach (var file in Directory.GetFiles(DumpLocation)) - processedDumps.AddRange(JsonSerializer + ProcessedDumps.AddRange(JsonSerializer .Deserialize>(File.ReadAllText(file), JsonSerializerSettings.Default)); - return processedDumps; + return ProcessedDumps; } public void Clear() @@ -51,7 +53,7 @@ public class DumpCollector : ICollector { foreach (var file in Directory.GetFiles(DumpLocation)) File.Delete(file); - processedDumps.Clear(); + ProcessedDumps.Clear(); } } } \ No newline at end of file diff --git a/source/LootDumpProcessor/Process/IKeyGenerator.cs b/source/LootDumpProcessor/Process/IKeyGenerator.cs deleted file mode 100644 index 5bf967e..0000000 --- a/source/LootDumpProcessor/Process/IKeyGenerator.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace LootDumpProcessor.Process; - -public interface IKeyGenerator -{ - string Generate(); -} \ No newline at end of file diff --git a/source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/AmmoProcessor.cs b/source/LootDumpProcessor/Process/Processor/AmmoProcessor/AmmoProcessor.cs similarity index 93% rename from source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/AmmoProcessor.cs rename to source/LootDumpProcessor/Process/Processor/AmmoProcessor/AmmoProcessor.cs index fe65694..5994eb5 100644 --- a/source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/AmmoProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/AmmoProcessor/AmmoProcessor.cs @@ -1,8 +1,9 @@ using LootDumpProcessor.Model.Output; using LootDumpProcessor.Model.Processing; +using LootDumpProcessor.Process.Services.TarkovItemsProvider; using Microsoft.Extensions.Logging; -namespace LootDumpProcessor.Process.Processor.v2.AmmoProcessor; +namespace LootDumpProcessor.Process.Processor.AmmoProcessor; public class AmmoProcessor(ILogger logger, ITarkovItemsProvider tarkovItemsProvider) : IAmmoProcessor { diff --git a/source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/IAmmoProcessor.cs b/source/LootDumpProcessor/Process/Processor/AmmoProcessor/IAmmoProcessor.cs similarity index 80% rename from source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/IAmmoProcessor.cs rename to source/LootDumpProcessor/Process/Processor/AmmoProcessor/IAmmoProcessor.cs index d7e703d..9547ace 100644 --- a/source/LootDumpProcessor/Process/Processor/v2/AmmoProcessor/IAmmoProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/AmmoProcessor/IAmmoProcessor.cs @@ -1,7 +1,7 @@ using LootDumpProcessor.Model.Output; using LootDumpProcessor.Model.Processing; -namespace LootDumpProcessor.Process.Processor.v2.AmmoProcessor; +namespace LootDumpProcessor.Process.Processor.AmmoProcessor; public interface IAmmoProcessor { diff --git a/source/LootDumpProcessor/Process/Processor/DumpProcessor/MultithreadSteppedDumpProcessor.cs b/source/LootDumpProcessor/Process/Processor/DumpProcessor/MultithreadSteppedDumpProcessor.cs index 1e5aaea..0fea688 100644 --- a/source/LootDumpProcessor/Process/Processor/DumpProcessor/MultithreadSteppedDumpProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/DumpProcessor/MultithreadSteppedDumpProcessor.cs @@ -1,20 +1,23 @@ using System.Collections.Concurrent; using System.Text.Json; using LootDumpProcessor.Model; +using LootDumpProcessor.Model.Config; using LootDumpProcessor.Model.Input; using LootDumpProcessor.Model.Output; using LootDumpProcessor.Model.Output.LooseLoot; using LootDumpProcessor.Model.Output.StaticContainer; using LootDumpProcessor.Model.Processing; -using LootDumpProcessor.Process.Processor.v2.AmmoProcessor; -using LootDumpProcessor.Process.Processor.v2.LooseLootProcessor; -using LootDumpProcessor.Process.Processor.v2.StaticContainersProcessor; -using LootDumpProcessor.Process.Processor.v2.StaticLootProcessor; +using LootDumpProcessor.Process.Processor.AmmoProcessor; +using LootDumpProcessor.Process.Processor.LooseLootProcessor; +using LootDumpProcessor.Process.Processor.StaticContainersProcessor; +using LootDumpProcessor.Process.Processor.StaticLootProcessor; +using LootDumpProcessor.Process.Services.KeyGenerator; using LootDumpProcessor.Serializers.Json; using LootDumpProcessor.Storage; using LootDumpProcessor.Storage.Collections; using LootDumpProcessor.Utils; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace LootDumpProcessor.Process.Processor.DumpProcessor; @@ -23,7 +26,8 @@ public class MultithreadSteppedDumpProcessor( IStaticContainersProcessor staticContainersProcessor, IAmmoProcessor ammoProcessor, ILooseLootProcessor looseLootProcessor, - ILogger logger, IKeyGenerator keyGenerator + ILogger logger, IKeyGenerator keyGenerator, IDataStorage dataStorage, + IOptions config ) : IDumpProcessor { @@ -45,8 +49,10 @@ public class MultithreadSteppedDumpProcessor( private readonly IKeyGenerator _keyGenerator = keyGenerator ?? throw new ArgumentNullException(nameof(keyGenerator)); - private static readonly IDataStorage _dataStorage = DataStorageFactory.GetInstance(); + private readonly IDataStorage _dataStorage = dataStorage ?? throw new ArgumentNullException(nameof(dataStorage)); + private readonly Config _config = (config ?? throw new ArgumentNullException(nameof(config))).Value; + public async Task> ProcessDumps(List dumps) { _logger.LogInformation("Starting final dump processing"); @@ -111,12 +117,12 @@ public class MultithreadSteppedDumpProcessor( _logger.LogInformation("Processing loose loot distribution"); var looseLoot = new ConcurrentDictionary(); - Parallel.ForEach(dumpProcessData.MapCounts.Keys, parallelOptions, mapId => + await Parallel.ForEachAsync(dumpProcessData.MapCounts.Keys, parallelOptions, async (mapId, _) => { var mapCount = dumpProcessData.MapCounts[mapId]; var looseLootCount = dumpProcessData.LooseLootCounts[mapId]; var looseLootDistribution = - _looseLootProcessor.CreateLooseLootDistribution(mapId, mapCount, looseLootCount); + await _looseLootProcessor.CreateLooseLootDistribution(mapId, mapCount, looseLootCount); looseLoot[mapId] = looseLootDistribution; }); _logger.LogInformation("Collecting loose loot distribution information"); @@ -159,8 +165,7 @@ public class MultithreadSteppedDumpProcessor( } else { - var mapStaticContainers = - _staticContainersProcessor.CreateStaticWeaponsAndForcedContainers(dataDump); + var mapStaticContainers = await _staticContainersProcessor.CreateStaticWeaponsAndForcedContainers(dataDump); var newStaticWeapons = mapStaticContainers.StaticWeapons.Where(x => !mapStaticLoot.StaticWeapons.Exists(y => y.Id == x.Id)); @@ -172,7 +177,7 @@ public class MultithreadSteppedDumpProcessor( } if (!mapStaticContainersAggregated.TryGetValue(mapId, - out ConcurrentDictionary mapAggregatedDataDict)) + out var mapAggregatedDataDict)) { mapAggregatedDataDict = new ConcurrentDictionary(); mapStaticContainersAggregated.TryAdd(mapId, mapAggregatedDataDict); @@ -182,9 +187,9 @@ public class MultithreadSteppedDumpProcessor( IncrementMapCounterDictionaryValue(mapDumpCounter, mapId); - var containerIgnoreListExists = LootDumpProcessorContext.GetConfig().ContainerIgnoreList + var containerIgnoreListExists = _config.ContainerIgnoreList .TryGetValue(mapId, out var ignoreListForMap); - foreach (var dynamicStaticContainer in _staticContainersProcessor.CreateDynamicStaticContainers( + foreach (var dynamicStaticContainer in await _staticContainersProcessor.CreateDynamicStaticContainers( dataDump)) { if (containerIgnoreListExists && ignoreListForMap.Contains(dynamicStaticContainer.Id)) continue; @@ -193,16 +198,17 @@ public class MultithreadSteppedDumpProcessor( mapAggregatedDataDict[dynamicStaticContainer] += 1; } - GCHandler.Collect(); + if (_config.ManualGarbageCollectionCalls) GC.Collect(); } - private static bool DumpWasMadeAfterConfigThresholdDate(PartialData dataDump) => + private bool DumpWasMadeAfterConfigThresholdDate(PartialData dataDump) => FileDateParser.TryParseFileDate(dataDump.BasicInfo.FileName, out var fileDate) && fileDate.HasValue && - fileDate.Value > LootDumpProcessorContext.GetConfig().DumpProcessorConfig + fileDate.Value > _config.DumpProcessorConfig .SpawnContainerChanceIncludeAfterDate; - private static void IncrementMapCounterDictionaryValue(ConcurrentDictionary mapDumpCounter, string mapName) + private static void IncrementMapCounterDictionaryValue(ConcurrentDictionary mapDumpCounter, + string mapName) { if (!mapDumpCounter.TryAdd(mapName, 1)) mapDumpCounter[mapName] += 1; } @@ -247,7 +253,7 @@ public class MultithreadSteppedDumpProcessor( partialFileMetaData = null; tuple = null; - GCHandler.Collect(); + if (_config.ManualGarbageCollectionCalls) GC.Collect(); var parallelOptions = new ParallelOptions { @@ -266,14 +272,14 @@ public class MultithreadSteppedDumpProcessor( _dataStorage.Store(dictionaryCounts); dictionaryCounts = null; - GCHandler.Collect(); + if (_config.ManualGarbageCollectionCalls) GC.Collect(); _dataStorage.Store(actualDictionaryItemProperties); actualDictionaryItemProperties = null; - GCHandler.Collect(); + if (_config.ManualGarbageCollectionCalls) GC.Collect(); _dataStorage.Store(looseLootCounts); looseLootCounts = null; - GCHandler.Collect(); + if (_config.ManualGarbageCollectionCalls) GC.Collect(); }); return dumpProcessData; } diff --git a/source/LootDumpProcessor/Process/Processor/FileProcessor/FileProcessor.cs b/source/LootDumpProcessor/Process/Processor/FileProcessor/FileProcessor.cs index 428c01b..522d27e 100644 --- a/source/LootDumpProcessor/Process/Processor/FileProcessor/FileProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/FileProcessor/FileProcessor.cs @@ -1,32 +1,33 @@ using LootDumpProcessor.Model; using LootDumpProcessor.Model.Processing; -using LootDumpProcessor.Process.Processor.v2.LooseLootProcessor; -using LootDumpProcessor.Process.Processor.v2.StaticLootProcessor; +using LootDumpProcessor.Process.Processor.LooseLootProcessor; +using LootDumpProcessor.Process.Processor.StaticLootProcessor; using LootDumpProcessor.Storage; using Microsoft.Extensions.Logging; namespace LootDumpProcessor.Process.Processor.FileProcessor; -public class FileProcessor : IFileProcessor +public class FileProcessor( + IStaticLootProcessor staticLootProcessor, + ILooseLootProcessor looseLootProcessor, + ILogger logger, IDataStorage dataStorage +) + : IFileProcessor { - private readonly IStaticLootProcessor _staticLootProcessor; - private readonly ILooseLootProcessor _looseLootProcessor; - private readonly ILogger _logger; + private readonly IStaticLootProcessor _staticLootProcessor = staticLootProcessor + ?? throw new ArgumentNullException( + nameof(staticLootProcessor)); - public FileProcessor( - IStaticLootProcessor staticLootProcessor, - ILooseLootProcessor looseLootProcessor, - ILogger logger) - { - _staticLootProcessor = staticLootProcessor - ?? throw new ArgumentNullException(nameof(staticLootProcessor)); - _looseLootProcessor = looseLootProcessor - ?? throw new ArgumentNullException(nameof(looseLootProcessor)); - _logger = logger - ?? throw new ArgumentNullException(nameof(logger)); - } + private readonly ILooseLootProcessor _looseLootProcessor = looseLootProcessor + ?? throw new ArgumentNullException( + nameof(looseLootProcessor)); - public PartialData Process(BasicInfo parsedData) + private readonly ILogger _logger = logger + ?? throw new ArgumentNullException(nameof(logger)); + + private readonly IDataStorage _dataStorage = dataStorage ?? throw new ArgumentNullException(nameof(dataStorage)); + + public async Task Process(BasicInfo parsedData) { _logger.LogDebug("Processing file {FileName}...", parsedData.FileName); @@ -50,16 +51,16 @@ public class FileProcessor : IFileProcessor ParsedDumpKey = (AbstractKey)dumpData.GetKey() }; - if (!DataStorageFactory.GetInstance().Exists(dumpData.GetKey())) + if (!_dataStorage.Exists(dumpData.GetKey())) { _logger.LogDebug( "Cache not found for {LookupIndex} processing.", string.Join("/", dumpData.GetKey().GetLookupIndex()) ); - dumpData.Containers = _staticLootProcessor.PreProcessStaticLoot(staticLoot); + dumpData.Containers = await _staticLootProcessor.PreProcessStaticLoot(staticLoot); dumpData.LooseLoot = _looseLootProcessor.PreProcessLooseLoot(looseLoot); - DataStorageFactory.GetInstance().Store(dumpData); + dataStorage.Store(dumpData); } _logger.LogDebug("File {FileName} finished processing!", parsedData.FileName); diff --git a/source/LootDumpProcessor/Process/Processor/FileProcessor/IFileProcessor.cs b/source/LootDumpProcessor/Process/Processor/FileProcessor/IFileProcessor.cs index 04e66d6..d096a90 100644 --- a/source/LootDumpProcessor/Process/Processor/FileProcessor/IFileProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/FileProcessor/IFileProcessor.cs @@ -4,5 +4,5 @@ namespace LootDumpProcessor.Process.Processor.FileProcessor; public interface IFileProcessor { - PartialData Process(BasicInfo parsedData); + Task Process(BasicInfo parsedData); } \ No newline at end of file diff --git a/source/LootDumpProcessor/Process/Processor/v2/LooseLootProcessor/ILooseLootProcessor.cs b/source/LootDumpProcessor/Process/Processor/LooseLootProcessor/ILooseLootProcessor.cs similarity index 62% rename from source/LootDumpProcessor/Process/Processor/v2/LooseLootProcessor/ILooseLootProcessor.cs rename to source/LootDumpProcessor/Process/Processor/LooseLootProcessor/ILooseLootProcessor.cs index 94bf430..dc9bb65 100644 --- a/source/LootDumpProcessor/Process/Processor/v2/LooseLootProcessor/ILooseLootProcessor.cs +++ b/source/LootDumpProcessor/Process/Processor/LooseLootProcessor/ILooseLootProcessor.cs @@ -3,15 +3,13 @@ using LootDumpProcessor.Model.Output.LooseLoot; using LootDumpProcessor.Model.Processing; using LootDumpProcessor.Storage; -namespace LootDumpProcessor.Process.Processor.v2.LooseLootProcessor; +namespace LootDumpProcessor.Process.Processor.LooseLootProcessor; public interface ILooseLootProcessor { PreProcessedLooseLoot PreProcessLooseLoot(List