Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
120
src/ReachGraph/StellaOps.ReachGraph.WebService/Program.cs
Normal file
120
src/ReachGraph/StellaOps.ReachGraph.WebService/Program.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
// Licensed to StellaOps under the AGPL-3.0-or-later license.
|
||||
|
||||
using System.Threading.RateLimiting;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Npgsql;
|
||||
using StellaOps.ReachGraph.Cache;
|
||||
using StellaOps.ReachGraph.Hashing;
|
||||
using StellaOps.ReachGraph.Persistence;
|
||||
using StellaOps.ReachGraph.Serialization;
|
||||
using StellaOps.ReachGraph.WebService.Services;
|
||||
using StackExchange.Redis;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new()
|
||||
{
|
||||
Title = "ReachGraph Store API",
|
||||
Version = "v1",
|
||||
Description = "Content-addressed storage for reachability subgraphs"
|
||||
});
|
||||
});
|
||||
|
||||
// PostgreSQL
|
||||
var connectionString = builder.Configuration.GetConnectionString("PostgreSQL")
|
||||
?? throw new InvalidOperationException("PostgreSQL connection string not configured");
|
||||
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
|
||||
var dataSource = dataSourceBuilder.Build();
|
||||
builder.Services.AddSingleton(dataSource);
|
||||
|
||||
// Redis/Valkey
|
||||
var redisConnectionString = builder.Configuration.GetConnectionString("Redis")
|
||||
?? "localhost:6379";
|
||||
var redis = ConnectionMultiplexer.Connect(redisConnectionString);
|
||||
builder.Services.AddSingleton<IConnectionMultiplexer>(redis);
|
||||
|
||||
// Core services
|
||||
builder.Services.AddSingleton<CanonicalReachGraphSerializer>();
|
||||
builder.Services.AddSingleton<ReachGraphDigestComputer>();
|
||||
|
||||
// Persistence
|
||||
builder.Services.AddScoped<IReachGraphRepository, PostgresReachGraphRepository>();
|
||||
|
||||
// Cache
|
||||
builder.Services.Configure<ReachGraphCacheOptions>(
|
||||
builder.Configuration.GetSection("ReachGraphCache"));
|
||||
builder.Services.AddScoped<IReachGraphCache>(sp =>
|
||||
{
|
||||
var redisMultiplexer = sp.GetRequiredService<IConnectionMultiplexer>();
|
||||
var serializer = sp.GetRequiredService<CanonicalReachGraphSerializer>();
|
||||
var options = Microsoft.Extensions.Options.Options.Create(
|
||||
builder.Configuration.GetSection("ReachGraphCache").Get<ReachGraphCacheOptions>()
|
||||
?? new ReachGraphCacheOptions());
|
||||
var logger = sp.GetRequiredService<ILogger<ReachGraphValkeyCache>>();
|
||||
|
||||
// TODO: Get tenant from request context
|
||||
return new ReachGraphValkeyCache(redisMultiplexer, serializer, options, logger, "default");
|
||||
});
|
||||
|
||||
// Application services
|
||||
builder.Services.AddScoped<IReachGraphStoreService, ReachGraphStoreService>();
|
||||
builder.Services.AddScoped<IReachGraphSliceService, ReachGraphSliceService>();
|
||||
builder.Services.AddScoped<IReachGraphReplayService, ReachGraphReplayService>();
|
||||
|
||||
// Rate limiting
|
||||
builder.Services.AddRateLimiter(options =>
|
||||
{
|
||||
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
||||
|
||||
options.AddPolicy("reachgraph-read", ctx =>
|
||||
RateLimitPartition.GetFixedWindowLimiter(
|
||||
ctx.User.FindFirst("tenant")?.Value ?? ctx.Request.Headers["X-Tenant-ID"].FirstOrDefault() ?? "anonymous",
|
||||
_ => new FixedWindowRateLimiterOptions
|
||||
{
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
PermitLimit = 100
|
||||
}));
|
||||
|
||||
options.AddPolicy("reachgraph-write", ctx =>
|
||||
RateLimitPartition.GetFixedWindowLimiter(
|
||||
ctx.User.FindFirst("tenant")?.Value ?? ctx.Request.Headers["X-Tenant-ID"].FirstOrDefault() ?? "anonymous",
|
||||
_ => new FixedWindowRateLimiterOptions
|
||||
{
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
PermitLimit = 20
|
||||
}));
|
||||
});
|
||||
|
||||
// Response compression
|
||||
builder.Services.AddResponseCompression(options =>
|
||||
{
|
||||
options.EnableForHttps = true;
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure pipeline
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseResponseCompression();
|
||||
app.UseRateLimiter();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
// Make Program class accessible for integration testing
|
||||
namespace StellaOps.ReachGraph.WebService
|
||||
{
|
||||
public partial class Program { }
|
||||
}
|
||||
Reference in New Issue
Block a user