123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- #define TRACE
- using System;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.Net;
- using System.Reflection;
- using System.Threading;
- namespace Microsoft.Samples.AppUpdater
- {
- public class AppDownloader
- {
- internal delegate void NotifyUpdateFileInfoEventHandler(object sender, NotifyUpdateFileInfoEventArgs e);
- internal delegate void UpdateCompleteEventHandler(object sender, UpdateCompleteEventArgs e);
- private AppUpdater AppMan;
- private Thread UpdaterThread;
- private AppStartConfig Config;
- private UpdateLog Log;
- private UpdateCompleteEventArgs UpdateEventArgs;
- private NotifyUpdateFileInfoEventArgs UpdateFileInfoEventArgs;
- private AppKeys Keys;
- private bool _ValidateAssemblies;
- private bool _SynchronizationDownload;
- private int _SecondsBetweenDownloadRetry = 60;
- private int _DownloadRetryAttempts = 3;
- private int _UpdateRetryAttempts = 2;
- [Description("Specifies whether or not downloaded assemblies must be signed with valid public keys inorder to be downloaded.")]
- [DefaultValue(false)]
- public bool ValidateAssemblies
- {
- get
- {
- return _ValidateAssemblies;
- }
- set
- {
- _ValidateAssemblies = value;
- }
- }
- [Description("Specifies whether or not downloaded assemblies must be Synchronize.")]
- [DefaultValue(false)]
- public bool SynchronizationDownload
- {
- get
- {
- return _SynchronizationDownload;
- }
- set
- {
- _SynchronizationDownload = value;
- }
- }
- [Description("Seconds between download retry attempts.")]
- [DefaultValue(60)]
- public int SecondsBetweenDownloadRetry
- {
- get
- {
- return _SecondsBetweenDownloadRetry;
- }
- set
- {
- _SecondsBetweenDownloadRetry = value;
- }
- }
- [DefaultValue(3)]
- [Description("Number of times to retry downloads when an error is encountered.")]
- public int DownloadRetryAttempts
- {
- get
- {
- return _DownloadRetryAttempts;
- }
- set
- {
- _DownloadRetryAttempts = value;
- }
- }
- [DefaultValue(2)]
- [Description("Number of times times to retry the app update.")]
- public int UpdateRetryAttempts
- {
- get
- {
- return _UpdateRetryAttempts;
- }
- set
- {
- _UpdateRetryAttempts = value;
- }
- }
- [Browsable(false)]
- public UpdateState State => AppMan.Manifest.State;
- internal event NotifyUpdateFileInfoEventHandler OnNotifyUpdateFileInfo;
- internal event UpdateCompleteEventHandler OnUpdateComplete;
- public AppDownloader(AppUpdater appMan)
- {
- AppMan = appMan;
- Log = new UpdateLog();
- UpdateEventArgs = new UpdateCompleteEventArgs();
- UpdateFileInfoEventArgs = new NotifyUpdateFileInfoEventArgs();
- }
- public void Start()
- {
- if (!SynchronizationDownload)
- {
- if (UpdaterThread == null)
- {
- UpdaterThread = new Thread(RunThread);
- }
- else if (!UpdaterThread.IsAlive)
- {
- UpdaterThread = new Thread(RunThread);
- }
- UpdaterThread.Name = "Updater Thread";
- if (!UpdaterThread.IsAlive)
- {
- UpdaterThread.Start();
- }
- }
- else
- {
- RunThread();
- }
- }
- public void Stop()
- {
- if (UpdaterThread != null && UpdaterThread.IsAlive)
- {
- UpdaterThread.Abort();
- UpdaterThread = null;
- }
- }
- public void RunThread()
- {
- string directoryName = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
- directoryName = Path.Combine(Directory.GetParent(directoryName).FullName, "AppStart.config");
- Config = AppStartConfig.Load(directoryName);
- try
- {
- if (AppMan.Manifest.State.Phase == UpdatePhases.Complete)
- {
- AppMan.Manifest.State.Phase = UpdatePhases.Scavenging;
- AppMan.Manifest.State.UpdateFailureCount = 0;
- AppMan.Manifest.State.UpdateFailureEncoutered = false;
- AppMan.Manifest.State.DownloadDestination = CreateTempDirectory();
- if (AppMan.ChangeDetectionMode == ChangeDetectionModes.ServerManifestCheck)
- {
- ServerManifest serverManifest = new ServerManifest();
- serverManifest.Load(AppMan.UpdateUrl);
- AppMan.Manifest.State.DownloadSource = serverManifest.ApplicationUrl;
- }
- else
- {
- AppMan.Manifest.State.DownloadSource = AppMan.UpdateUrl;
- }
- AppMan.Manifest.Update();
- }
- if (AppMan.Manifest.State.Phase == UpdatePhases.Scavenging)
- {
- Scavenge();
- AppMan.Manifest.State.Phase = UpdatePhases.Downloading;
- AppMan.Manifest.Update();
- }
- if (AppMan.Manifest.State.Phase == UpdatePhases.Downloading)
- {
- Download();
- AppMan.Manifest.State.Phase = UpdatePhases.Validating;
- AppMan.Manifest.Update();
- }
- if (AppMan.Manifest.State.Phase == UpdatePhases.Validating)
- {
- Validate();
- AppMan.Manifest.State.Phase = UpdatePhases.Merging;
- AppMan.Manifest.Update();
- }
- if (AppMan.Manifest.State.Phase == UpdatePhases.Merging)
- {
- MergeDirectory(AppDomain.CurrentDomain.BaseDirectory, AppMan.Manifest.State.DownloadDestination);
- AppMan.Manifest.State.Phase = UpdatePhases.Finalizing;
- AppMan.Manifest.Update();
- }
- if (AppMan.Manifest.State.Phase == UpdatePhases.Finalizing)
- {
- FinalizeUpdate();
- }
- AppMan.Manifest.State.Phase = UpdatePhases.Complete;
- AppMan.Manifest.State.UpdateFailureCount = 0;
- AppMan.Manifest.State.UpdateFailureEncoutered = false;
- AppMan.Manifest.State.DownloadSource = "";
- AppMan.Manifest.State.DownloadDestination = "";
- AppMan.Manifest.State.NewVersionDirectory = "";
- AppMan.Manifest.Update();
- }
- catch (ThreadAbortException)
- {
- Thread.ResetAbort();
- return;
- }
- catch (Exception failureException)
- {
- UpdateEventArgs.FailureException = failureException;
- }
- if (AppMan.Manifest.State.Phase != 0)
- {
- HandleUpdateFailure();
- }
- else
- {
- HandleUpdateSuccess();
- }
- }
- private void HandleUpdateSuccess()
- {
- try
- {
- Log.AddSuccess(GetFileVersion(Config.AppExePath));
- }
- catch (Exception)
- {
- }
- if (this.OnUpdateComplete != null)
- {
- UpdateEventArgs.UpdateSucceeded = true;
- UpdateEventArgs.NewVersion = new Version(GetFileVersion(Config.AppExePath));
- if (UpdateEventArgs.ErrorMessage == "")
- {
- UpdateEventArgs.ErrorMessage = "Unknown Error";
- }
- this.OnUpdateComplete(this, UpdateEventArgs);
- }
- }
- private void HandleUpdateFailure()
- {
- try
- {
- Log.AddError(UpdateEventArgs.FailureException.ToString());
- }
- catch (Exception)
- {
- }
- AppMan.Manifest.State.UpdateFailureEncoutered = true;
- AppMan.Manifest.State.UpdateFailureCount++;
- AppMan.Manifest.Update();
- if (AppMan.Manifest.State.UpdateFailureCount >= UpdateRetryAttempts)
- {
- AppMan.Manifest.State.Phase = UpdatePhases.Complete;
- AppMan.Manifest.State.UpdateFailureEncoutered = false;
- AppMan.Manifest.State.UpdateFailureCount = 0;
- AppMan.Manifest.State.DownloadSource = "";
- AppMan.Manifest.State.DownloadDestination = "";
- AppMan.Manifest.Update();
- }
- if (this.OnUpdateComplete != null)
- {
- UpdateEventArgs.UpdateSucceeded = false;
- if (UpdateEventArgs.ErrorMessage == "")
- {
- UpdateEventArgs.ErrorMessage = "Unknown Error";
- }
- this.OnUpdateComplete(this, UpdateEventArgs);
- }
- }
- private void Download()
- {
- bool flag = true;
- int num = 0;
- int num2 = 0;
- WebFileLoader.NotifyUpdateFileInfoEventHandler value = this.OnNotifyUpdateFileInfo.Invoke;
- WebFileLoader.OnNotifyUpdateFileInfo += value;
- while (flag)
- {
- Thread.Sleep(TimeSpan.FromSeconds(num2));
- num2 = SecondsBetweenDownloadRetry;
- num++;
- Trace.WriteLine("APPMANAGER: Attempting to download update from: " + AppMan.Manifest.State.DownloadSource);
- try
- {
- int fileTotal = WebFileLoader.CopyDirectory(AppMan.Manifest.State.DownloadSource, AppMan.Manifest.State.DownloadDestination, 0, bReport: true);
- if (this.OnNotifyUpdateFileInfo != null)
- {
- UpdateFileInfoEventArgs.FileTotal = fileTotal;
- UpdateFileInfoEventArgs.FileName = "";
- UpdateFileInfoEventArgs.CurrentFile = -1;
- this.OnNotifyUpdateFileInfo(this, UpdateFileInfoEventArgs);
- }
- WebFileLoader.CopyDirectory(AppMan.Manifest.State.DownloadSource, AppMan.Manifest.State.DownloadDestination, fileTotal, bReport: true);
- flag = false;
- }
- catch (WebException ex)
- {
- if (num >= DownloadRetryAttempts)
- {
- UpdateEventArgs.ErrorMessage = "Download of a new update from '" + AppMan.Manifest.State.DownloadSource + "' failed with the network error: " + ex.Message;
- WebFileLoader.OnNotifyUpdateFileInfo -= value;
- throw ex;
- }
- }
- catch (IOException ex2)
- {
- if (num >= DownloadRetryAttempts)
- {
- UpdateEventArgs.ErrorMessage = "Saving the new update to disk at '" + AppMan.Manifest.State.DownloadDestination + "' failed with the following error: " + ex2.Message;
- WebFileLoader.OnNotifyUpdateFileInfo -= value;
- throw ex2;
- }
- }
- catch (Exception ex3)
- {
- if (num >= DownloadRetryAttempts)
- {
- UpdateEventArgs.ErrorMessage = "Update failed with the following error: '" + ex3.Message + "'";
- WebFileLoader.OnNotifyUpdateFileInfo -= value;
- throw ex3;
- }
- }
- finally
- {
- WebFileLoader.OnNotifyUpdateFileInfo -= value;
- }
- }
- }
- private void Validate()
- {
- if (ValidateAssemblies)
- {
- Keys = new AppKeys(AppMan.Manifest.State.DownloadSource);
- Keys.InitializeKeyCheck();
- try
- {
- ValidateDirectory(AppMan.Manifest.State.DownloadDestination);
- }
- catch (Exception)
- {
- Keys.UnInitializeKeyCheck();
- HardDirectoryDelete(AppMan.Manifest.State.DownloadDestination);
- AppMan.Manifest.State.UpdateFailureCount = UpdateRetryAttempts;
- AppMan.Manifest.Update();
- throw;
- }
- Keys.UnInitializeKeyCheck();
- }
- }
- private void ValidateDirectory(string source)
- {
- try
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(source);
- FileInfo[] files = directoryInfo.GetFiles();
- FileInfo[] array = files;
- foreach (FileInfo fileInfo in array)
- {
- if (!Keys.ValidateAssembly(fileInfo.FullName))
- {
- throw new Exception("Invalid assembly: " + fileInfo.FullName);
- }
- }
- DirectoryInfo[] directories = directoryInfo.GetDirectories();
- DirectoryInfo[] array2 = directories;
- foreach (DirectoryInfo directoryInfo2 in array2)
- {
- ValidateDirectory(Path.Combine(source, directoryInfo2.Name));
- }
- }
- catch (Exception ex)
- {
- UpdateEventArgs.ErrorMessage = ex.Message;
- throw;
- }
- }
- private void Scavenge()
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(GetParentFolder(AppDomain.CurrentDomain.BaseDirectory));
- DirectoryInfo[] directories = directoryInfo.GetDirectories();
- DirectoryInfo[] array = directories;
- foreach (DirectoryInfo directoryInfo2 in array)
- {
- if (MakeValidPath(directoryInfo2.FullName).ToLower(new CultureInfo("en-US")) != AppDomain.CurrentDomain.BaseDirectory.ToLower(new CultureInfo("en-US")) && MakeValidPath(directoryInfo2.FullName).ToLower(new CultureInfo("en-US")) != Config.AppPath.ToLower(new CultureInfo("en-US")) && directoryInfo2.Name.ToLower(new CultureInfo("en-US")) != "bin")
- {
- try
- {
- HardDirectoryDelete(MakeValidPath(directoryInfo2.FullName));
- }
- catch (Exception)
- {
- }
- }
- }
- }
- private void MergeDirectory(string source, string destination)
- {
- try
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(source);
- if (!Directory.Exists(destination))
- {
- Directory.CreateDirectory(destination);
- DirectoryInfo directoryInfo2 = new DirectoryInfo(destination);
- directoryInfo2.Attributes = directoryInfo.Attributes;
- }
- FileInfo[] files = directoryInfo.GetFiles();
- FileInfo[] array = files;
- foreach (FileInfo fileInfo in array)
- {
- if (!File.Exists(Path.Combine(destination, fileInfo.Name)) && !isManifestFile(fileInfo.Name))
- {
- fileInfo.CopyTo(Path.Combine(destination, fileInfo.Name), overwrite: true);
- }
- }
- DirectoryInfo[] directories = directoryInfo.GetDirectories();
- DirectoryInfo[] array2 = directories;
- foreach (DirectoryInfo directoryInfo3 in array2)
- {
- MergeDirectory(Path.Combine(source, directoryInfo3.Name), Path.Combine(destination, directoryInfo3.Name));
- }
- }
- catch (Exception ex)
- {
- UpdateEventArgs.ErrorMessage = "Copy of user files from the current app directory '" + source + "' to the new app directory'" + destination + "' failed with the following error: " + ex.Message;
- throw;
- }
- }
- private void FinalizeUpdate()
- {
- try
- {
- if (AppMan.Manifest.State.NewVersionDirectory == "")
- {
- AppMan.Manifest.State.NewVersionDirectory = CreateNewVersionDirectory();
- AppMan.Manifest.Update();
- }
- }
- catch (Exception)
- {
- UpdateEventArgs.ErrorMessage = "Failed to create the New Version Directory, using temp download directory as final destination.";
- AppMan.Manifest.State.NewVersionDirectory = AppMan.Manifest.State.DownloadDestination;
- AppMan.Manifest.Update();
- }
- try
- {
- if (AppMan.Manifest.State.NewVersionDirectory.ToLower(new CultureInfo("en-US")) != AppMan.Manifest.State.DownloadDestination.ToLower(new CultureInfo("en-US")))
- {
- CopyDirectory(AppMan.Manifest.State.DownloadDestination, AppMan.Manifest.State.NewVersionDirectory);
- }
- }
- catch (Exception ex2)
- {
- UpdateEventArgs.ErrorMessage = "Failed to copy the downloaded update at: '" + AppMan.Manifest.State.DownloadDestination + "' to the new version directory at: '" + AppMan.Manifest.State.NewVersionDirectory + "'";
- throw ex2;
- }
- try
- {
- char[] trimChars = new char[1]
- {
- '\\'
- };
- Config.AppFolderName = Path.GetFileName(AppMan.Manifest.State.NewVersionDirectory.TrimEnd(trimChars));
- Config.Udpate();
- }
- catch (Exception ex3)
- {
- UpdateEventArgs.ErrorMessage = "Failed to write to 'AppStart.config'";
- throw ex3;
- }
- try
- {
- if (AppMan.Manifest.State.NewVersionDirectory.ToLower(new CultureInfo("en-US")) != AppMan.Manifest.State.DownloadDestination.ToLower(new CultureInfo("en-US")))
- {
- HardDirectoryDelete(AppMan.Manifest.State.DownloadDestination);
- }
- }
- catch (Exception)
- {
- }
- }
- private string CreateTempDirectory()
- {
- int num = 0;
- Random random = new Random();
- string str = "";
- string parentFolder = GetParentFolder(AppDomain.CurrentDomain.BaseDirectory);
- string text;
- do
- {
- text = parentFolder + "AppUpdate" + str + "\\";
- str = "_" + random.Next(10000).ToString();
- num++;
- }
- while (num <= 50 && Directory.Exists(text));
- if (num >= 50)
- {
- UpdateEventArgs.ErrorMessage = "Failed to created temporary download directory in: '" + parentFolder + "'";
- throw new Exception("Failed to create temporary download Directory after 1000 attempts");
- }
- try
- {
- Directory.CreateDirectory(text);
- return text;
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- private string CreateNewVersionDirectory()
- {
- string downloadDestination = AppMan.Manifest.State.DownloadDestination;
- downloadDestination += Config.AppExeName;
- string fileVersion = GetFileVersion(downloadDestination);
- string parentFolder = GetParentFolder(AppMan.Manifest.State.DownloadDestination);
- string text = "";
- int num = 1;
- bool flag = false;
- string str = "";
- do
- {
- text = parentFolder + fileVersion + str + "\\";
- str = "_" + num.ToString();
- num++;
- try
- {
- if (!Directory.Exists(text))
- {
- Directory.CreateDirectory(text);
- flag = true;
- }
- }
- catch (Exception)
- {
- flag = false;
- }
- }
- while (num <= 999 && !flag);
- if (num >= 999)
- {
- text = AppMan.Manifest.State.DownloadDestination;
- }
- return text;
- }
- private string MakeValidPath(string source)
- {
- if (source.EndsWith("\\"))
- {
- return source;
- }
- return source + "\\";
- }
- private void CopyDirectory(string source, string destination)
- {
- try
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(source);
- if (!Directory.Exists(destination))
- {
- Directory.CreateDirectory(destination);
- DirectoryInfo directoryInfo2 = new DirectoryInfo(destination);
- directoryInfo2.Attributes = directoryInfo.Attributes;
- }
- FileInfo[] files = directoryInfo.GetFiles();
- FileInfo[] array = files;
- foreach (FileInfo fileInfo in array)
- {
- if (!File.Exists(Path.Combine(destination, fileInfo.Name)))
- {
- fileInfo.CopyTo(Path.Combine(destination, fileInfo.Name), overwrite: true);
- }
- }
- DirectoryInfo[] directories = directoryInfo.GetDirectories();
- DirectoryInfo[] array2 = directories;
- foreach (DirectoryInfo directoryInfo3 in array2)
- {
- CopyDirectory(Path.Combine(source, directoryInfo3.Name), Path.Combine(destination, directoryInfo3.Name));
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- private void HardDirectoryDelete(string source)
- {
- string directoryName = Path.GetDirectoryName(source);
- string text = Path.GetDirectoryName(directoryName) + "\\" + Config.SetupVersion + "\\";
- StreamWriter streamWriter = new StreamWriter("TestFile.txt", append: true);
- streamWriter.WriteLine("ParentPath: " + text + "\r\n");
- streamWriter.Close();
- if (!(source == text))
- {
- try
- {
- if (Directory.Exists(source))
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(source);
- directoryInfo.Attributes = FileAttributes.Normal;
- FileInfo[] files = directoryInfo.GetFiles();
- FileInfo[] array = files;
- foreach (FileInfo fileInfo in array)
- {
- fileInfo.Attributes = FileAttributes.Normal;
- }
- DirectoryInfo[] directories = directoryInfo.GetDirectories();
- DirectoryInfo[] array2 = directories;
- foreach (DirectoryInfo directoryInfo2 in array2)
- {
- HardDirectoryDelete(Path.Combine(source, directoryInfo2.Name));
- }
- directoryInfo.Delete(recursive: true);
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- }
- private string GetFileVersion(string filePath)
- {
- AssemblyName assemblyName = AssemblyName.GetAssemblyName(filePath);
- return assemblyName.Version.ToString();
- }
- private string GetParentFolder(string filePath)
- {
- DirectoryInfo directoryInfo = new DirectoryInfo(filePath.Trim('\\'));
- return directoryInfo.Parent.FullName + "\\";
- }
- private bool isManifestFile(string name)
- {
- string fileName = Path.GetFileName(AppMan.Manifest.FilePath);
- if (fileName.ToLower(new CultureInfo("en-US")) == name.ToLower(new CultureInfo("en-US")))
- {
- return true;
- }
- return false;
- }
- }
- }
|