diff --git a/mRemoteNG/App/Update/AppUpdater.cs b/mRemoteNG/App/Update/AppUpdater.cs index e7c0e4bf..05a0b5dc 100644 --- a/mRemoteNG/App/Update/AppUpdater.cs +++ b/mRemoteNG/App/Update/AppUpdater.cs @@ -148,10 +148,14 @@ namespace mRemoteNG.App.Update } */ - public async Task DownloadUpdateAsync() + public async Task DownloadUpdateAsync(IProgress progress) { if (IsGetUpdateInfoRunning) { + getUpdateInfoCancelToken.Cancel(); + getUpdateInfoCancelToken.Dispose(); + getUpdateInfoCancelToken = null; + throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress."); } @@ -161,8 +165,7 @@ namespace mRemoteNG.App.Update "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); } #if !PORTABLE - CurrentUpdateInfo.UpdateFilePath = - Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); + CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); #else var sfd = new SaveFileDialog { @@ -179,7 +182,42 @@ namespace mRemoteNG.App.Update return; } #endif - // TODO: DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, CurrentUpdateInfo.UpdateFilePath); + try + { + getUpdateInfoCancelToken = new CancellationTokenSource(); + using (var response = await _httpClient.GetAsync(CurrentUpdateInfo.DownloadAddress, + HttpCompletionOption.ResponseHeadersRead, getUpdateInfoCancelToken.Token)) + { + var buffer = new byte[8192]; + var totalBytes = response.Content.Headers.ContentLength ?? 0; + var readBytes = 0L; + + await using var httpStream = + await response.Content.ReadAsStreamAsync(getUpdateInfoCancelToken.Token); + await using var fileStream = new FileStream(CurrentUpdateInfo.UpdateFilePath, FileMode.Create, + FileAccess.Write, FileShare.None, buffer.Length, true); + + while (readBytes <= totalBytes || !getUpdateInfoCancelToken.IsCancellationRequested) + { + var bytesRead = await httpStream.ReadAsync(buffer, 0, buffer.Length, getUpdateInfoCancelToken.Token); + if (bytesRead == 0) + { + progress.Report(100); + break; + } + + await fileStream.WriteAsync(buffer, 0, bytesRead, getUpdateInfoCancelToken.Token); + + readBytes += bytesRead; + + var percentComplete = (int)(readBytes * 100 / totalBytes); + progress.Report(percentComplete); + } + } + } finally{ + getUpdateInfoCancelToken.Dispose(); + getUpdateInfoCancelToken = null; + } } #endregion diff --git a/mRemoteNG/UI/Window/UpdateWindow.cs b/mRemoteNG/UI/Window/UpdateWindow.cs index 104cc011..6adfeb2c 100644 --- a/mRemoteNG/UI/Window/UpdateWindow.cs +++ b/mRemoteNG/UI/Window/UpdateWindow.cs @@ -11,13 +11,14 @@ using mRemoteNG.Messages; using mRemoteNG.Themes; using WeifenLuo.WinFormsUI.Docking; using mRemoteNG.Resources.Language; +using System.Threading.Tasks; namespace mRemoteNG.UI.Window { public partial class UpdateWindow : BaseWindow { private AppUpdater _appUpdate; - private bool _isUpdateDownloadHandlerDeclared; + //private bool _isUpdateDownloadHandlerDeclared; #region Public Methods @@ -43,7 +44,7 @@ namespace mRemoteNG.UI.Window ApplyTheme(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); - CheckForUpdate(); + CheckForUpdateAsync(); } private new void ApplyTheme() @@ -74,12 +75,12 @@ namespace mRemoteNG.UI.Window private void btnCheckForUpdate_Click(object sender, EventArgs e) { - CheckForUpdate(); + CheckForUpdateAsync(); } - private void btnDownload_Click(object sender, EventArgs e) + private async void btnDownload_Click(object sender, EventArgs e) { - DownloadUpdate(); + await DownloadUpdateAsync(); } private void pbUpdateImage_Click(object sender, EventArgs e) @@ -97,7 +98,7 @@ namespace mRemoteNG.UI.Window #region Private Methods - private async void CheckForUpdate() + private async void CheckForUpdateAsync() { if (_appUpdate == null) { @@ -192,7 +193,7 @@ namespace mRemoteNG.UI.Window prgbDownload.Visible = visible; } - private void DownloadUpdate() + private async Task DownloadUpdateAsync() { try { @@ -200,50 +201,18 @@ namespace mRemoteNG.UI.Window prgbDownload.Visible = true; prgbDownload.Value = 0; - if (_isUpdateDownloadHandlerDeclared == false) - { - // _appUpdate.DownloadUpdateProgressChangedEvent += DownloadUpdateProgressChanged; - // _appUpdate.DownloadUpdateCompletedEvent += DownloadUpdateCompleted; - _isUpdateDownloadHandlerDeclared = true; - } + await _appUpdate.DownloadUpdateAsync(new Progress(progress => prgbDownload.Value = progress)); - _appUpdate.DownloadUpdateAsync(); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadFailed, ex); - } - } - - #endregion - - #region Events - - - private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - prgbDownload.Value = e.ProgressPercentage; - } - - private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) - { - try - { btnDownload.Enabled = true; prgbDownload.Visible = false; - if (e.Cancelled) - return; - if (e.Error != null) - throw e.Error; - if (Runtime.IsPortableEdition) MessageBox.Show(Language.UpdatePortableDownloadComplete, Language.CheckForUpdates, - MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBoxButtons.OK, MessageBoxIcon.Information); else { if (MessageBox.Show(Language.UpdateDownloadComplete, Language.CheckForUpdates, - MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) + MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) { Shutdown.Quit(_appUpdate.CurrentUpdateInfo.UpdateFilePath); } @@ -255,8 +224,11 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { + Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadFailed, ex); + Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadCompleteFailed, ex); Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, ex.Message); + } }