Blog/Program.cs 3.3 K · 85 lines · raw · history

1 using Blog.Components;
2 using Blog.Services;
3 using Microsoft.AspNetCore.Mvc;
4
5 var builder = WebApplication.CreateBuilder(args);
6
7 // Add services to the container.
8 builder.Services.AddRazorComponents();
9
10 builder.Services.AddHttpClient();
11 builder.Services.AddHybridCache();
12 builder.Services.AddHttpClient<BrpService>(
13 client =>
14 {
15 client.BaseAddress = new Uri("https://brp.bes.is/");
16 });
17
18 // /Warframe searches Digital Extremes' published drop tables. warframe.com blocks requests from
19 // the server, so the 4 MB page ships in Blog/Resources and scripts/update-droptables.sh refreshes
20 // it before a publish. Singleton: the parsed tables live in the service, so a transient one would
21 // re-parse per request - see WarframeDropService.
22 builder.Services.Configure<WarframeOptions>(builder.Configuration.GetSection(WarframeOptions.Section));
23 builder.Services.AddSingleton<WarframeDropService>();
24
25 // /git browses the bare repositories on this server, in place of the cgit that used to. The
26 // service holds nothing: every read opens the repository it needs and closes it again, so a push
27 // shows up with nothing to invalidate - see GitService.
28 builder.Services.Configure<GitOptions>(builder.Configuration.GetSection(GitOptions.Section));
29 builder.Services.AddSingleton<GitService>();
30
31 // /rvrb reads the rvrb bot's stats straight off its BEAM, over Erlang distribution. The node this
32 // site dials with is started on the first request, not here - see RvrbService.
33 builder.Services.Configure<RvrbOptions>(builder.Configuration.GetSection(RvrbOptions.Section));
34 builder.Services.AddSingleton<RvrbService>();
35
36 // builder.Services.AddTransient<BrpService>();
37 // builder.Services.AddTransient<NsService>();
38
39 var app = builder.Build();
40
41 // Configure the HTTP request pipeline.
42 if (!app.Environment.IsDevelopment())
43 {
44 app.UseExceptionHandler("/Error", createScopeForErrors: true);
45 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
46 app.UseHsts();
47 }
48
49 app.UseHttpsRedirection();
50
51 app.UseAntiforgery();
52
53 app.MapStaticAssets();
54 app.MapRazorComponents<App>();
55
56 // One file out of a repository, exactly as it was committed.
57 //
58 // Never inline HTML: these repositories hold .html and .svg files, and serving one from this
59 // origin would run whatever a commit put in it as a page of mb.bes.is. Text goes out as
60 // text/plain with nosniff, which a browser will not reinterpret, and everything else is a
61 // download.
62 app.MapGet("/git/{repository}/raw/{**path}", (
63 string repository,
64 string path,
65 [FromQuery(Name = "h")] string? reference,
66 GitService git,
67 HttpResponse response) =>
68 {
69 if (git.GetRawBlob(repository, reference, path) is not { } blob) return Results.NotFound();
70
71 response.Headers.XContentTypeOptions = "nosniff";
72
73 return blob.IsBinary
74 ? Results.File(blob.Bytes, "application/octet-stream", blob.Name)
75 : Results.File(blob.Bytes, "text/plain; charset=utf-8");
76 });
77
78 // Item names matching what has been typed, for the search box's suggestion list.
79 app.MapGet("/api/warframe/names", async (string? q, WarframeDropService drops, CancellationToken cancellationToken) =>
80 {
81 var status = await drops.GetTablesAsync(cancellationToken).ConfigureAwait(false);
82 return status.Tables?.Search(q ?? "", 10) ?? [];
83 });
84
85 app.Run();