Pārlūkot izejas kodu

Merge pull request #2515 from JustAMan/migration-scripts

Implement ability to run migration routines when updating Jellyfin
Joshua M. Boniface 5 gadi atpakaļ
vecāks
revīzija
dcf3dbb250

+ 28 - 0
Jellyfin.Server/CoreAppHost.cs

@@ -57,5 +57,33 @@ namespace Jellyfin.Server
 
         /// <inheritdoc />
         protected override void ShutdownInternal() => Program.Shutdown();
+
+        /// <summary>
+        /// Runs the migration routines if necessary.
+        /// </summary>
+        public void TryMigrate()
+        {
+            var previousVersion = ConfigurationManager.CommonConfiguration.PreviousVersion;
+            switch (ApplicationVersion.CompareTo(previousVersion))
+            {
+                case 1:
+                    Logger.LogWarning("Version check shows Jellyfin was updated: previous version={0}, current version={1}", previousVersion, ApplicationVersion);
+
+                    Migrations.Run(this, Logger);
+
+                    ConfigurationManager.CommonConfiguration.PreviousVersion = ApplicationVersion;
+                    ConfigurationManager.SaveConfiguration();
+                    break;
+                case 0:
+                    // nothing to do, versions match
+                    break;
+                case -1:
+                    Logger.LogWarning("Version check shows Jellyfin was rolled back, use at your own risk: previous version={0}, current version={1}", previousVersion, ApplicationVersion);
+                    // no "rollback" routines for now
+                    ConfigurationManager.CommonConfiguration.PreviousVersion = ApplicationVersion;
+                    ConfigurationManager.SaveConfiguration();
+                    break;
+            }
+        }
     }
 }

+ 92 - 0
Jellyfin.Server/Migrations.cs

@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server
+{
+    /// <summary>
+    /// The class that knows how migrate between different Jellyfin versions.
+    /// </summary>
+    internal static class Migrations
+    {
+        private static readonly IUpdater[] _migrations =
+        {
+            new Pre10_5()
+        };
+
+        /// <summary>
+        /// Interface that descibes a migration routine.
+        /// </summary>
+        private interface IUpdater
+        {
+            /// <summary>
+            /// Gets maximum version this Updater applies to.
+            /// If current version is greater or equal to it, skip the updater.
+            /// </summary>
+            public abstract Version Maximum { get; }
+
+            /// <summary>
+            /// Execute the migration from version "from".
+            /// </summary>
+            /// <param name="host">Host that hosts current version.</param>
+            /// <param name="logger">Host logger.</param>
+            /// <param name="from">Version to migrate from.</param>
+            /// <returns>Whether configuration was changed.</returns>
+            public abstract bool Perform(CoreAppHost host, ILogger logger, Version from);
+        }
+
+        /// <summary>
+        /// Run all needed migrations.
+        /// </summary>
+        /// <param name="host">CoreAppHost that hosts current version.</param>
+        /// <param name="logger">AppHost logger.</param>
+        /// <returns>Whether anything was changed.</returns>
+        public static bool Run(CoreAppHost host, ILogger logger)
+        {
+            bool updated = false;
+            var version = host.ServerConfigurationManager.CommonConfiguration.PreviousVersion;
+
+            for (var i = 0; i < _migrations.Length; i++)
+            {
+                var updater = _migrations[i];
+                if (version.CompareTo(updater.Maximum) >= 0)
+                {
+                    logger.LogDebug("Skipping updater {0} as current version {1} >= its maximum applicable version {2}", updater, version, updater.Maximum);
+                    continue;
+                }
+
+                if (updater.Perform(host, logger, version))
+                {
+                    updated = true;
+                }
+
+                version = updater.Maximum;
+            }
+
+            return updated;
+        }
+
+        private class Pre10_5 : IUpdater
+        {
+            public Version Maximum { get => Version.Parse("10.5.0"); }
+
+            public bool Perform(CoreAppHost host, ILogger logger, Version from)
+            {
+                // Set EnableThrottling to false as it wasn't used before, and in 10.5.0 it may introduce issues
+                var encoding = ((IConfigurationManager)host.ServerConfigurationManager).GetConfiguration<EncodingOptions>("encoding");
+                if (encoding.EnableThrottling)
+                {
+                    logger.LogInformation("Disabling transcoding throttling during migration");
+                    encoding.EnableThrottling = false;
+
+                    host.ServerConfigurationManager.SaveConfiguration("encoding", encoding);
+                    return true;
+                }
+
+                return false;
+            }
+        }
+    }
+}

+ 1 - 0
Jellyfin.Server/Program.cs

@@ -182,6 +182,7 @@ namespace Jellyfin.Server
                 // A bit hacky to re-use service provider since ASP.NET doesn't allow a custom service collection.
                 appHost.ServiceProvider = host.Services;
                 appHost.FindParts();
+                appHost.TryMigrate();
 
                 try
                 {

+ 21 - 0
MediaBrowser.Model/Configuration/BaseApplicationConfiguration.cs

@@ -1,3 +1,6 @@
+using System;
+using System.Xml.Serialization;
+
 namespace MediaBrowser.Model.Configuration
 {
     /// <summary>
@@ -25,6 +28,24 @@ namespace MediaBrowser.Model.Configuration
         /// <value>The cache path.</value>
         public string CachePath { get; set; }
 
+        /// <summary>
+        /// Last known version that was ran using the configuration.
+        /// </summary>
+        /// <value>The version from previous run.</value>
+        [XmlIgnore]
+        public Version PreviousVersion { get; set; }
+
+        /// <summary>
+        /// Stringified PreviousVersion to be stored/loaded,
+        /// because System.Version itself isn't xml-serializable
+        /// </summary>
+        /// <value>String value of PreviousVersion</value>
+        public string PreviousVersionStr
+        {
+            get => PreviousVersion?.ToString();
+            set => PreviousVersion = Version.Parse(value);
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseApplicationConfiguration" /> class.
         /// </summary>