Move WebHostBuilder extension method to separate file

This commit is contained in:
Patrick Barron 2023-01-15 11:46:30 -05:00
parent 029d53502f
commit f8ca71ee15
4 changed files with 147 additions and 111 deletions

View File

@ -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;
/// <summary>
/// Extensions for configuring the web host builder.
/// </summary>
public static class WebHostBuilderExtensions
{
/// <summary>
/// Configure the web host builder.
/// </summary>
/// <param name="builder">The builder to configure.</param>
/// <param name="appHost">The application host.</param>
/// <param name="startupConfig">The application configuration.</param>
/// <param name="appPaths">The application paths.</param>
/// <param name="logger">The logger.</param>
/// <returns>The configured web host builder.</returns>
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));
}
}

View File

@ -2,14 +2,18 @@ using System;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Runtime.Versioning;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Emby.Server.Implementations; using Emby.Server.Implementations;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog; using Serilog;
using SQLitePCL; using SQLitePCL;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Jellyfin.Server.Helpers; namespace Jellyfin.Server.Helpers;
@ -187,6 +191,52 @@ public static class StartupHelpers
return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir); return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir);
} }
/// <summary>
/// Gets the path for the unix socket Kestrel should bind to.
/// </summary>
/// <param name="startupConfig">The startup config.</param>
/// <param name="appPaths">The application paths.</param>
/// <returns>The path for Kestrel to bind to.</returns>
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;
}
/// <summary>
/// Sets the unix file permissions for Kestrel's socket file.
/// </summary>
/// <param name="startupConfig">The startup config.</param>
/// <param name="socketPath">The socket path.</param>
/// <param name="logger">The logger.</param>
[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);
}
}
/// <summary> /// <summary>
/// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist /// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist
/// already. /// already.

View File

@ -3,18 +3,15 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Reflection; using System.Reflection;
using System.Runtime.Versioning;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommandLine; using CommandLine;
using Emby.Server.Implementations; using Emby.Server.Implementations;
using Jellyfin.Server.Extensions;
using Jellyfin.Server.Helpers; using Jellyfin.Server.Helpers;
using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -182,7 +179,7 @@ namespace Jellyfin.Server
{ {
var host = Host.CreateDefaultBuilder() var host = Host.CreateDefaultBuilder()
.ConfigureServices(services => appHost.Init(services)) .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)) .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(options, appPaths, startupConfig))
.UseSerilog() .UseSerilog()
.Build(); .Build();
@ -199,9 +196,9 @@ namespace Jellyfin.Server
if (!OperatingSystem.IsWindows() && startupConfig.UseUnixSocket()) 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) catch (Exception ex) when (ex is not TaskCanceledException)
@ -251,75 +248,6 @@ namespace Jellyfin.Server
} }
} }
/// <summary>
/// Configure the web host builder.
/// </summary>
/// <param name="builder">The builder to configure.</param>
/// <param name="appHost">The application host.</param>
/// <param name="startupConfig">The application configuration.</param>
/// <param name="appPaths">The application paths.</param>
/// <returns>The configured web host builder.</returns>
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));
}
/// <summary> /// <summary>
/// Create the application configuration. /// Create the application configuration.
/// </summary> /// </summary>
@ -393,39 +321,5 @@ namespace Jellyfin.Server
return "\"" + arg + "\""; 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);
}
}
} }
} }

View File

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using Emby.Server.Implementations; using Emby.Server.Implementations;
using Jellyfin.Server.Extensions;
using Jellyfin.Server.Helpers; using Jellyfin.Server.Helpers;
using MediaBrowser.Common; using MediaBrowser.Common;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -12,6 +13,7 @@ using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Serilog; using Serilog;
using Serilog.Extensions.Logging; using Serilog.Extensions.Logging;
@ -82,7 +84,7 @@ namespace Jellyfin.Server.Integration.Tests
_disposableComponents.Add(appHost); _disposableComponents.Add(appHost);
builder.ConfigureServices(services => appHost.Init(services)) builder.ConfigureServices(services => appHost.Init(services))
.ConfigureWebHostBuilder(appHost, startupConfig, appPaths) .ConfigureWebHostBuilder(appHost, startupConfig, appPaths, NullLogger.Instance)
.ConfigureAppConfiguration((context, builder) => .ConfigureAppConfiguration((context, builder) =>
{ {
builder builder