aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
blob: dd3da2214a259f76d17bdf89ece5f70a87f393d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Updates;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;

namespace Emby.Server.Implementations.ScheduledTasks.Tasks;

/// <summary>
/// Plugin Update Task.
/// </summary>
public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
{
    private readonly ILogger<PluginUpdateTask> _logger;

    private readonly IInstallationManager _installationManager;
    private readonly ILocalizationManager _localization;

    /// <summary>
    /// Initializes a new instance of the <see cref="PluginUpdateTask" /> class.
    /// </summary>
    /// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
    /// <param name="installationManager">Instance of the <see cref="IInstallationManager"/> interface.</param>
    /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
    public PluginUpdateTask(ILogger<PluginUpdateTask> logger, IInstallationManager installationManager, ILocalizationManager localization)
    {
        _logger = logger;
        _installationManager = installationManager;
        _localization = localization;
    }

    /// <inheritdoc />
    public string Name => _localization.GetLocalizedString("TaskUpdatePlugins");

    /// <inheritdoc />
    public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription");

    /// <inheritdoc />
    public string Category => _localization.GetLocalizedString("TasksApplicationCategory");

    /// <inheritdoc />
    public string Key => "PluginUpdates";

    /// <inheritdoc />
    public bool IsHidden => false;

    /// <inheritdoc />
    public bool IsEnabled => true;

    /// <inheritdoc />
    public bool IsLogged => true;

    /// <inheritdoc />
    public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
    {
        yield return new TaskTriggerInfo
        {
            Type = TaskTriggerInfoType.StartupTrigger
        };

        yield return new TaskTriggerInfo
        {
            Type = TaskTriggerInfoType.IntervalTrigger,
            IntervalTicks = TimeSpan.FromHours(24).Ticks
        };
    }

    /// <inheritdoc />
    public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
    {
        progress.Report(0);

        var packageFetchTask = _installationManager.GetAvailablePluginUpdates(cancellationToken);
        var packagesToInstall = (await packageFetchTask.ConfigureAwait(false)).ToList();

        progress.Report(10);

        var numComplete = 0;

        foreach (var package in packagesToInstall)
        {
            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                await _installationManager.InstallPackage(package, cancellationToken).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
                // InstallPackage has its own inner cancellation token, so only throw this if it's ours
                if (cancellationToken.IsCancellationRequested)
                {
                    throw;
                }
            }
            catch (HttpRequestException ex)
            {
                _logger.LogError(ex, "Error downloading {Name}", package.Name);
            }
            catch (IOException ex)
            {
                _logger.LogError(ex, "Error updating {Name}", package.Name);
            }
            catch (TimeoutException ex)
            {
                // One slow download must not abort the updates for the remaining plugins.
                _logger.LogError(ex, "Error downloading {Name}", package.Name);
            }
            catch (InvalidDataException ex)
            {
                _logger.LogError(ex, "Error updating {Name}", package.Name);
            }

            // Update progress
            lock (progress)
            {
                progress.Report((90.0 * ++numComplete / packagesToInstall.Count) + 10);
            }
        }

        progress.Report(100);
    }
}