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