116 lines
3 KiB
C#
116 lines
3 KiB
C#
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|