using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Microsoft.Extensions.Configuration; namespace Configuration.Core { public class KeyValueConfigurationBuilder { private readonly IConfigurationRepository _repository; private readonly JObject _rootObject = new(); private ConfigurationReloadToken _reloadToken = new(); private IConfiguration _configuration; private readonly object _configurationLock = new(); public KeyValueConfigurationBuilder(IConfigurationRepository repository) { _repository = repository ?? throw new ArgumentNullException(nameof(repository)); } /// /// Loads configurations from the repository and builds the configuration tree. /// public async Task LoadConfiguration() { try { var configurations = await _repository.GetActiveConfigurations(); foreach (var config in configurations) { AddKeyValue(config.Key, config.Value); } OnReload(); } catch (Exception ex) { // Log the exception or handle it as needed throw new InvalidOperationException("Failed to load configurations.", ex); } } /// /// Adds a key-value pair to the configuration tree. /// /// The key to add. /// The JSON value to add. public void AddKeyValue(string key, string jsonValue) { if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); if (string.IsNullOrEmpty(jsonValue)) throw new ArgumentNullException(nameof(jsonValue)); try { var valueObject = JsonConvert.DeserializeObject(jsonValue); var parts = key.Split(':'); JObject current = _rootObject; for (int i = 0; i < parts.Length - 1; i++) { var part = parts[i]; if (!current.ContainsKey(part)) { current[part] = new JObject(); } current = (JObject)current[part]; } current[parts[^1]] = valueObject; } catch (JsonException ex) { throw new ArgumentException("Invalid JSON value.", nameof(jsonValue), ex); } } private void OnReload() { var previousToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken()); previousToken.OnReload(); _configuration = null; // Reset the configuration to force a rebuild } /// /// Builds the configuration instance. /// /// The built instance. public IConfiguration Build() { if (_configuration == null) { lock (_configurationLock) { if (_configuration == null) { _configuration = new JsonConfiguration(_rootObject, _reloadToken); } } } return _configuration; } } }