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.LoadPluginsAsync(); 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.InitializeAsync(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.MapStaticAssetsWithTransparentDecompression(); app.MapControllers(); app.MapFallbackToController("/api/{**slug}", "FallbackAction", "Fallback").WithOrder(int.MaxValue - 3); app.MapHub("/hubs/streaming"); app.MapRazorPages().WithStaticAssets(); app.MapRazorComponents(); 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();