Iceshrimp.NET/Iceshrimp.Backend/Startup.cs
Laura Hausmann 705e061f74
[backend/asp] Refactor middleware stack
This commit splits the request pipeline conditionally instead of invoking every middleware in the stack.

It also simplifies middleware instantiation by using runtime discovery, allowing for Plugins to add Middleware.
2024-11-18 19:02:44 +01:00

96 lines
3.3 KiB
C#

using System.Diagnostics;
using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Helpers;
using Iceshrimp.Backend.Pages.Shared;
using Iceshrimp.Backend.SignalR;
using Iceshrimp.Backend.SignalR.Authentication;
using Microsoft.AspNetCore.HttpOverrides;
var options = StartupHelpers.ParseCliArguments(args);
var builder = WebApplication.CreateBuilder(options);
builder.Configuration.Sources.Clear();
builder.Configuration.AddCustomConfiguration();
await PluginLoader.LoadPlugins();
builder.Services
.AddControllersWithOptions()
.AddNewtonsoftJson() //TODO: remove once dotNetRdf switches to System.Text.Json (or we switch to LinkedData.NET)
.ConfigureNewtonsoftJson()
.AddMultiFormatter()
.AddModelBindingProviders()
.AddValueProviderFactories()
.AddApiBehaviorOptions()
.AddPlugins(PluginLoader.Assemblies);
builder.Services.AddOpenApiWithOptions();
builder.Services.AddOutputCacheWithOptions();
builder.Services.AddLogging(logging => logging.AddCustomConsoleFormatter());
builder.Services.AddDatabaseContext(builder.Configuration);
builder.Services.AddSlidingWindowRateLimiter();
builder.Services.AddCorsPolicies();
builder.Services.AddAuthorizationPolicies();
builder.Services.AddAuthenticationServices();
builder.Services.AddSignalR().AddMessagePackProtocol();
builder.Services.AddResponseCompression();
builder.Services.AddRazorPages();
builder.Services.AddRazorComponents();
builder.Services.AddAntiforgery(o => o.Cookie.Name = "CSRF-Token");
builder.Services.AddMiddleware();
builder.Services.AddServices(builder.Configuration);
builder.Services.ConfigureServices(builder.Configuration);
builder.WebHost.ConfigureKestrel(builder.Configuration);
builder.WebHost.UseStaticWebAssets();
PluginLoader.RunBuilderHooks(builder);
var app = builder.Build();
var config = await app.Initialize(args);
// This determines the order of middleware execution in the request pipeline
#if DEBUG
if (app.Environment.IsDevelopment())
app.UseWebAssemblyDebugging();
else
app.UseResponseCompression();
#else
app.UseResponseCompression();
#endif
app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedProto });
app.UseRouting();
app.UseOpenApiWithOptions();
app.UseCors();
app.UseAuthorization();
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) });
app.UseCustomMiddleware();
app.UseAntiforgery();
app.UseOutputCache();
app.MapStaticAssetsWithTransparentDecompression();
app.MapControllers();
app.MapFallbackToController("/api/{**slug}", "FallbackAction", "Fallback").WithOrder(int.MaxValue - 3);
app.MapHub<StreamingHub>("/hubs/streaming");
app.MapRazorPages().WithStaticAssets();
app.MapRazorComponents<RootComponent>();
app.MapFrontendRoutes("/Shared/FrontendSPA");
PluginLoader.RunAppHooks(app);
PluginLoader.PrintPluginInformation(app);
// If running under IIS, this collection is read only
if (!app.Urls.IsReadOnly)
{
app.Urls.Clear();
if (config.ListenSocket == null)
app.Urls.Add($"{(args.Contains("--https") ? "https" : "http")}://{config.ListenHost}:{config.ListenPort}");
}
var elapsed = (DateTime.Now - Process.GetCurrentProcess().StartTime).GetTotalMilliseconds();
app.Logger.LogInformation("Startup complete after {ms} ms.", elapsed);
await app.StartAsync();
app.SetKestrelUnixSocketPermissions();
await app.WaitForShutdownAsync();