diff options
Diffstat (limited to 'Jellyfin.Server')
| -rw-r--r-- | Jellyfin.Server/CoreAppHost.cs | 17 | ||||
| -rw-r--r-- | Jellyfin.Server/Jellyfin.Server.csproj | 17 | ||||
| -rw-r--r-- | Jellyfin.Server/Program.cs | 82 | ||||
| -rw-r--r-- | Jellyfin.Server/StartupOptions.cs | 26 |
4 files changed, 105 insertions, 37 deletions
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index b9b0cc3825..8b4b61e290 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -9,8 +9,21 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Server { + /// <summary> + /// Implementation of the abstract <see cref="ApplicationHost" /> class. + /// </summary> public class CoreAppHost : ApplicationHost { + /// <summary> + /// Initializes a new instance of the <see cref="CoreAppHost" /> class. + /// </summary> + /// <param name="applicationPaths">The <see cref="ServerApplicationPaths" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="imageEncoder">The <see cref="IImageEncoder" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param> + /// <param name="configuration">The <see cref="IConfiguration" /> to be used by the <see cref="CoreAppHost" />.</param> public CoreAppHost( ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, @@ -30,15 +43,19 @@ namespace Jellyfin.Server { } + /// <inheritdoc /> public override bool CanSelfRestart => StartupOptions.RestartPath != null; + /// <inheritdoc /> protected override void RestartInternal() => Program.Restart(); + /// <inheritdoc /> protected override IEnumerable<Assembly> GetAssembliesWithPartsInternal() { yield return typeof(CoreAppHost).Assembly; } + /// <inheritdoc /> protected override void ShutdownInternal() => Program.Shutdown(); } } diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 641b3f1827..efdb75f980 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -3,16 +3,14 @@ <PropertyGroup> <AssemblyName>jellyfin</AssemblyName> <OutputType>Exe</OutputType> - <TargetFramework>netcoreapp2.1</TargetFramework> + <TargetFramework>netcoreapp3.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup> <PropertyGroup> - <!-- We need C# 7.1 for async main--> + <!-- We need at least C# 7.1 for async main--> <LangVersion>latest</LangVersion> - <!-- Disable documentation warnings (for now) --> - <NoWarn>SA1600;SA1601;SA1629;CS1591</NoWarn> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> @@ -24,9 +22,9 @@ <EmbeddedResource Include="Resources/Configuration/*" /> </ItemGroup> - <!-- Code analysers--> + <!-- Code analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.3" /> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" /> <PackageReference Include="SerilogAnalyzer" Version="0.15.0" /> </ItemGroup> @@ -36,22 +34,21 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="CommandLineParser" Version="2.5.0" /> + <PackageReference Include="CommandLineParser" Version="2.6.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.4" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /> - <PackageReference Include="Serilog.AspNetCore" Version="2.1.1" /> + <PackageReference Include="Serilog.AspNetCore" Version="3.0.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> <PackageReference Include="Serilog.Sinks.File" Version="4.0.0" /> <PackageReference Include="SkiaSharp" Version="1.68.0" /> - <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.14" /> + <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.1" /> <PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.14" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj" /> - <ProjectReference Include="..\Emby.IsoMounting\IsoMounter\IsoMounter.csproj" /> <ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" /> <ProjectReference Include="..\Jellyfin.Drawing.Skia\Jellyfin.Drawing.Skia.csproj" /> </ItemGroup> diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 08c0983bef..e8bd0cd309 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -18,17 +18,19 @@ using Jellyfin.Drawing.Skia; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; -using Serilog.AspNetCore; +using Serilog.Extensions.Logging; using SQLitePCL; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Jellyfin.Server { + /// <summary> + /// Class containing the entry point of the application. + /// </summary> public static class Program { private static readonly CancellationTokenSource _tokenSource = new CancellationTokenSource(); @@ -36,17 +38,22 @@ namespace Jellyfin.Server private static ILogger _logger; private static bool _restartOnShutdown; + /// <summary> + /// The entry point of the application. + /// </summary> + /// <param name="args">The command line arguments passed.</param> + /// <returns><see cref="Task" />.</returns> public static Task Main(string[] args) { // For backwards compatibility. // Modify any input arguments now which start with single-hyphen to POSIX standard // double-hyphen to allow parsing by CommandLineParser package. - const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx - const string substitution = @"-$1"; // Prepend with additional single-hyphen - var regex = new Regex(pattern); + const string Pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx + const string Substitution = @"-$1"; // Prepend with additional single-hyphen + var regex = new Regex(Pattern); for (var i = 0; i < args.Length; i++) { - args[i] = regex.Replace(args[i], substitution); + args[i] = regex.Replace(args[i], Substitution); } // Parse the command line arguments and either start the app or exit indicating error @@ -54,7 +61,10 @@ namespace Jellyfin.Server .MapResult(StartApp, _ => Task.CompletedTask); } - public static void Shutdown() + /// <summary> + /// Shuts down the application. + /// </summary> + internal static void Shutdown() { if (!_tokenSource.IsCancellationRequested) { @@ -62,7 +72,10 @@ namespace Jellyfin.Server } } - public static void Restart() + /// <summary> + /// Restarts the application. + /// </summary> + internal static void Restart() { _restartOnShutdown = true; @@ -71,6 +84,8 @@ namespace Jellyfin.Server private static async Task StartApp(StartupOptions options) { + var stopWatch = new Stopwatch(); + stopWatch.Start(); ServerApplicationPaths appPaths = CreateApplicationPaths(options); // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager @@ -112,7 +127,9 @@ namespace Jellyfin.Server Shutdown(); }; - _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version); + _logger.LogInformation( + "Jellyfin version: {Version}", + Assembly.GetEntryAssembly().GetName().Version.ToString(3)); ApplicationHost.LogEnvironmentInfo(_logger, appPaths); @@ -134,17 +151,18 @@ namespace Jellyfin.Server Batteries_V2.Init(); if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK) { - Console.WriteLine("WARN: Failed to enable shared cache for SQLite"); + _logger.LogWarning("Failed to enable shared cache for SQLite"); } - using (var appHost = new CoreAppHost( + var appHost = new CoreAppHost( appPaths, _loggerFactory, options, new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths), new NullImageEncoder(), new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()), - appConfig)) + appConfig); + try { await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false); @@ -152,15 +170,24 @@ namespace Jellyfin.Server await appHost.RunStartupTasksAsync().ConfigureAwait(false); - try - { - // Block main thread until shutdown - await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false); - } - catch (TaskCanceledException) - { - // Don't throw on cancellation - } + stopWatch.Stop(); + + _logger.LogInformation("Startup complete {Time:g}", stopWatch.Elapsed); + + // Block main thread until shutdown + await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + // Don't throw on cancellation + } + catch (Exception ex) + { + _logger.LogCritical(ex, "Error while starting server."); + } + finally + { + appHost?.Dispose(); } if (_restartOnShutdown) @@ -172,11 +199,12 @@ 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 XDG approach is followed: - /// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + /// 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">StartupOptions</param> - /// <returns>ServerApplicationPaths</returns> + /// <param name="options">The <see cref="StartupOptions" /> for this instance.</param> + /// <returns><see cref="ServerApplicationPaths" />.</returns> private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options) { // dataDir @@ -292,7 +320,7 @@ namespace Jellyfin.Server if (string.IsNullOrEmpty(webDir)) { // Use default location under ResourcesPath - webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web", "src"); + webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web"); } } @@ -348,7 +376,7 @@ namespace Jellyfin.Server return new ConfigurationBuilder() .SetBasePath(appPaths.ConfigurationDirectoryPath) - .AddJsonFile("logging.json") + .AddJsonFile("logging.json", false, true) .AddEnvironmentVariables("JELLYFIN_") .AddInMemoryCollection(ConfigurationOptions.Configuration) .Build(); diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index 8296d414ef..bb0adaf630 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -8,36 +8,62 @@ namespace Jellyfin.Server /// </summary> public class StartupOptions : IStartupOptions { + /// <summary> + /// Gets or sets the path to the data directory. + /// </summary> + /// <value>The path to the data directory.</value> [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")] public string DataDir { get; set; } + /// <summary> + /// Gets or sets the path to the web directory. + /// </summary> + /// <value>The path to the web directory.</value> [Option('w', "webdir", Required = false, HelpText = "Path to the Jellyfin web UI resources.")] public string WebDir { get; set; } + /// <summary> + /// Gets or sets the path to the cache directory. + /// </summary> + /// <value>The path to the cache directory.</value> [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")] public string CacheDir { get; set; } + /// <summary> + /// Gets or sets the path to the config directory. + /// </summary> + /// <value>The path to the config directory.</value> [Option('c', "configdir", Required = false, HelpText = "Path to use for configuration data (user settings and pictures).")] public string ConfigDir { get; set; } + /// <summary> + /// Gets or sets the path to the log directory. + /// </summary> + /// <value>The path to the log directory.</value> [Option('l', "logdir", Required = false, HelpText = "Path to use for writing log files.")] public string LogDir { get; set; } + /// <inheritdoc /> [Option("ffmpeg", Required = false, HelpText = "Path to external FFmpeg executable to use in place of default found in PATH.")] public string FFmpegPath { get; set; } + /// <inheritdoc /> [Option("service", Required = false, HelpText = "Run as headless service.")] public bool IsService { get; set; } + /// <inheritdoc /> [Option("noautorunwebapp", Required = false, HelpText = "Run headless if startup wizard is complete.")] public bool NoAutoRunWebApp { get; set; } + /// <inheritdoc /> [Option("package-name", Required = false, HelpText = "Used when packaging Jellyfin (example, synology).")] public string PackageName { get; set; } + /// <inheritdoc /> [Option("restartpath", Required = false, HelpText = "Path to restart script.")] public string RestartPath { get; set; } + /// <inheritdoc /> [Option("restartargs", Required = false, HelpText = "Arguments for restart script.")] public string RestartArgs { get; set; } } |
