mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-02 18:47:18 -05:00 
			
		
		
		
	Improvements to InstallationManager
This commit is contained in:
		
							parent
							
								
									d4a42a1680
								
							
						
					
					
						commit
						65a0ca2f32
					
				@ -346,7 +346,7 @@ namespace Emby.Server.Implementations.Activity
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void OnPluginUpdated(object sender, GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> e)
 | 
					        private void OnPluginUpdated(object sender, GenericEventArgs<(IPlugin, PackageVersionInfo)> e)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            CreateLogEntry(new ActivityLogEntry
 | 
					            CreateLogEntry(new ActivityLogEntry
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,11 @@
 | 
				
			|||||||
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
 | 
					    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <!-- We need C# 7.3 to compare tuples-->
 | 
				
			||||||
 | 
					     <LangVersion>latest</LangVersion>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
 | 
					  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
 | 
				
			||||||
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
 | 
					    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
using MediaBrowser.Common;
 | 
					 | 
				
			||||||
using MediaBrowser.Common.Updates;
 | 
					using MediaBrowser.Common.Updates;
 | 
				
			||||||
using MediaBrowser.Model.Net;
 | 
					using MediaBrowser.Model.Net;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
@ -25,13 +24,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private readonly IInstallationManager _installationManager;
 | 
					        private readonly IInstallationManager _installationManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly IApplicationHost _appHost;
 | 
					        public PluginUpdateTask(ILogger logger, IInstallationManager installationManager)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger = logger;
 | 
					            _logger = logger;
 | 
				
			||||||
            _installationManager = installationManager;
 | 
					            _installationManager = installationManager;
 | 
				
			||||||
            _appHost = appHost;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -40,14 +36,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
				
			|||||||
        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
 | 
					        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
 | 
				
			||||||
        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 | 
					        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return new[] { 
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            // At startup
 | 
					            // At startup
 | 
				
			||||||
                new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
 | 
					            yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerStartup };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Every so often
 | 
					            // Every so often
 | 
				
			||||||
                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
 | 
					            yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks };
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -72,7 +65,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                try
 | 
					                try
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
 | 
					                    await _installationManager.InstallPackage(package, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (OperationCanceledException)
 | 
					                catch (OperationCanceledException)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ using System.Collections.Concurrent;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using MediaBrowser.Common;
 | 
					using MediaBrowser.Common;
 | 
				
			||||||
@ -33,7 +34,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// The current installations
 | 
					        /// The current installations
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public List<Tuple<InstallationInfo, CancellationTokenSource>> CurrentInstallations { get; set; }
 | 
					        private List<(InstallationInfo info, CancellationTokenSource token)> _currentInstallations { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// The completed installations
 | 
					        /// The completed installations
 | 
				
			||||||
@ -47,49 +48,15 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
 | 
					        public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when [plugin uninstalled].
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        /// <param name="plugin">The plugin.</param>
 | 
					 | 
				
			||||||
        private void OnPluginUninstalled(IPlugin plugin)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            PluginUninstalled?.Invoke(this, new GenericEventArgs<IPlugin> { Argument = plugin });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Occurs when [plugin updated].
 | 
					        /// Occurs when [plugin updated].
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public event EventHandler<GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>>> PluginUpdated;
 | 
					        public event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when [plugin updated].
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        /// <param name="plugin">The plugin.</param>
 | 
					 | 
				
			||||||
        /// <param name="newVersion">The new version.</param>
 | 
					 | 
				
			||||||
        private void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _logger.LogInformation("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.versionStr ?? string.Empty, newVersion.classification);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            PluginUpdated?.Invoke(this, new GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> { Argument = new Tuple<IPlugin, PackageVersionInfo>(plugin, newVersion) });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _applicationHost.NotifyPendingRestart();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Occurs when [plugin updated].
 | 
					        /// Occurs when [plugin updated].
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
 | 
					        public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled;
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when [plugin installed].
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        /// <param name="package">The package.</param>
 | 
					 | 
				
			||||||
        private void OnPluginInstalled(PackageVersionInfo package)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            PluginInstalled?.Invoke(this, new GenericEventArgs<PackageVersionInfo> { Argument = package });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _applicationHost.NotifyPendingRestart();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// The _logger
 | 
					        /// The _logger
 | 
				
			||||||
@ -111,7 +78,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        private readonly IZipClient _zipClient;
 | 
					        private readonly IZipClient _zipClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public InstallationManager(
 | 
					        public InstallationManager(
 | 
				
			||||||
            ILoggerFactory loggerFactory,
 | 
					            ILogger<InstallationManager> logger,
 | 
				
			||||||
            IApplicationHost appHost,
 | 
					            IApplicationHost appHost,
 | 
				
			||||||
            IApplicationPaths appPaths,
 | 
					            IApplicationPaths appPaths,
 | 
				
			||||||
            IHttpClient httpClient,
 | 
					            IHttpClient httpClient,
 | 
				
			||||||
@ -120,15 +87,15 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            IFileSystem fileSystem,
 | 
					            IFileSystem fileSystem,
 | 
				
			||||||
            IZipClient zipClient)
 | 
					            IZipClient zipClient)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (loggerFactory == null)
 | 
					            if (logger == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                throw new ArgumentNullException(nameof(loggerFactory));
 | 
					                throw new ArgumentNullException(nameof(logger));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CurrentInstallations = new List<Tuple<InstallationInfo, CancellationTokenSource>>();
 | 
					            _currentInstallations = new List<(InstallationInfo, CancellationTokenSource)>();
 | 
				
			||||||
            _completedInstallationsInternal = new ConcurrentBag<InstallationInfo>();
 | 
					            _completedInstallationsInternal = new ConcurrentBag<InstallationInfo>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _logger = loggerFactory.CreateLogger(nameof(InstallationManager));
 | 
					            _logger = logger;
 | 
				
			||||||
            _applicationHost = appHost;
 | 
					            _applicationHost = appHost;
 | 
				
			||||||
            _appPaths = appPaths;
 | 
					            _appPaths = appPaths;
 | 
				
			||||||
            _httpClient = httpClient;
 | 
					            _httpClient = httpClient;
 | 
				
			||||||
@ -138,21 +105,12 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            _zipClient = zipClient;
 | 
					            _zipClient = zipClient;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static Version GetPackageVersion(PackageVersionInfo version)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new Version(ValueOrDefault(version.versionStr, "0.0.0.1"));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private static string ValueOrDefault(string str, string def)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return string.IsNullOrEmpty(str) ? def : str;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets all available packages.
 | 
					        /// Gets all available packages.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <returns>Task{List{PackageInfo}}.</returns>
 | 
					        /// <returns>Task{List{PackageInfo}}.</returns>
 | 
				
			||||||
        public async Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
 | 
					        public async Task<List<PackageInfo>> GetAvailablePackages(
 | 
				
			||||||
 | 
					            CancellationToken cancellationToken,
 | 
				
			||||||
            bool withRegistration = true,
 | 
					            bool withRegistration = true,
 | 
				
			||||||
            string packageType = null,
 | 
					            string packageType = null,
 | 
				
			||||||
            Version applicationVersion = null)
 | 
					            Version applicationVersion = null)
 | 
				
			||||||
@ -172,21 +130,13 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
 | 
					                Url = "https://repo.jellyfin.org/releases/plugin/manifest.json",
 | 
				
			||||||
                CancellationToken = cancellationToken,
 | 
					                CancellationToken = cancellationToken,
 | 
				
			||||||
                Progress = new SimpleProgress<double>(),
 | 
					 | 
				
			||||||
                CacheLength = GetCacheLength()
 | 
					                CacheLength = GetCacheLength()
 | 
				
			||||||
            }, "GET").ConfigureAwait(false))
 | 
					            }, HttpMethod.Get).ConfigureAwait(false))
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
            using (var stream = response.Content)
 | 
					            using (var stream = response.Content)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return FilterPackages(await _jsonSerializer.DeserializeFromStreamAsync<PackageInfo[]>(stream).ConfigureAwait(false));
 | 
					                return FilterPackages(await _jsonSerializer.DeserializeFromStreamAsync<PackageInfo[]>(stream).ConfigureAwait(false));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private PackageVersionClass GetSystemUpdateLevel()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return _applicationHost.SystemUpdateLevel;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static TimeSpan GetCacheLength()
 | 
					        private static TimeSpan GetCacheLength()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -211,7 +161,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                package.versions = versions
 | 
					                package.versions = versions
 | 
				
			||||||
                    .OrderByDescending(GetPackageVersion)
 | 
					                    .OrderByDescending(x => x.Version)
 | 
				
			||||||
                    .ToArray();
 | 
					                    .ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (package.versions.Length == 0)
 | 
					                if (package.versions.Length == 0)
 | 
				
			||||||
@ -294,7 +244,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return package.versions.FirstOrDefault(v => GetPackageVersion(v).Equals(version) && v.classification == classification);
 | 
					            return package.versions.FirstOrDefault(v => v.Version == version && v.classification == classification);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -331,7 +281,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return package.versions
 | 
					            return package.versions
 | 
				
			||||||
                .OrderByDescending(GetPackageVersion)
 | 
					                .OrderByDescending(x => x.Version)
 | 
				
			||||||
                .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, currentServerVersion));
 | 
					                .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, currentServerVersion));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -346,14 +296,14 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
 | 
					            var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var systemUpdateLevel = GetSystemUpdateLevel();
 | 
					            var systemUpdateLevel = _applicationHost.SystemUpdateLevel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Figure out what needs to be installed
 | 
					            // Figure out what needs to be installed
 | 
				
			||||||
            return _applicationHost.Plugins.Select(p =>
 | 
					            return _applicationHost.Plugins.Select(p =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel);
 | 
					                var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return latestPluginInfo != null && GetPackageVersion(latestPluginInfo) > p.Version ? latestPluginInfo : null;
 | 
					                return latestPluginInfo != null && latestPluginInfo.Version > p.Version ? latestPluginInfo : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }).Where(i => i != null)
 | 
					            }).Where(i => i != null)
 | 
				
			||||||
            .Where(p => !string.IsNullOrEmpty(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
 | 
					            .Where(p => !string.IsNullOrEmpty(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
 | 
				
			||||||
@ -368,7 +318,7 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
					        /// <param name="cancellationToken">The cancellation token.</param>
 | 
				
			||||||
        /// <returns>Task.</returns>
 | 
					        /// <returns>Task.</returns>
 | 
				
			||||||
        /// <exception cref="ArgumentNullException">package</exception>
 | 
					        /// <exception cref="ArgumentNullException">package</exception>
 | 
				
			||||||
        public async Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken)
 | 
					        public async Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (package == null)
 | 
					            if (package == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -391,12 +341,12 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var innerCancellationTokenSource = new CancellationTokenSource();
 | 
					            var innerCancellationTokenSource = new CancellationTokenSource();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource);
 | 
					            var tuple = (installationInfo, innerCancellationTokenSource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Add it to the in-progress list
 | 
					            // Add it to the in-progress list
 | 
				
			||||||
            lock (CurrentInstallations)
 | 
					            lock (_currentInstallations)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                CurrentInstallations.Add(tuple);
 | 
					                _currentInstallations.Add(tuple);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var innerProgress = new ActionableProgress<double>();
 | 
					            var innerProgress = new ActionableProgress<double>();
 | 
				
			||||||
@ -421,11 +371,11 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                await InstallPackageInternal(package, isPlugin, innerProgress, linkedToken).ConfigureAwait(false);
 | 
					                await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                lock (CurrentInstallations)
 | 
					                lock (_currentInstallations)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    CurrentInstallations.Remove(tuple);
 | 
					                    _currentInstallations.Remove(tuple);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _completedInstallationsInternal.Add(installationInfo);
 | 
					                _completedInstallationsInternal.Add(installationInfo);
 | 
				
			||||||
@ -434,9 +384,9 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (OperationCanceledException)
 | 
					            catch (OperationCanceledException)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                lock (CurrentInstallations)
 | 
					                lock (_currentInstallations)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    CurrentInstallations.Remove(tuple);
 | 
					                    _currentInstallations.Remove(tuple);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _logger.LogInformation("Package installation cancelled: {0} {1}", package.name, package.versionStr);
 | 
					                _logger.LogInformation("Package installation cancelled: {0} {1}", package.name, package.versionStr);
 | 
				
			||||||
@ -449,9 +399,9 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.LogError(ex, "Package installation failed");
 | 
					                _logger.LogError(ex, "Package installation failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                lock (CurrentInstallations)
 | 
					                lock (_currentInstallations)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    CurrentInstallations.Remove(tuple);
 | 
					                    _currentInstallations.Remove(tuple);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                PackageInstallationFailed?.Invoke(this, new InstallationFailedEventArgs
 | 
					                PackageInstallationFailed?.Invoke(this, new InstallationFailedEventArgs
 | 
				
			||||||
@ -477,16 +427,12 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        /// <param name="progress">The progress.</param>
 | 
					        /// <param name="progress">The progress.</param>
 | 
				
			||||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
					        /// <param name="cancellationToken">The cancellation token.</param>
 | 
				
			||||||
        /// <returns>Task.</returns>
 | 
					        /// <returns>Task.</returns>
 | 
				
			||||||
        private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken)
 | 
					        private async Task InstallPackageInternal(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            IPlugin plugin = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (isPlugin)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Set last update time if we were installed before
 | 
					            // Set last update time if we were installed before
 | 
				
			||||||
                plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase))
 | 
					            IPlugin plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
                           ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
 | 
					                           ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase));
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            string targetPath = plugin == null ? null : plugin.AssemblyFilePath;
 | 
					            string targetPath = plugin == null ? null : plugin.AssemblyFilePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -494,17 +440,20 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
            await PerformPackageInstallation(progress, targetPath, package, cancellationToken).ConfigureAwait(false);
 | 
					            await PerformPackageInstallation(progress, targetPath, package, cancellationToken).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Do plugin-specific processing
 | 
					            // Do plugin-specific processing
 | 
				
			||||||
            if (isPlugin)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
            if (plugin == null)
 | 
					            if (plugin == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                    OnPluginInstalled(package);
 | 
					                _logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                PluginInstalled?.Invoke(this, new GenericEventArgs<PackageVersionInfo>(package));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                    OnPluginUpdated(plugin, package);
 | 
					                _logger.LogInformation("Plugin updated: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
 | 
				
			||||||
                }
 | 
					
 | 
				
			||||||
 | 
					                PluginUpdated?.Invoke(this, new GenericEventArgs<(IPlugin, PackageVersionInfo)>((plugin, package)));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _applicationHost.NotifyPendingRestart();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async Task PerformPackageInstallation(IProgress<double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken)
 | 
					        private async Task PerformPackageInstallation(IProgress<double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken)
 | 
				
			||||||
@ -622,11 +571,34 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
                _config.SaveConfiguration();
 | 
					                _config.SaveConfiguration();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            OnPluginUninstalled(plugin);
 | 
					            PluginUninstalled?.Invoke(this, new GenericEventArgs<IPlugin> { Argument = plugin });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _applicationHost.NotifyPendingRestart();
 | 
					            _applicationHost.NotifyPendingRestart();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <inheritdoc/>
 | 
				
			||||||
 | 
					        public bool CancelInstallation(Guid id)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            lock (_currentInstallations)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var install = _currentInstallations.Find(x => x.Item1.Id == id);
 | 
				
			||||||
 | 
					                if (install == default((InstallationInfo, CancellationTokenSource)))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                install.Item2.Cancel();
 | 
				
			||||||
 | 
					                _currentInstallations.Remove(install);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Dispose(true);
 | 
				
			||||||
 | 
					            GC.SuppressFinalize(this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Releases unmanaged and - optionally - managed resources.
 | 
					        /// Releases unmanaged and - optionally - managed resources.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@ -635,21 +607,16 @@ namespace Emby.Server.Implementations.Updates
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (dispose)
 | 
					            if (dispose)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                lock (CurrentInstallations)
 | 
					                lock (_currentInstallations)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    foreach (var tuple in CurrentInstallations)
 | 
					                    foreach (var tuple in _currentInstallations)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        tuple.Item2.Dispose();
 | 
					                        tuple.Item2.Dispose();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    CurrentInstallations.Clear();
 | 
					                    _currentInstallations.Clear();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void Dispose()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Dispose(true);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -197,7 +197,7 @@ namespace MediaBrowser.Api
 | 
				
			|||||||
                throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
 | 
					                throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), CancellationToken.None);
 | 
					            await _installationManager.InstallPackage(package, new SimpleProgress<double>(), CancellationToken.None);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@ -206,13 +206,7 @@ namespace MediaBrowser.Api
 | 
				
			|||||||
        /// <param name="request">The request.</param>
 | 
					        /// <param name="request">The request.</param>
 | 
				
			||||||
        public void Delete(CancelPackageInstallation request)
 | 
					        public void Delete(CancelPackageInstallation request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var info = _installationManager.CurrentInstallations.FirstOrDefault(i => i.Item1.Id.Equals(request.Id));
 | 
					            _installationManager.CancelInstallation(new Guid(request.Id));
 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (info != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                info.Item2.Cancel();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -15,11 +15,6 @@ namespace MediaBrowser.Common.Updates
 | 
				
			|||||||
        event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
 | 
					        event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed;
 | 
				
			||||||
        event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
 | 
					        event EventHandler<InstallationEventArgs> PackageInstallationCancelled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// The current installations
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        List<Tuple<InstallationInfo, CancellationTokenSource>> CurrentInstallations { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// The completed installations
 | 
					        /// The completed installations
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@ -33,7 +28,7 @@ namespace MediaBrowser.Common.Updates
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Occurs when [plugin updated].
 | 
					        /// Occurs when [plugin updated].
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        event EventHandler<GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>>> PluginUpdated;
 | 
					        event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Occurs when [plugin updated].
 | 
					        /// Occurs when [plugin updated].
 | 
				
			||||||
@ -107,7 +102,7 @@ namespace MediaBrowser.Common.Updates
 | 
				
			|||||||
        /// <param name="cancellationToken">The cancellation token.</param>
 | 
					        /// <param name="cancellationToken">The cancellation token.</param>
 | 
				
			||||||
        /// <returns>Task.</returns>
 | 
					        /// <returns>Task.</returns>
 | 
				
			||||||
        /// <exception cref="ArgumentNullException">package</exception>
 | 
					        /// <exception cref="ArgumentNullException">package</exception>
 | 
				
			||||||
        Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress<double> progress, CancellationToken cancellationToken);
 | 
					        Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Uninstalls a plugin
 | 
					        /// Uninstalls a plugin
 | 
				
			||||||
@ -115,5 +110,12 @@ namespace MediaBrowser.Common.Updates
 | 
				
			|||||||
        /// <param name="plugin">The plugin.</param>
 | 
					        /// <param name="plugin">The plugin.</param>
 | 
				
			||||||
        /// <exception cref="ArgumentException"></exception>
 | 
					        /// <exception cref="ArgumentException"></exception>
 | 
				
			||||||
        void UninstallPlugin(IPlugin plugin);
 | 
					        void UninstallPlugin(IPlugin plugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Cancels the installation
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="id">The id of the package that is being installed</param>
 | 
				
			||||||
 | 
					        /// <returns>Returns true if the install was cancelled</returns>
 | 
				
			||||||
 | 
					        bool CancelInstallation(Guid id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -30,23 +30,25 @@ namespace MediaBrowser.Model.Updates
 | 
				
			|||||||
        /// The _version
 | 
					        /// The _version
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        private Version _version;
 | 
					        private Version _version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets or sets the version.
 | 
					        /// Gets or sets the version.
 | 
				
			||||||
        /// Had to make this an interpreted property since Protobuf can't handle Version
 | 
					        /// Had to make this an interpreted property since Protobuf can't handle Version
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <value>The version.</value>
 | 
					        /// <value>The version.</value>
 | 
				
			||||||
        [IgnoreDataMember]
 | 
					        [IgnoreDataMember]
 | 
				
			||||||
        public Version version => _version ?? (_version = new Version(ValueOrDefault(versionStr, "0.0.0.1")));
 | 
					        public Version Version
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Values the or default.
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        /// <param name="str">The STR.</param>
 | 
					 | 
				
			||||||
        /// <param name="def">The def.</param>
 | 
					 | 
				
			||||||
        /// <returns>System.String.</returns>
 | 
					 | 
				
			||||||
        private static string ValueOrDefault(string str, string def)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return string.IsNullOrEmpty(str) ? def : str;
 | 
					            get
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_version == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var ver = versionStr;
 | 
				
			||||||
 | 
					                    _version = new Version(string.IsNullOrEmpty(ver) ? "0.0.0.1" : ver);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return _version;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.Globalization;
 | 
					using System.Globalization;
 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
@ -347,7 +348,7 @@ namespace MediaBrowser.Providers.Omdb
 | 
				
			|||||||
                CancellationToken = cancellationToken,
 | 
					                CancellationToken = cancellationToken,
 | 
				
			||||||
                BufferContent = true,
 | 
					                BufferContent = true,
 | 
				
			||||||
                EnableDefaultUserAgent = true
 | 
					                EnableDefaultUserAgent = true
 | 
				
			||||||
            }, "GET");
 | 
					            }, HttpMethod.Get);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal string GetDataFilePath(string imdbId)
 | 
					        internal string GetDataFilePath(string imdbId)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user