aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Common.Implementations/Updates/PackageManager.cs
blob: a9335dce0ea3641abaaec8df52a1df5743d967b0 (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
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Kernel;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Updates;

namespace MediaBrowser.Common.Implementations.Updates
{
    public class PackageManager : IPackageManager
    {
        public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(IHttpClient client, 
            INetworkManager networkManager, 
            ISecurityManager securityManager, 
            ResourcePool resourcePool, 
            IJsonSerializer serializer, 
            CancellationToken cancellationToken)
        {
            var data = new Dictionary<string, string> { { "key", securityManager.SupporterKey }, { "mac", networkManager.GetMacAddress() } };

            using (var json = await client.Post(Constants.Constants.MBAdminUrl + "service/package/retrieveall", data, resourcePool.Mb, cancellationToken).ConfigureAwait(false))
            {
                cancellationToken.ThrowIfCancellationRequested();

                var packages = serializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
                foreach (var package in packages)
                {
                    package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
                        .OrderByDescending(v => v.version).ToList();
                }

                return packages;
            }

        }

        public async Task InstallPackage(IHttpClient client, ILogger logger, ResourcePool resourcePool, IProgress<double> progress, IZipClient zipClient, IApplicationPaths appPaths, PackageVersionInfo package, CancellationToken cancellationToken)
        {
            // Target based on if it is an archive or single assembly
            //  zip archives are assumed to contain directory structures relative to our ProgramDataPath
            var isArchive = string.Equals(Path.GetExtension(package.sourceUrl), ".zip", StringComparison.OrdinalIgnoreCase);
            var target = isArchive ? appPaths.ProgramDataPath : Path.Combine(appPaths.PluginsPath, package.targetFilename);

            // Download to temporary file so that, if interrupted, it won't destroy the existing installation
            var tempFile = await client.GetTempFile(package.sourceUrl, resourcePool.Mb, cancellationToken, progress).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            // Validate with a checksum
            if (package.checksum != Guid.Empty) // support for legacy uploads for now
            {
                using (var crypto = new MD5CryptoServiceProvider())
                using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000))
                {
                    var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty));
                    if (check != package.checksum)
                    {
                        throw new ApplicationException(string.Format("Download validation failed for {0}.  Probably corrupted during transfer.", package.name));
                    }
                }
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Success - move it to the real target based on type
            if (isArchive)
            {
                try
                {
                    zipClient.ExtractAll(tempFile, target, true);
                }
                catch (IOException e)
                {
                    logger.ErrorException("Error attempting to extract archive from {0} to {1}", e, tempFile, target);
                    throw;
                }

            }
            else
            {
                try
                {
                    File.Copy(tempFile, target, true);
                    File.Delete(tempFile);
                }
                catch (IOException e)
                {
                    logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target);
                    throw;
                }
            }

        }
    }
}