fengling-gateway/Config/DatabaseRouteConfigProvider.cs

84 lines
2.3 KiB
C#

using System.Collections.Concurrent;
using Microsoft.EntityFrameworkCore;
using Yarp.ReverseProxy.Configuration;
using YarpGateway.Data;
using YarpGateway.Models;
namespace YarpGateway.Config;
public class DatabaseRouteConfigProvider
{
private readonly IDbContextFactory<GatewayDbContext> _dbContextFactory;
private readonly ConcurrentDictionary<string, RouteConfig> _routes = new();
private readonly SemaphoreSlim _lock = new(1, 1);
private readonly ILogger<DatabaseRouteConfigProvider> _logger;
public DatabaseRouteConfigProvider(
IDbContextFactory<GatewayDbContext> dbContextFactory,
ILogger<DatabaseRouteConfigProvider> logger
)
{
_dbContextFactory = dbContextFactory;
_logger = logger;
_ = LoadConfigAsync();
}
public IReadOnlyList<RouteConfig> GetRoutes()
{
return _routes.Values.ToList().AsReadOnly();
}
public async Task ReloadAsync()
{
await _lock.WaitAsync();
try
{
await LoadConfigInternalAsync();
}
finally
{
_lock.Release();
}
}
private async Task LoadConfigAsync()
{
await LoadConfigInternalAsync();
}
private async Task LoadConfigInternalAsync()
{
await using var dbContext = _dbContextFactory.CreateDbContext();
var routes = await dbContext
.TenantRoutes.Where(r => r.Status == 1 && !r.IsDeleted)
.ToListAsync();
var newRoutes = new ConcurrentDictionary<string, RouteConfig>();
foreach (var route in routes)
{
var config = new RouteConfig
{
RouteId = route.Id.ToString(),
ClusterId = route.ClusterId,
Match = new RouteMatch { Path = route.PathPattern },
Metadata = new Dictionary<string, string>
{
["TenantCode"] = route.TenantCode,
["ServiceName"] = route.ServiceName,
},
};
newRoutes[route.Id.ToString()] = config;
}
_routes.Clear();
foreach (var route in newRoutes)
{
_routes[route.Key] = route.Value;
}
_logger.LogInformation("Loaded {Count} routes from database", _routes.Count);
}
}