Remove obsolete HttpRequestTimeFeature.cs

add openapi definitions output
Start logging in Program.cs
This commit is contained in:
2025-09-28 17:02:27 +02:00
parent 82489f3870
commit 24cf63f235
5 changed files with 4538 additions and 86 deletions

View File

@@ -7,6 +7,10 @@
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn> <NoWarn>$(NoWarn);1591</NoWarn>
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)\openapi</OpenApiDocumentsDirectory>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
<OpenApiGenerateDocumentsOnBuild>true</OpenApiGenerateDocumentsOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,35 +0,0 @@
namespace API;
public interface IHttpRequestTimeFeature
{
DateTime RequestTime { get; }
}
public class HttpRequestTimeFeature : IHttpRequestTimeFeature
{
public DateTime RequestTime { get; }
public HttpRequestTimeFeature()
{
RequestTime = DateTime.Now;
}
}
public class RequestTimeMiddleware
{
private readonly RequestDelegate _next;
public RequestTimeMiddleware(RequestDelegate next)
{
_next = next;
}
public Task InvokeAsync(HttpContext context)
{
var httpRequestTimeFeature = new HttpRequestTimeFeature();
context.Features.Set<IHttpRequestTimeFeature>(httpRequestTimeFeature);
// Call the next delegate/middleware in the pipeline
return this._next(context);
}
}

View File

@@ -7,12 +7,19 @@ using Asp.Versioning;
using Asp.Versioning.Builder; using Asp.Versioning.Builder;
using Asp.Versioning.Conventions; using Asp.Versioning.Conventions;
using log4net; using log4net;
using log4net.Config;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
using Npgsql; using Npgsql;
var builder = WebApplication.CreateBuilder(args); XmlConfigurator.ConfigureAndWatch(new FileInfo("Log4Net.config.xml"));
ILog Log = LogManager.GetLogger("Startup");
Log.Info("Logger Configured.");
Log.Info("Starting up");
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {
@@ -26,6 +33,7 @@ builder.Services.AddCors(options =>
}); });
}); });
Log.Debug("Adding API-Explorer-helpers...");
builder.Services.AddApiVersioning(option => builder.Services.AddApiVersioning(option =>
{ {
option.AssumeDefaultVersionWhenUnspecified = true; option.AssumeDefaultVersionWhenUnspecified = true;
@@ -47,14 +55,14 @@ builder.Services.AddApiVersioning(option =>
options.SubstituteApiVersionInUrl = true; options.SubstituteApiVersionInUrl = true;
}); });
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGenNewtonsoftSupport(); builder.Services.ConfigureOptions<NamedSwaggerGenOptions>();
builder.Services.AddSwaggerGen(opt => builder.Services.AddSwaggerGenNewtonsoftSupport().AddSwaggerGen(opt =>
{ {
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; string xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
opt.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); opt.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
}); });
builder.Services.ConfigureOptions<NamedSwaggerGenOptions>();
Log.Debug("Adding Database-Connection...");
NpgsqlConnectionStringBuilder connectionStringBuilder = new() NpgsqlConnectionStringBuilder connectionStringBuilder = new()
{ {
Host = Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "tranga-pg:5432", Host = Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "tranga-pg:5432",
@@ -89,71 +97,86 @@ builder.Services.AddScoped<ILog>(_ => LogManager.GetLogger("API"));
builder.WebHost.UseUrls("http://*:6531"); builder.WebHost.UseUrls("http://*:6531");
var app = builder.Build(); Log.Info("Starting app...");
WebApplication app = builder.Build();
app.UseCors("AllowAll");
ApiVersionSet apiVersionSet = app.NewApiVersionSet() ApiVersionSet apiVersionSet = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(2)) .HasApiVersion(new ApiVersion(2))
.ReportApiVersions() .ReportApiVersions()
.Build(); .Build();
app.UseCors("AllowAll"); app.UseCors("AllowAll");
Log.Debug("Mapping Controllers...");
app.MapControllers() app.MapControllers()
.WithApiVersionSet(apiVersionSet) .WithApiVersionSet(apiVersionSet)
.MapToApiVersion(2); .MapToApiVersion(2);
app.UseSwagger(); Log.Debug("Adding Swagger...");
app.UseSwaggerUI(options => app.UseSwagger(opts =>
{ {
options.SwaggerEndpoint($"/swagger/v2/swagger.json", "v2"); opts.OpenApiVersion = OpenApiSpecVersion.OpenApi3_0;
opts.RouteTemplate = "swagger/{documentName}/swagger.json";
}); });
app.UseSwaggerUI();
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseMiddleware<RequestTimeMiddleware>(); try //Connect to DB and apply migrations
using (IServiceScope scope = app.Services.CreateScope())
{ {
MangaContext context = scope.ServiceProvider.GetRequiredService<MangaContext>(); Log.Debug("Applying Migrations...");
await context.Database.MigrateAsync(CancellationToken.None); using (IServiceScope scope = app.Services.CreateScope())
await context.Database.EnsureCreatedAsync(CancellationToken.None);
if (!context.FileLibraries.Any())
{ {
await context.FileLibraries.AddAsync(new (Tranga.Settings.DefaultDownloadLocation, "Default FileLibrary"), CancellationToken.None); MangaContext context = scope.ServiceProvider.GetRequiredService<MangaContext>();
await context.Sync(CancellationToken.None, reason: "Add default library"); await context.Database.MigrateAsync(CancellationToken.None);
if (!context.FileLibraries.Any())
{
await context.FileLibraries.AddAsync(new(Tranga.Settings.DefaultDownloadLocation, "Default FileLibrary"),
CancellationToken.None);
await context.Sync(CancellationToken.None, reason: "Add default library");
}
}
using (IServiceScope scope = app.Services.CreateScope())
{
NotificationsContext context = scope.ServiceProvider.GetRequiredService<NotificationsContext>();
await context.Database.MigrateAsync(CancellationToken.None);
context.Notifications.ExecuteDelete();
string[] emojis =
[
"(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=",
"(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~", "૮ \u00b4• ﻌ \u00b4• ა",
"(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"
];
await context.Notifications.AddAsync(
new("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High),
CancellationToken.None);
await context.Sync(CancellationToken.None, reason: "Startup notification");
}
using (IServiceScope scope = app.Services.CreateScope())
{
LibraryContext context = scope.ServiceProvider.GetRequiredService<LibraryContext>();
await context.Database.MigrateAsync(CancellationToken.None);
await context.Sync(CancellationToken.None, reason: "Startup library");
} }
} }
catch (Exception e)
using (IServiceScope scope = app.Services.CreateScope())
{ {
NotificationsContext context = scope.ServiceProvider.GetRequiredService<NotificationsContext>(); Log.Debug("Migrations failed!", e);
await context.Database.MigrateAsync(CancellationToken.None); return;
await context.Database.EnsureCreatedAsync(CancellationToken.None);
context.Notifications.ExecuteDelete();
string[] emojis = ["(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"
];
await context.Notifications.AddAsync(new ("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High), CancellationToken.None);
await context.Sync(CancellationToken.None, reason: "Startup notification");
}
using (IServiceScope scope = app.Services.CreateScope())
{
LibraryContext context = scope.ServiceProvider.GetRequiredService<LibraryContext>();
await context.Database.MigrateAsync(CancellationToken.None);
await context.Database.EnsureCreatedAsync(CancellationToken.None);
await context.Sync(CancellationToken.None, reason: "Startup library");
} }
Log.Info("Starting Tranga.");
Tranga.ServiceProvider = app.Services; Tranga.ServiceProvider = app.Services;
Tranga.StartLogger(new FileInfo("Log4Net.config.xml"));
Tranga.StartupTasks(); Tranga.StartupTasks();
Tranga.AddDefaultWorkers(); Tranga.AddDefaultWorkers();
app.UseCors("AllowAll"); Log.Info("Running app.");
app.Run(); app.Run();

View File

@@ -35,15 +35,9 @@ public static class Tranga
internal static readonly CleanupMangaconnectorIdsWithoutConnector CleanupMangaconnectorIdsWithoutConnector = new(); internal static readonly CleanupMangaconnectorIdsWithoutConnector CleanupMangaconnectorIdsWithoutConnector = new();
// ReSharper restore MemberCanBePrivate.Global // ReSharper restore MemberCanBePrivate.Global
internal static void StartLogger(FileInfo loggerConfigFile)
{
XmlConfigurator.ConfigureAndWatch(loggerConfigFile);
Log.Info("Logger Configured.");
Log.Info(Constants.TRANGA);
}
internal static void StartupTasks() internal static void StartupTasks()
{ {
Log.Info(Constants.TRANGA);
AddWorker(SendNotificationsWorker); AddWorker(SendNotificationsWorker);
AddWorker(CleanupMangaconnectorIdsWithoutConnector); AddWorker(CleanupMangaconnectorIdsWithoutConnector);
AddWorker(UpdateChaptersDownloadedWorker); AddWorker(UpdateChaptersDownloadedWorker);

4466
API/openapi/API_v2.json Normal file

File diff suppressed because it is too large Load Diff