fengling-gateway/Program.cs
sam 71a15fd9fb refactor: major project restructuring and cleanup
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>
2026-02-15 10:34:07 +08:00

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();
}