From f8ca71ee157079aeee075f92f9537e9d580d584d Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 15 Jan 2023 11:46:30 -0500 Subject: [PATCH] Move WebHostBuilder extension method to separate file --- .../Extensions/WebHostBuilderExtensions.cs | 90 ++++++++++++++ Jellyfin.Server/Helpers/StartupHelpers.cs | 50 ++++++++ Jellyfin.Server/Program.cs | 114 +----------------- .../JellyfinApplicationFactory.cs | 4 +- 4 files changed, 147 insertions(+), 111 deletions(-) create mode 100644 Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs diff --git a/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs new file mode 100644 index 0000000000..58d3e1b2d9 --- /dev/null +++ b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using System.Net; +using Jellyfin.Server.Helpers; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Extensions; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Extensions; + +/// +/// Extensions for configuring the web host builder. +/// +public static class WebHostBuilderExtensions +{ + /// + /// Configure the web host builder. + /// + /// The builder to configure. + /// The application host. + /// The application configuration. + /// The application paths. + /// The logger. + /// The configured web host builder. + public static IWebHostBuilder ConfigureWebHostBuilder( + this IWebHostBuilder builder, + CoreAppHost appHost, + IConfiguration startupConfig, + IApplicationPaths appPaths, + ILogger logger) + { + return builder + .UseKestrel((builderContext, options) => + { + var addresses = appHost.NetManager.GetAllBindInterfaces(); + + bool flagged = false; + foreach (IPObject netAdd in addresses) + { + logger.LogInformation("Kestrel listening on {Address}", IPAddress.IPv6Any.Equals(netAdd.Address) ? "All Addresses" : netAdd); + options.Listen(netAdd.Address, appHost.HttpPort); + if (appHost.ListenWithHttps) + { + options.Listen( + netAdd.Address, + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps(appHost.Certificate)); + } + else if (builderContext.HostingEnvironment.IsDevelopment()) + { + try + { + options.Listen( + netAdd.Address, + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps()); + } + catch (InvalidOperationException) + { + if (!flagged) + { + logger.LogWarning("Failed to listen to HTTPS using the ASP.NET Core HTTPS development certificate. Please ensure it has been installed and set as trusted"); + flagged = true; + } + } + } + } + + // Bind to unix socket (only on unix systems) + if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) + { + var socketPath = StartupHelpers.GetUnixSocketPath(startupConfig, appPaths); + + // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 + if (File.Exists(socketPath)) + { + File.Delete(socketPath); + } + + options.ListenUnixSocket(socketPath); + logger.LogInformation("Kestrel listening to unix socket {SocketPath}", socketPath); + } + }) + .UseStartup(_ => new Startup(appHost)); + } +} diff --git a/Jellyfin.Server/Helpers/StartupHelpers.cs b/Jellyfin.Server/Helpers/StartupHelpers.cs index b10e34898c..f1bb9b2831 100644 --- a/Jellyfin.Server/Helpers/StartupHelpers.cs +++ b/Jellyfin.Server/Helpers/StartupHelpers.cs @@ -2,14 +2,18 @@ using System; using System.Globalization; using System.IO; using System.Net; +using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using Emby.Server.Implementations; using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Extensions; using MediaBrowser.Model.IO; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Serilog; using SQLitePCL; +using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Jellyfin.Server.Helpers; @@ -187,6 +191,52 @@ public static class StartupHelpers return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir); } + /// + /// Gets the path for the unix socket Kestrel should bind to. + /// + /// The startup config. + /// The application paths. + /// The path for Kestrel to bind to. + public static string GetUnixSocketPath(IConfiguration startupConfig, IApplicationPaths appPaths) + { + var socketPath = startupConfig.GetUnixSocketPath(); + + if (string.IsNullOrEmpty(socketPath)) + { + var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); + var socketFile = "jellyfin.sock"; + if (xdgRuntimeDir is null) + { + // Fall back to config dir + socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, socketFile); + } + else + { + socketPath = Path.Join(xdgRuntimeDir, socketFile); + } + } + + return socketPath; + } + + /// + /// Sets the unix file permissions for Kestrel's socket file. + /// + /// The startup config. + /// The socket path. + /// The logger. + [UnsupportedOSPlatform("windows")] + public static void SetUnixSocketPermissions(IConfiguration startupConfig, string socketPath, ILogger logger) + { + var socketPerms = startupConfig.GetUnixSocketPermissions(); + + if (!string.IsNullOrEmpty(socketPerms)) + { + File.SetUnixFileMode(socketPath, (UnixFileMode)Convert.ToInt32(socketPerms, 8)); + logger.LogInformation("Kestrel unix socket permissions set to {SocketPerms}", socketPerms); + } + } + /// /// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist /// already. diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index f6fa0ff5ba..b817ea6275 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -3,18 +3,15 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Net; using System.Reflection; -using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; +using Jellyfin.Server.Extensions; using Jellyfin.Server.Helpers; using Jellyfin.Server.Implementations; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; -using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -182,7 +179,7 @@ namespace Jellyfin.Server { var host = Host.CreateDefaultBuilder() .ConfigureServices(services => appHost.Init(services)) - .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.ConfigureWebHostBuilder(appHost, startupConfig, appPaths)) + .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.ConfigureWebHostBuilder(appHost, startupConfig, appPaths, _logger)) .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(options, appPaths, startupConfig)) .UseSerilog() .Build(); @@ -199,9 +196,9 @@ namespace Jellyfin.Server if (!OperatingSystem.IsWindows() && startupConfig.UseUnixSocket()) { - var socketPath = GetUnixSocketPath(startupConfig, appPaths); + var socketPath = StartupHelpers.GetUnixSocketPath(startupConfig, appPaths); - SetUnixSocketPermissions(startupConfig, socketPath); + StartupHelpers.SetUnixSocketPermissions(startupConfig, socketPath, _logger); } } catch (Exception ex) when (ex is not TaskCanceledException) @@ -251,75 +248,6 @@ namespace Jellyfin.Server } } - /// - /// Configure the web host builder. - /// - /// The builder to configure. - /// The application host. - /// The application configuration. - /// The application paths. - /// The configured web host builder. - public static IWebHostBuilder ConfigureWebHostBuilder( - this IWebHostBuilder builder, - CoreAppHost appHost, - IConfiguration startupConfig, - IApplicationPaths appPaths) - { - return builder - .UseKestrel((builderContext, options) => - { - var addresses = appHost.NetManager.GetAllBindInterfaces(); - - bool flagged = false; - foreach (IPObject netAdd in addresses) - { - _logger.LogInformation("Kestrel listening on {Address}", netAdd.Address == IPAddress.IPv6Any ? "All Addresses" : netAdd); - options.Listen(netAdd.Address, appHost.HttpPort); - if (appHost.ListenWithHttps) - { - options.Listen( - netAdd.Address, - appHost.HttpsPort, - listenOptions => listenOptions.UseHttps(appHost.Certificate)); - } - else if (builderContext.HostingEnvironment.IsDevelopment()) - { - try - { - options.Listen( - netAdd.Address, - appHost.HttpsPort, - listenOptions => listenOptions.UseHttps()); - } - catch (InvalidOperationException) - { - if (!flagged) - { - _logger.LogWarning("Failed to listen to HTTPS using the ASP.NET Core HTTPS development certificate. Please ensure it has been installed and set as trusted."); - flagged = true; - } - } - } - } - - // Bind to unix socket (only on unix systems) - if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) - { - var socketPath = GetUnixSocketPath(startupConfig, appPaths); - - // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 - if (File.Exists(socketPath)) - { - File.Delete(socketPath); - } - - options.ListenUnixSocket(socketPath); - _logger.LogInformation("Kestrel listening to unix socket {SocketPath}", socketPath); - } - }) - .UseStartup(_ => new Startup(appHost)); - } - /// /// Create the application configuration. /// @@ -393,39 +321,5 @@ namespace Jellyfin.Server return "\"" + arg + "\""; } - - private static string GetUnixSocketPath(IConfiguration startupConfig, IApplicationPaths appPaths) - { - var socketPath = startupConfig.GetUnixSocketPath(); - - if (string.IsNullOrEmpty(socketPath)) - { - var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); - var socketFile = "jellyfin.sock"; - if (xdgRuntimeDir is null) - { - // Fall back to config dir - socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, socketFile); - } - else - { - socketPath = Path.Join(xdgRuntimeDir, socketFile); - } - } - - return socketPath; - } - - [UnsupportedOSPlatform("windows")] - private static void SetUnixSocketPermissions(IConfiguration startupConfig, string socketPath) - { - var socketPerms = startupConfig.GetUnixSocketPermissions(); - - if (!string.IsNullOrEmpty(socketPerms)) - { - File.SetUnixFileMode(socketPath, (UnixFileMode)Convert.ToInt32(socketPerms, 8)); - _logger.LogInformation("Kestrel unix socket permissions set to {SocketPerms}", socketPerms); - } - } } } diff --git a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs index 3faea64bec..55bc43455f 100644 --- a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs +++ b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Threading; using Emby.Server.Implementations; +using Jellyfin.Server.Extensions; using Jellyfin.Server.Helpers; using MediaBrowser.Common; using Microsoft.AspNetCore.Hosting; @@ -12,6 +13,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Serilog; using Serilog.Extensions.Logging; @@ -82,7 +84,7 @@ namespace Jellyfin.Server.Integration.Tests _disposableComponents.Add(appHost); builder.ConfigureServices(services => appHost.Init(services)) - .ConfigureWebHostBuilder(appHost, startupConfig, appPaths) + .ConfigureWebHostBuilder(appHost, startupConfig, appPaths, NullLogger.Instance) .ConfigureAppConfiguration((context, builder) => { builder