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>
This commit is contained in:
parent
f14bf019f1
commit
9516e1cd93
@ -39,6 +39,7 @@ builder.Services.AddScoped<IRoleRepository, RoleRepository>();
|
||||
builder.Services.AddScoped<IUserService, UserService>();
|
||||
builder.Services.AddScoped<ITenantService, TenantService>();
|
||||
builder.Services.AddScoped<IRoleService, RoleService>();
|
||||
builder.Services.AddScoped<IGatewayService, GatewayService>();
|
||||
|
||||
builder.Services.AddOpenIddict()
|
||||
.AddCore(options =>
|
||||
@ -79,6 +80,7 @@ builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new() { Title = "Fengling.Console API", Version = "v1" });
|
||||
c.CustomSchemaIds(type => type.FullName); // Use full name to avoid conflicts with YarpGateway DTOs
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
if (File.Exists(xmlPath))
|
||||
|
||||
@ -24,21 +24,19 @@ public interface IGatewayService
|
||||
|
||||
public class GatewayService : IGatewayService
|
||||
{
|
||||
private readonly IDbContextFactory<GatewayDbContext> _dbContextFactory;
|
||||
private readonly GatewayDbContext _dbContext;
|
||||
private readonly ILogger<GatewayService> _logger;
|
||||
|
||||
public GatewayService(IDbContextFactory<GatewayDbContext> dbContextFactory, ILogger<GatewayService> logger)
|
||||
public GatewayService(GatewayDbContext dbContext, ILogger<GatewayService> logger)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory;
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<GatewayStatisticsDto> GetStatisticsAsync()
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var routes = await db.TenantRoutes.Where(r => !r.IsDeleted).ToListAsync();
|
||||
var instances = await db.ServiceInstances.Where(i => !i.IsDeleted).ToListAsync();
|
||||
var routes = await _dbContext.TenantRoutes.Where(r => !r.IsDeleted).ToListAsync();
|
||||
var instances = await _dbContext.ServiceInstances.Where(i => !i.IsDeleted).ToListAsync();
|
||||
|
||||
return new GatewayStatisticsDto
|
||||
{
|
||||
@ -57,9 +55,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<List<GatewayServiceDto>> GetServicesAsync(bool globalOnly = false, string? tenantCode = null)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var query = db.TenantRoutes.Where(r => !r.IsDeleted);
|
||||
var query = _dbContext.TenantRoutes.Where(r => !r.IsDeleted);
|
||||
|
||||
if (globalOnly)
|
||||
query = query.Where(r => r.IsGlobal);
|
||||
@ -69,7 +65,7 @@ public class GatewayService : IGatewayService
|
||||
var routes = await query.OrderByDescending(r => r.CreatedTime).ToListAsync();
|
||||
var clusters = routes.Select(r => r.ClusterId).Distinct().ToList();
|
||||
|
||||
var instances = await db.ServiceInstances
|
||||
var instances = await _dbContext.ServiceInstances
|
||||
.Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted)
|
||||
.GroupBy(i => i.ClusterId)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.Count());
|
||||
@ -79,9 +75,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<GatewayServiceDto?> GetServiceAsync(string serviceName, string? tenantCode = null)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var route = await db.TenantRoutes
|
||||
var route = await _dbContext.TenantRoutes
|
||||
.FirstOrDefaultAsync(r =>
|
||||
r.ServiceName == serviceName &&
|
||||
r.IsDeleted == false &&
|
||||
@ -89,7 +83,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
if (route == null) return null;
|
||||
|
||||
var instances = await db.ServiceInstances
|
||||
var instances = await _dbContext.ServiceInstances
|
||||
.CountAsync(i => i.ClusterId == route.ClusterId && !i.IsDeleted);
|
||||
|
||||
return MapToServiceDto(route, instances);
|
||||
@ -97,8 +91,6 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<GatewayServiceDto> RegisterServiceAsync(CreateGatewayServiceDto dto)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var clusterId = $"{dto.ServicePrefix}-service";
|
||||
var pathPattern = $"/{dto.ServicePrefix}/{dto.Version}/{{**path}}";
|
||||
var destinationId = string.IsNullOrEmpty(dto.DestinationId)
|
||||
@ -106,7 +98,7 @@ public class GatewayService : IGatewayService
|
||||
: dto.DestinationId;
|
||||
|
||||
// Check if route already exists
|
||||
var existingRoute = await db.TenantRoutes
|
||||
var existingRoute = await _dbContext.TenantRoutes
|
||||
.FirstOrDefaultAsync(r =>
|
||||
r.ServiceName == dto.ServicePrefix &&
|
||||
r.IsGlobal == dto.IsGlobal &&
|
||||
@ -130,7 +122,7 @@ public class GatewayService : IGatewayService
|
||||
Status = 1,
|
||||
CreatedTime = DateTime.UtcNow
|
||||
};
|
||||
await db.ServiceInstances.AddAsync(instance);
|
||||
await _dbContext.ServiceInstances.AddAsync(instance);
|
||||
|
||||
// Add route
|
||||
var routeId = instanceId + 1;
|
||||
@ -146,9 +138,9 @@ public class GatewayService : IGatewayService
|
||||
IsGlobal = dto.IsGlobal,
|
||||
CreatedTime = DateTime.UtcNow
|
||||
};
|
||||
await db.TenantRoutes.AddAsync(route);
|
||||
await _dbContext.TenantRoutes.AddAsync(route);
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("Registered service {Service} at {Address}", dto.ServicePrefix, dto.ServiceAddress);
|
||||
|
||||
@ -157,9 +149,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<bool> UnregisterServiceAsync(string serviceName, string? tenantCode = null)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var route = await db.TenantRoutes
|
||||
var route = await _dbContext.TenantRoutes
|
||||
.FirstOrDefaultAsync(r =>
|
||||
r.ServiceName == serviceName &&
|
||||
r.IsDeleted == false &&
|
||||
@ -172,7 +162,7 @@ public class GatewayService : IGatewayService
|
||||
route.UpdatedTime = DateTime.UtcNow;
|
||||
|
||||
// Soft delete instances
|
||||
var instances = await db.ServiceInstances
|
||||
var instances = await _dbContext.ServiceInstances
|
||||
.Where(i => i.ClusterId == route.ClusterId && !i.IsDeleted)
|
||||
.ToListAsync();
|
||||
|
||||
@ -182,7 +172,7 @@ public class GatewayService : IGatewayService
|
||||
instance.UpdatedTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("Unregistered service {Service}", serviceName);
|
||||
|
||||
@ -191,9 +181,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<List<GatewayRouteDto>> GetRoutesAsync(bool globalOnly = false)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var query = db.TenantRoutes.Where(r => !r.IsDeleted);
|
||||
var query = _dbContext.TenantRoutes.Where(r => !r.IsDeleted);
|
||||
|
||||
if (globalOnly)
|
||||
query = query.Where(r => r.IsGlobal);
|
||||
@ -201,7 +189,7 @@ public class GatewayService : IGatewayService
|
||||
var routes = await query.OrderByDescending(r => r.Priority).ToListAsync();
|
||||
var clusters = routes.Select(r => r.ClusterId).Distinct().ToList();
|
||||
|
||||
var instances = await db.ServiceInstances
|
||||
var instances = await _dbContext.ServiceInstances
|
||||
.Where(i => clusters.Contains(i.ClusterId) && !i.IsDeleted)
|
||||
.GroupBy(i => i.ClusterId)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.Count());
|
||||
@ -222,9 +210,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<GatewayRouteDto> CreateRouteAsync(CreateGatewayRouteDto dto)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var existing = await db.TenantRoutes
|
||||
var existing = await _dbContext.TenantRoutes
|
||||
.FirstOrDefaultAsync(r =>
|
||||
r.ServiceName == dto.ServiceName &&
|
||||
r.IsGlobal == dto.IsGlobal &&
|
||||
@ -248,8 +234,8 @@ public class GatewayService : IGatewayService
|
||||
CreatedTime = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await db.TenantRoutes.AddAsync(route);
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.TenantRoutes.AddAsync(route);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return new GatewayRouteDto
|
||||
{
|
||||
@ -267,9 +253,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<List<GatewayInstanceDto>> GetInstancesAsync(string clusterId)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var instances = await db.ServiceInstances
|
||||
var instances = await _dbContext.ServiceInstances
|
||||
.Where(i => i.ClusterId == clusterId && !i.IsDeleted)
|
||||
.OrderByDescending(i => i.Weight)
|
||||
.ToListAsync();
|
||||
@ -289,9 +273,7 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<GatewayInstanceDto> AddInstanceAsync(CreateGatewayInstanceDto dto)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var existing = await db.ServiceInstances
|
||||
var existing = await _dbContext.ServiceInstances
|
||||
.FirstOrDefaultAsync(i =>
|
||||
i.ClusterId == dto.ClusterId &&
|
||||
i.DestinationId == dto.DestinationId &&
|
||||
@ -314,8 +296,8 @@ public class GatewayService : IGatewayService
|
||||
CreatedTime = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await db.ServiceInstances.AddAsync(instance);
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.ServiceInstances.AddAsync(instance);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return new GatewayInstanceDto
|
||||
{
|
||||
@ -332,29 +314,25 @@ public class GatewayService : IGatewayService
|
||||
|
||||
public async Task<bool> RemoveInstanceAsync(long instanceId)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var instance = await db.ServiceInstances.FindAsync(instanceId);
|
||||
var instance = await _dbContext.ServiceInstances.FindAsync(instanceId);
|
||||
if (instance == null) return false;
|
||||
|
||||
instance.IsDeleted = true;
|
||||
instance.UpdatedTime = DateTime.UtcNow;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateInstanceWeightAsync(long instanceId, int weight)
|
||||
{
|
||||
await using var db = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
var instance = await db.ServiceInstances.FindAsync(instanceId);
|
||||
var instance = await _dbContext.ServiceInstances.FindAsync(instanceId);
|
||||
if (instance == null) return false;
|
||||
|
||||
instance.Weight = weight;
|
||||
instance.UpdatedTime = DateTime.UtcNow;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user