using Microsoft.Extensions.Primitives; using Yarp.ReverseProxy.Configuration; using YarpGateway.Config; namespace YarpGateway.DynamicProxy; public class DynamicProxyConfigProvider : IProxyConfigProvider { private volatile IProxyConfig _config; private readonly DatabaseRouteConfigProvider _routeProvider; private readonly DatabaseClusterConfigProvider _clusterProvider; private readonly object _lock = new(); private CancellationTokenSource? _cts; public DynamicProxyConfigProvider( DatabaseRouteConfigProvider routeProvider, DatabaseClusterConfigProvider clusterProvider) { _routeProvider = routeProvider; _clusterProvider = clusterProvider; _cts = new CancellationTokenSource(); UpdateConfig(); } public IProxyConfig GetConfig() { return _config; } public void UpdateConfig() { lock (_lock) { _cts?.Cancel(); _cts = new CancellationTokenSource(); var routes = _routeProvider.GetRoutes(); var clusters = _clusterProvider.GetClusters(); _config = new InMemoryProxyConfig( routes, clusters, Array.Empty>(), _cts.Token ); } } public async Task ReloadAsync() { await _routeProvider.ReloadAsync(); await _clusterProvider.ReloadAsync(); UpdateConfig(); } private class InMemoryProxyConfig : IProxyConfig { private readonly CancellationChangeToken _changeToken; public InMemoryProxyConfig( IReadOnlyList routes, IReadOnlyList clusters, IReadOnlyList> transforms, CancellationToken token) { Routes = routes; Clusters = clusters; Transforms = transforms; _changeToken = new CancellationChangeToken(token); } public IReadOnlyList Routes { get; } public IReadOnlyList Clusters { get; } public IReadOnlyList> Transforms { get; } public IChangeToken ChangeToken => _changeToken; } }