diff options
| author | Patrick Barron <barronpm@gmail.com> | 2023-01-14 15:47:26 -0500 |
|---|---|---|
| committer | Patrick Barron <barronpm@gmail.com> | 2023-01-15 15:48:07 -0500 |
| commit | 029d53502fafe11a67bde33551f1ab8b382829d7 (patch) | |
| tree | 803569df50d6fda4efe4527cefe5e9255f8c9c65 /Jellyfin.Server/Program.cs | |
| parent | 7186b343bd21fe6b4e771b8530bd780a98a84472 (diff) | |
Move some startup methods to StartupHelpers
Diffstat (limited to 'Jellyfin.Server/Program.cs')
| -rw-r--r-- | Jellyfin.Server/Program.cs | 268 |
1 files changed, 5 insertions, 263 deletions
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 540375dce..f6fa0ff5b 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -1,21 +1,19 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.Versioning; -using System.Text; using System.Threading; using System.Threading.Tasks; using CommandLine; using Emby.Server.Implementations; +using Jellyfin.Server.Helpers; using Jellyfin.Server.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; -using MediaBrowser.Model.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -25,7 +23,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Serilog; using Serilog.Extensions.Logging; -using SQLitePCL; using static MediaBrowser.Controller.Extensions.ConfigurationExtensions; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -99,7 +96,7 @@ namespace Jellyfin.Server Console.Error.WriteLine("Unhandled Exception\n" + e.ExceptionObject.ToString()); AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionToConsole; - ServerApplicationPaths appPaths = CreateApplicationPaths(options); + ServerApplicationPaths appPaths = StartupHelpers.CreateApplicationPaths(options); // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath); @@ -108,13 +105,12 @@ namespace Jellyfin.Server Environment.SetEnvironmentVariable("NEOReadDebugKeys", "1"); Environment.SetEnvironmentVariable("EnableExtendedVaFormats", "1"); - await InitLoggingConfigFile(appPaths).ConfigureAwait(false); + await StartupHelpers.InitLoggingConfigFile(appPaths).ConfigureAwait(false); // Create an instance of the application configuration to use for application startup IConfiguration startupConfig = CreateAppConfiguration(options, appPaths); - // Initialize logging framework - InitializeLoggingFramework(startupConfig, appPaths); + StartupHelpers.InitializeLoggingFramework(startupConfig, appPaths); _logger = _loggerFactory.CreateLogger("Main"); // Log uncaught exceptions to the logging instead of std error @@ -173,7 +169,7 @@ namespace Jellyfin.Server } } - PerformStaticInitialization(); + StartupHelpers.PerformStaticInitialization(); Migrations.MigrationRunner.RunPreStartup(appPaths, _loggerFactory); var appHost = new CoreAppHost( @@ -256,26 +252,6 @@ namespace Jellyfin.Server } /// <summary> - /// Call static initialization methods for the application. - /// </summary> - public static void PerformStaticInitialization() - { - // Make sure we have all the code pages we can get - // Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - - // Increase the max http request limit - // The default connection limit is 10 for ASP.NET hosted applications and 2 for all others. - ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit); - - // Disable the "Expect: 100-Continue" header by default - // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c - ServicePointManager.Expect100Continue = false; - - Batteries_V2.Init(); - } - - /// <summary> /// Configure the web host builder. /// </summary> /// <param name="builder">The builder to configure.</param> @@ -345,206 +321,6 @@ namespace Jellyfin.Server } /// <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% - /// for everything else the - /// <a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG approach</a> - /// is followed. - /// </summary> - /// <param name="options">The <see cref="StartupOptions" /> for this instance.</param> - /// <returns><see cref="ServerApplicationPaths" />.</returns> - private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options) - { - // dataDir - // IF --datadir - // ELSE IF $JELLYFIN_DATA_DIR - // ELSE IF windows, use <%APPDATA%>/jellyfin - // ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin - // ELSE use $HOME/.local/share/jellyfin - var dataDir = options.DataDir; - if (string.IsNullOrEmpty(dataDir)) - { - dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_DIR"); - - if (string.IsNullOrEmpty(dataDir)) - { - // LocalApplicationData follows the XDG spec on unix machines - dataDir = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "jellyfin"); - } - } - - // configDir - // IF --configdir - // ELSE IF $JELLYFIN_CONFIG_DIR - // ELSE IF --datadir, use <datadir>/config (assume portable run) - // ELSE IF <datadir>/config exists, use that - // ELSE IF windows, use <datadir>/config - // ELSE IF $XDG_CONFIG_HOME use $XDG_CONFIG_HOME/jellyfin - // ELSE $HOME/.config/jellyfin - var configDir = options.ConfigDir; - if (string.IsNullOrEmpty(configDir)) - { - configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR"); - - if (string.IsNullOrEmpty(configDir)) - { - if (options.DataDir is not null - || Directory.Exists(Path.Combine(dataDir, "config")) - || OperatingSystem.IsWindows()) - { - // Hang config folder off already set dataDir - configDir = Path.Combine(dataDir, "config"); - } - else - { - // $XDG_CONFIG_HOME defines the base directory relative to which - // user specific configuration files should be stored. - configDir = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME"); - - // If $XDG_CONFIG_HOME is either not set or empty, - // a default equal to $HOME /.config should be used. - if (string.IsNullOrEmpty(configDir)) - { - configDir = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - ".config"); - } - - configDir = Path.Combine(configDir, "jellyfin"); - } - } - } - - // cacheDir - // IF --cachedir - // ELSE IF $JELLYFIN_CACHE_DIR - // ELSE IF windows, use <datadir>/cache - // ELSE IF XDG_CACHE_HOME, use $XDG_CACHE_HOME/jellyfin - // ELSE HOME/.cache/jellyfin - var cacheDir = options.CacheDir; - if (string.IsNullOrEmpty(cacheDir)) - { - cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR"); - - if (string.IsNullOrEmpty(cacheDir)) - { - if (OperatingSystem.IsWindows()) - { - // Hang cache folder off already set dataDir - cacheDir = Path.Combine(dataDir, "cache"); - } - else - { - // $XDG_CACHE_HOME defines the base directory relative to which - // user specific non-essential data files should be stored. - cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME"); - - // If $XDG_CACHE_HOME is either not set or empty, - // a default equal to $HOME/.cache should be used. - if (string.IsNullOrEmpty(cacheDir)) - { - cacheDir = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), - ".cache"); - } - - cacheDir = Path.Combine(cacheDir, "jellyfin"); - } - } - } - - // webDir - // IF --webdir - // ELSE IF $JELLYFIN_WEB_DIR - // ELSE <bindir>/jellyfin-web - var webDir = options.WebDir; - if (string.IsNullOrEmpty(webDir)) - { - webDir = Environment.GetEnvironmentVariable("JELLYFIN_WEB_DIR"); - - if (string.IsNullOrEmpty(webDir)) - { - // Use default location under ResourcesPath - webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web"); - } - } - - // logDir - // IF --logdir - // ELSE IF $JELLYFIN_LOG_DIR - // ELSE IF --datadir, use <datadir>/log (assume portable run) - // ELSE <datadir>/log - var logDir = options.LogDir; - if (string.IsNullOrEmpty(logDir)) - { - logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR"); - - if (string.IsNullOrEmpty(logDir)) - { - // Hang log folder off already set dataDir - logDir = Path.Combine(dataDir, "log"); - } - } - - // Normalize paths. Only possible with GetFullPath for now - https://github.com/dotnet/runtime/issues/2162 - dataDir = Path.GetFullPath(dataDir); - logDir = Path.GetFullPath(logDir); - configDir = Path.GetFullPath(configDir); - cacheDir = Path.GetFullPath(cacheDir); - webDir = Path.GetFullPath(webDir); - - // Ensure the main folders exist before we continue - try - { - Directory.CreateDirectory(dataDir); - Directory.CreateDirectory(logDir); - Directory.CreateDirectory(configDir); - Directory.CreateDirectory(cacheDir); - } - catch (IOException ex) - { - Console.Error.WriteLine("Error whilst attempting to create folder"); - Console.Error.WriteLine(ex.ToString()); - Environment.Exit(1); - } - - return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir); - } - - /// <summary> - /// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist - /// already. - /// </summary> - /// <param name="appPaths">The application paths.</param> - /// <returns>A task representing the creation of the configuration file, or a completed task if the file already exists.</returns> - public static async Task InitLoggingConfigFile(IApplicationPaths appPaths) - { - // Do nothing if the config file already exists - string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, LoggingConfigFileDefault); - if (File.Exists(configPath)) - { - return; - } - - // Get a stream of the resource contents - // NOTE: The .csproj name is used instead of the assembly name in the resource path - const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json"; - Stream resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath) - ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); - await using (resource.ConfigureAwait(false)) - { - Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - await using (dst.ConfigureAwait(false)) - { - // Copy the resource contents to the expected file path for the config file - await resource.CopyToAsync(dst).ConfigureAwait(false); - } - } - } - - /// <summary> /// Create the application configuration. /// </summary> /// <param name="commandLineOpts">The command line options passed to the program.</param> @@ -579,40 +355,6 @@ namespace Jellyfin.Server .AddInMemoryCollection(commandLineOpts.ConvertToConfig()); } - /// <summary> - /// Initialize Serilog using configuration and fall back to defaults on failure. - /// </summary> - private static void InitializeLoggingFramework(IConfiguration configuration, IApplicationPaths appPaths) - { - try - { - // Serilog.Log is used by SerilogLoggerFactory when no logger is specified - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .Enrich.FromLogContext() - .Enrich.WithThreadId() - .CreateLogger(); - } - catch (Exception ex) - { - Log.Logger = new LoggerConfiguration() - .WriteTo.Console( - outputTemplate: "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}", - formatProvider: CultureInfo.InvariantCulture) - .WriteTo.Async(x => x.File( - Path.Combine(appPaths.LogDirectoryPath, "log_.log"), - rollingInterval: RollingInterval.Day, - outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message}{NewLine}{Exception}", - formatProvider: CultureInfo.InvariantCulture, - encoding: Encoding.UTF8)) - .Enrich.FromLogContext() - .Enrich.WithThreadId() - .CreateLogger(); - - Log.Logger.Fatal(ex, "Failed to create/read logger configuration"); - } - } - private static void StartNewInstance(StartupOptions options) { _logger.LogInformation("Starting new instance"); |
