mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-30 23:11:53 +01:00
Merge pull request #1503 from cvium/webapi_v2
Move StartupWizard to ASP.NET Web Api
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Jellyfin.Server.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for adding API specific functionality to the application pipeline.
|
||||
/// </summary>
|
||||
public static class ApiApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds swagger and swagger UI to the application pipeline.
|
||||
/// </summary>
|
||||
/// <param name="applicationBuilder">The application builder.</param>
|
||||
/// <returns>The updated application builder.</returns>
|
||||
public static IApplicationBuilder UseJellyfinApiSwagger(this IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
applicationBuilder.UseSwagger();
|
||||
|
||||
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
|
||||
// specifying the Swagger JSON endpoint.
|
||||
return applicationBuilder.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Jellyfin API V1");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
Normal file
90
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Jellyfin.Api;
|
||||
using Jellyfin.Api.Auth;
|
||||
using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy;
|
||||
using Jellyfin.Api.Auth.RequiresElevationPolicy;
|
||||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Api.Controllers;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Jellyfin.Server.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// API specific extensions for the service collection.
|
||||
/// </summary>
|
||||
public static class ApiServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds jellyfin API authorization policies to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <returns>The updated service collection.</returns>
|
||||
public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeSetupOrElevatedHandler>();
|
||||
serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>();
|
||||
return serviceCollection.AddAuthorizationCore(options =>
|
||||
{
|
||||
options.AddPolicy(
|
||||
Policies.RequiresElevation,
|
||||
policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||
policy.AddRequirements(new RequiresElevationRequirement());
|
||||
});
|
||||
options.AddPolicy(
|
||||
Policies.FirstTimeSetupOrElevated,
|
||||
policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||
policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds custom legacy authentication to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <returns>The updated service collection.</returns>
|
||||
public static AuthenticationBuilder AddCustomAuthentication(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection.AddAuthentication(AuthenticationSchemes.CustomAuthentication)
|
||||
.AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>(AuthenticationSchemes.CustomAuthentication, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for adding the jellyfin API to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <param name="baseUrl">The base url for the API.</param>
|
||||
/// <returns>The MVC builder.</returns>
|
||||
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl)
|
||||
{
|
||||
return serviceCollection.AddMvc(opts =>
|
||||
{
|
||||
opts.UseGeneralRoutePrefix(baseUrl);
|
||||
})
|
||||
|
||||
// Clear app parts to avoid other assemblies being picked up
|
||||
.ConfigureApplicationPartManager(a => a.ApplicationParts.Clear())
|
||||
.AddApplicationPart(typeof(StartupController).Assembly)
|
||||
.AddControllersAsServices();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Swagger to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collection.</param>
|
||||
/// <returns>The updated service collection.</returns>
|
||||
public static IServiceCollection AddJellyfinApiSwagger(this IServiceCollection serviceCollection)
|
||||
{
|
||||
return serviceCollection.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Jellyfin API", Version = "v1" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,10 @@
|
||||
<EmbeddedResource Include="Resources/Configuration/*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Code analyzers-->
|
||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" />
|
||||
|
||||
@@ -19,8 +19,10 @@ using Jellyfin.Drawing.Skia;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Serilog;
|
||||
@@ -167,7 +169,24 @@ namespace Jellyfin.Server
|
||||
appConfig);
|
||||
try
|
||||
{
|
||||
await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false);
|
||||
ServiceCollection serviceCollection = new ServiceCollection();
|
||||
await appHost.InitAsync(serviceCollection).ConfigureAwait(false);
|
||||
|
||||
var host = CreateWebHostBuilder(appHost, serviceCollection).Build();
|
||||
|
||||
// A bit hacky to re-use service provider since ASP.NET doesn't allow a custom service collection.
|
||||
appHost.ServiceProvider = host.Services;
|
||||
appHost.FindParts();
|
||||
|
||||
try
|
||||
{
|
||||
await host.StartAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.LogError("Kestrel failed to start! This is most likely due to an invalid address or port bind - correct your bind configuration in system.xml and try again.");
|
||||
throw;
|
||||
}
|
||||
|
||||
appHost.ImageProcessor.ImageEncoder = GetImageEncoder(appPaths, appHost.LocalizationManager);
|
||||
|
||||
@@ -199,6 +218,55 @@ namespace Jellyfin.Server
|
||||
}
|
||||
}
|
||||
|
||||
private static IWebHostBuilder CreateWebHostBuilder(ApplicationHost appHost, IServiceCollection serviceCollection)
|
||||
{
|
||||
return new WebHostBuilder()
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
var addresses = appHost.ServerConfigurationManager
|
||||
.Configuration
|
||||
.LocalNetworkAddresses
|
||||
.Select(appHost.NormalizeConfiguredLocalAddress)
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
if (addresses.Any())
|
||||
{
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
_logger.LogInformation("Kestrel listening on {ipaddr}", address);
|
||||
options.Listen(address, appHost.HttpPort);
|
||||
|
||||
if (appHost.EnableHttps && appHost.Certificate != null)
|
||||
{
|
||||
options.Listen(
|
||||
address,
|
||||
appHost.HttpsPort,
|
||||
listenOptions => listenOptions.UseHttps(appHost.Certificate));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Kestrel listening on all interfaces");
|
||||
options.ListenAnyIP(appHost.HttpPort);
|
||||
|
||||
if (appHost.EnableHttps && appHost.Certificate != null)
|
||||
{
|
||||
options.ListenAnyIP(
|
||||
appHost.HttpsPort,
|
||||
listenOptions => listenOptions.UseHttps(appHost.Certificate));
|
||||
}
|
||||
}
|
||||
})
|
||||
.UseContentRoot(appHost.ContentRoot)
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
// Merge the external ServiceCollection into ASP.NET DI
|
||||
services.TryAdd(serviceCollection);
|
||||
})
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the data, config and log paths from the variety of inputs(command line args,
|
||||
/// environment variables) or decide on what default to use. For Windows it's %AppPath%
|
||||
|
||||
81
Jellyfin.Server/Startup.cs
Normal file
81
Jellyfin.Server/Startup.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Jellyfin.Server.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Jellyfin.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Startup configuration for the Kestrel webhost.
|
||||
/// </summary>
|
||||
public class Startup
|
||||
{
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Startup" /> class.
|
||||
/// </summary>
|
||||
/// <param name="serverConfigurationManager">The server configuration manager.</param>
|
||||
public Startup(IServerConfigurationManager serverConfigurationManager)
|
||||
{
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the service collection for the webhost.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection.</param>
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddResponseCompression();
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'));
|
||||
|
||||
services.AddJellyfinApiSwagger();
|
||||
|
||||
// configure custom legacy authentication
|
||||
services.AddCustomAuthentication();
|
||||
|
||||
services.AddJellyfinApiAuthorization();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the app builder for the webhost.
|
||||
/// </summary>
|
||||
/// <param name="app">The application builder.</param>
|
||||
/// <param name="env">The webhost environment.</param>
|
||||
/// <param name="serverApplicationHost">The server application host.</param>
|
||||
public void Configure(
|
||||
IApplicationBuilder app,
|
||||
IWebHostEnvironment env,
|
||||
IServerApplicationHost serverApplicationHost)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseWebSockets();
|
||||
|
||||
app.UseResponseCompression();
|
||||
|
||||
// TODO app.UseMiddleware<WebSocketMiddleware>();
|
||||
app.Use(serverApplicationHost.ExecuteWebsocketHandlerAsync);
|
||||
|
||||
// TODO use when old API is removed: app.UseAuthentication();
|
||||
app.UseJellyfinApiSwagger();
|
||||
app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
|
||||
app.Use(serverApplicationHost.ExecuteHttpHandlerAsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user