Working on tenants and config

This commit is contained in:
Janus Knudsen 2025-01-21 17:40:23 +01:00
parent c10de11bbe
commit f3352318f5
12 changed files with 309 additions and 19 deletions

View file

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Configurations
{
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class KeyValueNester
{
private JObject _rootObject = new JObject();
public void AddKeyValue(string key, string jsonValue)
{
try
{
// Parse input JSON value
var valueObject = JsonConvert.DeserializeObject<JObject>(jsonValue);
var parts = key.Split(':');
// Start med root object eller nuværende struktur
JObject current = _rootObject;
// Gennemgå hver del af key'en
for (int i = 0; i < parts.Length - 1; i++)
{
string part = parts[i];
if (!current.ContainsKey(part))
{
current[part] = new JObject();
}
current = (JObject)current[part];
}
// Tilføj den sidste værdi
current[parts[^1]] = valueObject;
}
catch (JsonReaderException ex)
{
throw new ArgumentException("Invalid JSON value", nameof(jsonValue), ex);
}
}
public JObject GetResult()
{
return _rootObject;
}
public void Clear()
{
_rootObject = new JObject();
}
}
}

View file

@ -0,0 +1,115 @@
using Microsoft.Extensions.Configuration;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Configurations.PostgresqlConfigurationBuilder
{
public class PostgresConfigurationSource : IConfigurationSource
{
private readonly string _connectionString;
private readonly string _channel;
private readonly string _configurationQuery;
public PostgresConfigurationSource(string connectionString, string channel, string configurationQuery)
{
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
_configurationQuery = configurationQuery ?? throw new ArgumentNullException(nameof(configurationQuery));
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new PostgresConfigurationProvider(_connectionString, _channel, _configurationQuery);
}
}
public class PostgresConfigurationProvider : ConfigurationProvider, IDisposable
{
private readonly string _connectionString;
private readonly string _channel;
private readonly string _configurationQuery;
private readonly NpgsqlConnection _listenerConnection;
private bool _disposedValue;
public PostgresConfigurationProvider(string connectionString, string channel, string configurationQuery)
{
_connectionString = connectionString;
_channel = channel;
_configurationQuery = configurationQuery;
_listenerConnection = new NpgsqlConnection(connectionString);
// Start listening for notifications
StartListening();
}
private async void StartListening()
{
try
{
await _listenerConnection.OpenAsync();
_listenerConnection.Notification += OnNotificationReceived;
using var cmd = new NpgsqlCommand($"LISTEN {_channel};", _listenerConnection);
await cmd.ExecuteNonQueryAsync();
}
catch (Exception ex)
{
// Log error and possibly retry
Console.WriteLine($"Error starting listener: {ex.Message}");
}
}
private void OnNotificationReceived(object sender, NpgsqlNotificationEventArgs e)
{
if (e.Channel == _channel)
{
// Reload configuration and notify
Load();
OnReload();
}
}
public override void Load()
{
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
using (var connection = new NpgsqlConnection(_connectionString))
{
connection.Open();
using var cmd = new NpgsqlCommand(_configurationQuery, connection);
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
string key = reader.GetString(0);
string value = reader.GetString(1);
data[key] = value;
}
}
Data = data;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_listenerConnection?.Dispose();
}
_disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

View file

@ -0,0 +1,34 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Configurations.PostgresqlConfigurationBuilder
{
public static class PostgresConfigurationExtensions
{
public static IConfigurationBuilder AddPostgresConfiguration(
this IConfigurationBuilder builder,
Action<PostgresConfigurationOptions> setupAction)
{
var options = new PostgresConfigurationOptions();
setupAction(options);
builder.Add(new PostgresConfigurationSource(
options.ConnectionString,
options.Channel,
options.ConfigurationQuery));
return builder;
}
}
public class PostgresConfigurationOptions
{
public string ConnectionString { get; set; }
public string Channel { get; set; }
public string ConfigurationQuery { get; set; }
}
}

View file

@ -25,7 +25,6 @@ namespace Core.ModuleRegistry
public class TelemetryConfig
{
public string InstrumentationKey { get; set; }
public string ConnectionString { get; set; }
}
}