using NPin.Framework.SettingManagement.Domain.Caching; using NPin.Framework.SettingManagement.Domain.Entities; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Settings; using Volo.Abp.Uow; namespace NPin.Framework.SettingManagement.Domain.Store; public class SettingManagementStore : ISettingManagementStore, ITransientDependency { protected IDistributedCache Cache { get; } protected ISettingDefinitionManager SettingDefinitionManager { get; } protected ISettingRepository SettingRepository { get; } protected IGuidGenerator GuidGenerator { get; } public SettingManagementStore(IDistributedCache cache, ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository, IGuidGenerator guidGenerator) { Cache = cache; SettingDefinitionManager = settingDefinitionManager; SettingRepository = settingRepository; GuidGenerator = guidGenerator; } [UnitOfWork] public virtual async Task GetOrNullAsync(string name, string providerName, string providerKey) { return (await GetCacheItemAsync(name, providerName, providerKey)).Value; } [UnitOfWork] public virtual async Task> GetListAsync(string providerName, string providerKey) { var settings = await SettingRepository.GetListAsync(providerName, providerKey); return settings.Select(s => new SettingValue(s.Name, s.Value)).ToList(); } [UnitOfWork] public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey) { Check.NotNullOrEmpty(names, nameof(names)); var result = new List(); if (names.Length == 1) { var name = names.First(); result.Add(new SettingValue(name, (await GetCacheItemAsync(name, providerName, providerKey)).Value)); return result; } var cacheItems = await GetCacheItemsAsync(names, providerName, providerKey); result.AddRange(cacheItems.Select(item => new SettingValue(GetSettingNameFormCacheKeyOrNull(item.Key), item.Value?.Value))); return result; } [UnitOfWork] public virtual async Task SetAsync(string name, string value, string providerName, string providerKey) { var setting = await SettingRepository.FindAsync(name, providerName, providerKey); if (setting == null) { setting = new SettingEntity(GuidGenerator.Create(), name, value, providerName, providerKey); await SettingRepository.InsertAsync(setting); } else { setting.Value = value; await SettingRepository.UpdateAsync(setting); } await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new SettingCacheItem(setting.Value), considerUow: true); } [UnitOfWork] public virtual async Task DeleteAsync(string name, string providerName, string providerKey) { var setting = await SettingRepository.FindAsync(name, providerName, providerKey); if (setting != null) { await SettingRepository.DeleteAsync(setting); await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true); } } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); if (cacheItem != null) { return cacheItem; } cacheItem = new SettingCacheItem(null); await SetCacheItemsAsync(providerName, providerKey, name, cacheItem); return cacheItem; } protected virtual async Task>> GetCacheItemsAsync(string[] names, string providerName, string providerKey) { var cacheKeys = names.Select(x => CalculateCacheKey(x, providerName, providerKey)).ToList(); var cacheItems = (await Cache.GetManyAsync(cacheKeys, considerUow: true)).ToList(); if (cacheItems.All(x => x.Value != null)) { return cacheItems; } var notCacheKeys = cacheItems.Where(x => x.Value == null).Select(x => x.Key).ToList(); var newCacheItems = await SetCacheItemsAsync(providerName, providerKey, notCacheKeys); var result = new List>(); foreach (var key in cacheKeys) { var item = newCacheItems.FirstOrDefault(x => x.Key == key); if (item.Value == null) { item = cacheItems.FirstOrDefault(x => x.Key == key); } result.Add(new KeyValuePair(key, item.Value)); } return result; } private async Task SetCacheItemsAsync( string providerName, string providerKey, string currentName, SettingCacheItem currentCacheItem) { var settingDefinitions = await SettingDefinitionManager.GetAllAsync(); var settingsDictionary = (await SettingRepository.GetListAsync(providerName, providerKey)) .ToDictionary(s => s.Name, s => s.Value); var cacheItems = new List>(); foreach (var settingDefinition in settingDefinitions) { var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name); cacheItems.Add( new KeyValuePair( CalculateCacheKey(settingDefinition.Name, providerName, providerKey), new SettingCacheItem(settingValue) ) ); if (settingDefinition.Name == currentName) { currentCacheItem.Value = settingValue; } } await Cache.SetManyAsync(cacheItems, considerUow: true); } private async Task>> SetCacheItemsAsync( string providerName, string providerKey, List notCacheKeys) { var settingDefinitions = (await SettingDefinitionManager.GetAllAsync()).Where(x => notCacheKeys.Any(k => GetSettingNameFormCacheKeyOrNull(k) == x.Name)); var settingsDictionary = (await SettingRepository.GetListAsync(notCacheKeys.Select(GetSettingNameFormCacheKeyOrNull).ToArray(), providerName, providerKey)) .ToDictionary(s => s.Name, s => s.Value); var cacheItems = new List>(); foreach (var settingDefinition in settingDefinitions) { var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name); cacheItems.Add( new KeyValuePair( CalculateCacheKey(settingDefinition.Name, providerName, providerKey), new SettingCacheItem(settingValue) ) ); } await Cache.SetManyAsync(cacheItems, considerUow: true); return cacheItems; } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) { return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey); } protected virtual string? GetSettingNameFormCacheKeyOrNull(string key) { //TODO: throw ex when name is null? return SettingCacheItem.GetSettingNameFormCacheKeyOrNull(key); } }