Changes: - Remove deprecated Fengling.Activity and YarpGateway.Admin projects - Add points processing services with distributed lock support - Update Vben frontend with gateway management pages - Add gateway config controller and database listener - Update routing to use header-mixed-nav layout - Add comprehensive test suites for Member services - Add YarpGateway integration tests - Update package versions in Directory.Packages.props Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
119 lines
3.6 KiB
C#
119 lines
3.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Options;
|
|
using Serilog;
|
|
using Yarp.ReverseProxy.Configuration;
|
|
using Yarp.ReverseProxy.LoadBalancing;
|
|
using YarpGateway.Config;
|
|
using YarpGateway.Data;
|
|
using YarpGateway.DynamicProxy;
|
|
using YarpGateway.LoadBalancing;
|
|
using YarpGateway.Middleware;
|
|
using YarpGateway.Services;
|
|
using StackExchange.Redis;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
builder.Host.UseSerilog(
|
|
(context, services, configuration) =>
|
|
configuration
|
|
.ReadFrom.Configuration(context.Configuration)
|
|
.ReadFrom.Services(services)
|
|
.Enrich.FromLogContext()
|
|
);
|
|
|
|
builder.Services.Configure<JwtConfig>(builder.Configuration.GetSection("Jwt"));
|
|
builder.Services.Configure<RedisConfig>(builder.Configuration.GetSection("Redis"));
|
|
builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<RedisConfig>>().Value);
|
|
|
|
builder.Services.AddDbContextFactory<GatewayDbContext>(options =>
|
|
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))
|
|
);
|
|
|
|
builder.Services.AddSingleton<DatabaseRouteConfigProvider>();
|
|
builder.Services.AddSingleton<DatabaseClusterConfigProvider>();
|
|
builder.Services.AddSingleton<IRouteCache, RouteCache>();
|
|
|
|
builder.Services.AddSingleton<IRedisConnectionManager, RedisConnectionManager>();
|
|
builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
|
|
{
|
|
var config = sp.GetRequiredService<RedisConfig>();
|
|
var connectionOptions = ConfigurationOptions.Parse(config.ConnectionString);
|
|
connectionOptions.AbortOnConnectFail = false;
|
|
connectionOptions.ConnectRetry = 3;
|
|
connectionOptions.ConnectTimeout = 5000;
|
|
connectionOptions.SyncTimeout = 3000;
|
|
connectionOptions.DefaultDatabase = config.Database;
|
|
|
|
var connection = ConnectionMultiplexer.Connect(connectionOptions);
|
|
connection.ConnectionFailed += (sender, e) =>
|
|
{
|
|
Serilog.Log.Error(e.Exception, "Redis connection failed");
|
|
};
|
|
connection.ConnectionRestored += (sender, e) =>
|
|
{
|
|
Serilog.Log.Information("Redis connection restored");
|
|
};
|
|
|
|
return connection;
|
|
});
|
|
|
|
builder.Services.AddSingleton<ILoadBalancingPolicy, DistributedWeightedRoundRobinPolicy>();
|
|
|
|
builder.Services.AddSingleton<DynamicProxyConfigProvider>();
|
|
builder.Services.AddSingleton<IProxyConfigProvider>(sp => sp.GetRequiredService<DynamicProxyConfigProvider>());
|
|
|
|
builder.Services.AddHostedService<PgSqlConfigChangeListener>();
|
|
|
|
var corsSettings = builder.Configuration.GetSection("Cors");
|
|
builder.Services.AddCors(options =>
|
|
{
|
|
var allowAnyOrigin = corsSettings.GetValue<bool>("AllowAnyOrigin");
|
|
var allowedOrigins = corsSettings.GetSection("AllowedOrigins").Get<string[]>() ?? Array.Empty<string>();
|
|
|
|
options.AddPolicy("AllowFrontend", policy =>
|
|
{
|
|
if (allowAnyOrigin)
|
|
{
|
|
policy.AllowAnyOrigin();
|
|
}
|
|
else
|
|
{
|
|
policy.WithOrigins(allowedOrigins);
|
|
}
|
|
|
|
policy.AllowAnyHeader()
|
|
.AllowAnyMethod()
|
|
.AllowCredentials();
|
|
});
|
|
});
|
|
|
|
builder.Services.AddControllers();
|
|
builder.Services.AddHttpForwarder();
|
|
builder.Services.AddRouting();
|
|
builder.Services.AddReverseProxy();
|
|
|
|
var app = builder.Build();
|
|
|
|
app.UseCors("AllowFrontend");
|
|
app.UseMiddleware<JwtTransformMiddleware>();
|
|
app.UseMiddleware<TenantRoutingMiddleware>();
|
|
|
|
app.MapControllers();
|
|
app.MapReverseProxy();
|
|
|
|
await app.Services.GetRequiredService<IRouteCache>().InitializeAsync();
|
|
|
|
try
|
|
{
|
|
Log.Information("Starting YARP Gateway");
|
|
app.Run();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Fatal(ex, "Application terminated unexpectedly");
|
|
}
|
|
finally
|
|
{
|
|
Log.CloseAndFlush();
|
|
}
|