From c9579b7d991981e04b7b3ccdd1127d9c8287dfc1 Mon Sep 17 00:00:00 2001 From: Scott Whitney <79826944+puppetsw@users.noreply.github.com> Date: Sun, 25 Sep 2022 09:37:14 +0930 Subject: [PATCH 1/2] Removed obsolete WebClient. Updated code style. Removed unused events/properties. --- .../SideloadUpdateService.cs | 111 ++++++------------ .../ServicesImplementation/UpdateService.cs | 23 +--- src/Files.Backend/Services/IUpdateService.cs | 2 - 3 files changed, 45 insertions(+), 91 deletions(-) diff --git a/src/Files.App/ServicesImplementation/SideloadUpdateService.cs b/src/Files.App/ServicesImplementation/SideloadUpdateService.cs index 34549a401c16..4adf013d32ae 100644 --- a/src/Files.App/ServicesImplementation/SideloadUpdateService.cs +++ b/src/Files.App/ServicesImplementation/SideloadUpdateService.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; -using System.Net; +using System.IO; +using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using System.Xml.Serialization; using Windows.ApplicationModel; @@ -15,31 +16,30 @@ namespace Files.App.ServicesImplementation { - public class SideloadUpdateService : ObservableObject, IUpdateService + public sealed class SideloadUpdateService : ObservableObject, IUpdateService { - private const string SideloadStable = "https://cdn.files.community/files/stable/Files.Package.appinstaller"; - private const string SideloadPreview = "https://cdn.files.community/files/preview/Files.Package.appinstaller"; + private const string SIDELOAD_STABLE = "https://cdn.files.community/files/stable/Files.Package.appinstaller"; + private const string SIDELOAD_PREVIEW = "https://cdn.files.community/files/preview/Files.Package.appinstaller"; private bool _isUpdateAvailable; private bool _isUpdating; - private int _downloadPercentage; private readonly Dictionary _sideloadVersion = new() { - { "Files", SideloadStable }, - { "FilesPreview", SideloadPreview } + { "Files", SIDELOAD_STABLE }, + { "FilesPreview", SIDELOAD_PREVIEW } }; - private const string TemporaryUpdatePackageName = "UpdatePackage.msix"; + private const string TEMPORARY_UPDATE_PACKAGE_NAME = "UpdatePackage.msix"; - private ILogger Logger { get; } = Ioc.Default.GetService(); + private ILogger? Logger { get; } = Ioc.Default.GetService(); private string PackageName { get; } = Package.Current.Id.Name; private Version PackageVersion { get; } = new(Package.Current.Id.Version.Major, Package.Current.Id.Version.Minor, Package.Current.Id.Version.Build, Package.Current.Id.Version.Revision); - private Uri DownloadUri { get; set; } + private Uri? DownloadUri { get; set; } public bool IsUpdateAvailable { @@ -53,12 +53,6 @@ public bool IsUpdating private set => SetProperty(ref _isUpdating, value); } - public int DownloadPercentage - { - get => _downloadPercentage; - private set => SetProperty(ref _downloadPercentage, value); - } - public async Task DownloadUpdates() { await ApplyPackageUpdate(); @@ -71,55 +65,44 @@ public Task DownloadMandatoryUpdates() public async Task CheckForUpdates() { - Logger.Info($"SIDELOAD: Checking for updates..."); - await CheckForRemoteUpdate(_sideloadVersion[PackageName]); - } - - private async Task CheckForRemoteUpdate(string uri) - { - if (string.IsNullOrEmpty(uri)) - { - throw new ArgumentNullException(nameof(uri)); - } - try { - using var client = new WebClient(); - using var stream = await client.OpenReadTaskAsync(uri); + Logger?.Info($"SIDELOAD: Checking for updates..."); + + using var client = new HttpClient(); + await using var stream = await client.GetStreamAsync(_sideloadVersion[PackageName]); // Deserialize AppInstaller. XmlSerializer xml = new XmlSerializer(typeof(AppInstaller)); - var appInstaller = (AppInstaller)xml.Deserialize(stream); + var appInstaller = (AppInstaller?)xml.Deserialize(stream); if (appInstaller == null) - { throw new ArgumentNullException(nameof(appInstaller)); - } var remoteVersion = new Version(appInstaller.Version); - Logger.Info($"SIDELOAD: Current Package Name: {PackageName}"); - Logger.Info($"SIDELOAD: Remote Package Name: {appInstaller.MainBundle.Name}"); - Logger.Info($"SIDELOAD: Current Version: {PackageVersion}"); - Logger.Info($"SIDELOAD: Remote Version: {remoteVersion}"); + Logger?.Info($"SIDELOAD: Current Package Name: {PackageName}"); + Logger?.Info($"SIDELOAD: Remote Package Name: {appInstaller.MainBundle.Name}"); + Logger?.Info($"SIDELOAD: Current Version: {PackageVersion}"); + Logger?.Info($"SIDELOAD: Remote Version: {remoteVersion}"); // Check details and version number. if (appInstaller.MainBundle.Name.Equals(PackageName) && remoteVersion.CompareTo(PackageVersion) > 0) { - Logger.Info("SIDELOAD: Update found."); - Logger.Info("SIDELOAD: Starting background download."); + Logger?.Info("SIDELOAD: Update found."); + Logger?.Info("SIDELOAD: Starting background download."); DownloadUri = new Uri(appInstaller.MainBundle.Uri); await StartBackgroundDownload(); } else { - Logger.Warn("SIDELOAD: Update not found."); + Logger?.Warn("SIDELOAD: Update not found."); IsUpdateAvailable = false; } } catch (Exception e) { - Logger.Error(e, e.Message); + Logger?.Error(e, e.Message); } } @@ -127,58 +110,45 @@ private async Task StartBackgroundDownload() { try { - using var client = new WebClient(); - client.DownloadFileCompleted += BackgroundDownloadCompleted; - client.DownloadProgressChanged += BackgroundDownloadProgressChanged; + using var client = new HttpClient(); - // Use temp folder instead? - var tempDownloadPath = ApplicationData.Current.LocalFolder.Path + "\\" + TemporaryUpdatePackageName; + var tempDownloadPath = ApplicationData.Current.LocalFolder.Path + "\\" + TEMPORARY_UPDATE_PACKAGE_NAME; Stopwatch timer = Stopwatch.StartNew(); - await client.DownloadFileTaskAsync(DownloadUri, tempDownloadPath); + await using (var stream = await client.GetStreamAsync(DownloadUri)) + await using (var fileStream = new FileStream(tempDownloadPath, FileMode.CreateNew)) + await stream.CopyToAsync(fileStream); timer.Stop(); var timespan = timer.Elapsed; - Logger.Info($"Download time taken: {timespan.Hours:00}:{timespan.Minutes:00}:{timespan.Seconds:00}"); + Logger?.Info($"Download time taken: {timespan.Hours:00}:{timespan.Minutes:00}:{timespan.Seconds:00}"); - client.DownloadFileCompleted -= BackgroundDownloadCompleted; - client.DownloadProgressChanged -= BackgroundDownloadProgressChanged; + IsUpdateAvailable = true; } catch (Exception e) { - Logger.Error(e, e.Message); + Logger?.Error(e, e.Message); } } - private void BackgroundDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - DownloadPercentage = e.ProgressPercentage; - } - - private void BackgroundDownloadCompleted(object sender, AsyncCompletedEventArgs e) - { - IsUpdateAvailable = true; - } - private async Task ApplyPackageUpdate() { if (!IsUpdateAvailable) - { return; - } IsUpdating = true; PackageManager pm = new PackageManager(); - DeploymentResult result = null; + DeploymentResult? result = null; try { await Task.Run(async () => { - var bundlePath = new Uri(ApplicationData.Current.LocalFolder.Path + "\\" + TemporaryUpdatePackageName); + var bundlePath = new Uri(ApplicationData.Current.LocalFolder.Path + Path.DirectorySeparatorChar + + TEMPORARY_UPDATE_PACKAGE_NAME); var deployment = pm.RequestAddPackageAsync( bundlePath, @@ -194,18 +164,15 @@ await Task.Run(async () => catch (Exception e) { if (result?.ExtendedErrorCode != null) - { - Logger.Info(result.ErrorText); - } + Logger?.Info(result.ErrorText); - Logger.Error(e, e.Message); + Logger?.Error(e, e.Message); } finally { // Reset fields. IsUpdating = false; IsUpdateAvailable = false; - DownloadPercentage = 0; DownloadUri = null; } } @@ -215,7 +182,7 @@ await Task.Run(async () => /// AppInstaller class to hold information about remote updates. /// [XmlRoot(ElementName = "AppInstaller", Namespace = "http://schemas.microsoft.com/appx/appinstaller/2018")] - public class AppInstaller + public sealed class AppInstaller { [XmlElement("MainBundle")] public MainBundle MainBundle { get; set; } @@ -227,7 +194,7 @@ public class AppInstaller public string Version { get; set; } } - public class MainBundle + public sealed class MainBundle { [XmlAttribute("Name")] public string Name { get; set; } diff --git a/src/Files.App/ServicesImplementation/UpdateService.cs b/src/Files.App/ServicesImplementation/UpdateService.cs index adf7beb9948c..bba7e2113920 100644 --- a/src/Files.App/ServicesImplementation/UpdateService.cs +++ b/src/Files.App/ServicesImplementation/UpdateService.cs @@ -13,8 +13,8 @@ namespace Files.App.ServicesImplementation { internal sealed class UpdateService : ObservableObject, IUpdateService { - private StoreContext _storeContext; - private IList _updatePackages; + private StoreContext? _storeContext; + private IList? _updatePackages; private bool IsMandatory => _updatePackages?.Where(e => e.Mandatory).ToList().Count >= 1; @@ -23,11 +23,7 @@ internal sealed class UpdateService : ObservableObject, IUpdateService public bool IsUpdateAvailable { get => _isUpdateAvailable; - set - { - _isUpdateAvailable = value; - OnPropertyChanged(nameof(IsUpdateAvailable)); - } + set => SetProperty(ref _isUpdateAvailable, value); } private bool _isUpdating; @@ -35,16 +31,9 @@ public bool IsUpdateAvailable public bool IsUpdating { get => _isUpdating; - private set - { - _isUpdating = value; - OnPropertyChanged(nameof(IsUpdating)); - } + private set => SetProperty(ref _isUpdating, value); } - // TODO: This needs to be implemented in this service. - public int DownloadPercentage { get; } - public UpdateService() { _updatePackages = new List(); @@ -108,7 +97,7 @@ public async Task CheckForUpdates() private async Task DownloadAndInstall() { App.SaveSessionTabs(); - var downloadOperation = _storeContext.RequestDownloadAndInstallStorePackageUpdatesAsync(_updatePackages); + var downloadOperation = _storeContext?.RequestDownloadAndInstallStorePackageUpdatesAsync(_updatePackages); await downloadOperation.AsTask(); } @@ -166,7 +155,7 @@ private void OnUpdateCompleted() { IsUpdating = false; IsUpdateAvailable = false; - _updatePackages.Clear(); + _updatePackages?.Clear(); } private void OnUpdateCancelled() diff --git a/src/Files.Backend/Services/IUpdateService.cs b/src/Files.Backend/Services/IUpdateService.cs index 5db25cef3d4c..d455bba0d000 100644 --- a/src/Files.Backend/Services/IUpdateService.cs +++ b/src/Files.Backend/Services/IUpdateService.cs @@ -15,8 +15,6 @@ public interface IUpdateService : INotifyPropertyChanged /// bool IsUpdating { get; } - int DownloadPercentage { get; } - Task DownloadUpdates(); Task DownloadMandatoryUpdates(); From f29811d131a405628918817f2919909318f00df5 Mon Sep 17 00:00:00 2001 From: Scott Whitney <79826944+puppetsw@users.noreply.github.com> Date: Tue, 27 Sep 2022 15:46:18 +0930 Subject: [PATCH 2/2] Changed to FileMode.OpenOrCreate. Added PooledConnectionLifetime property to HttpClient --- .../SideloadUpdateService.cs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Files.App/ServicesImplementation/SideloadUpdateService.cs b/src/Files.App/ServicesImplementation/SideloadUpdateService.cs index 4adf013d32ae..d2a3299d65e7 100644 --- a/src/Files.App/ServicesImplementation/SideloadUpdateService.cs +++ b/src/Files.App/ServicesImplementation/SideloadUpdateService.cs @@ -3,20 +3,19 @@ using System.Diagnostics; using System.IO; using System.Net.Http; -using System.Threading; using System.Threading.Tasks; using System.Xml.Serialization; -using Windows.ApplicationModel; -using Windows.Management.Deployment; -using Windows.Storage; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.DependencyInjection; using Files.Backend.Services; using Files.Shared; +using Windows.ApplicationModel; +using Windows.Management.Deployment; +using Windows.Storage; namespace Files.App.ServicesImplementation { - public sealed class SideloadUpdateService : ObservableObject, IUpdateService + public sealed class SideloadUpdateService : ObservableObject, IUpdateService, IDisposable { private const string SIDELOAD_STABLE = "https://cdn.files.community/files/stable/Files.Package.appinstaller"; private const string SIDELOAD_PREVIEW = "https://cdn.files.community/files/preview/Files.Package.appinstaller"; @@ -24,6 +23,8 @@ public sealed class SideloadUpdateService : ObservableObject, IUpdateService private bool _isUpdateAvailable; private bool _isUpdating; + private readonly HttpClient _client = new(new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(1) }); + private readonly Dictionary _sideloadVersion = new() { { "Files", SIDELOAD_STABLE }, @@ -69,8 +70,7 @@ public async Task CheckForUpdates() { Logger?.Info($"SIDELOAD: Checking for updates..."); - using var client = new HttpClient(); - await using var stream = await client.GetStreamAsync(_sideloadVersion[PackageName]); + await using var stream = await _client.GetStreamAsync(_sideloadVersion[PackageName]); // Deserialize AppInstaller. XmlSerializer xml = new XmlSerializer(typeof(AppInstaller)); @@ -110,14 +110,12 @@ private async Task StartBackgroundDownload() { try { - using var client = new HttpClient(); - var tempDownloadPath = ApplicationData.Current.LocalFolder.Path + "\\" + TEMPORARY_UPDATE_PACKAGE_NAME; Stopwatch timer = Stopwatch.StartNew(); - await using (var stream = await client.GetStreamAsync(DownloadUri)) - await using (var fileStream = new FileStream(tempDownloadPath, FileMode.CreateNew)) + await using (var stream = await _client.GetStreamAsync(DownloadUri)) + await using (var fileStream = new FileStream(tempDownloadPath, FileMode.OpenOrCreate)) await stream.CopyToAsync(fileStream); timer.Stop(); @@ -176,6 +174,11 @@ await Task.Run(async () => DownloadUri = null; } } + + public void Dispose() + { + _client?.Dispose(); + } } ///