21 using System.Text.RegularExpressions;
41 public class Updater : Mvvm.Models.ProcessModel, IDisposable
43 #region Public properties 45 public UpdaterStatus Status {
get;
protected set; }
47 public Exception Exception {
get;
protected set; }
51 public string DestinationFolder {
get;
set; }
55 public int PercentDownloaded {
get;
protected set; }
57 public long DownloadBytesTotal {
get;
protected set; }
59 public long DownloadBytesReceived {
get;
protected set; }
63 #region Public methods 68 if (Status == UpdaterStatus.Downloaded)
72 if (CheckAuthorization())
74 string command = GetInstallerCommand();
75 string arguments = GetInstallerParameters();
78 Logger.Info(
"Install: {0} {1}", command, arguments);
79 var process =
System.Diagnostics.Process.Start(command, arguments);
80 Logger.Info(
"Install: Process: {0}", process);
81 Status = UpdaterStatus.InstallationStarted;
86 Logger.Fatal(
"Install: Could not start process");
88 Status = UpdaterStatus.InstallationFailed;
94 Logger.Warn(
"Install: Not authorized to install!");
95 Status = UpdaterStatus.NotAuthorizedToInstall;
100 Logger.Warn(
"Install: Verification failed");
101 Status = UpdaterStatus.VerificationFailed;
106 Logger.Warn(
"Install: No update available!");
132 public void Dispose()
135 GC.SuppressFinalize(
this);
138 protected void Dispose(
bool disposing)
146 if (_webClient != null)
148 _webClient.Dispose();
156 #region Implementation of ProcessModel 162 throw new InvalidOperationException(
"Cannot download release because ReleaseInfo is null");
164 if (
ReleaseInfo.Status != ReleaseInfoStatus.InfoAvailable)
166 throw new InvalidOperationException(
"Cannot download release because no release info is available");
169 _destinationFileName = GetDestinationFileName();
171 if (!(File.Exists(_destinationFileName) && Verify()))
173 Logger.Info(
"Execute: Starting download");
175 _webClient =
new WebClient();
176 _webClient.DownloadFileCompleted += WebClient_DownloadFileCompleted;
177 _webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
178 var lockObject =
new Object();
181 _webClient.DownloadFileAsync(
ReleaseInfo.DownloadUri, _destinationFileName, lockObject);
182 Monitor.Wait(lockObject);
185 Logger.Info(
"Execute: exiting");
189 Logger.Info(
"Execute: Skipping download because destination file exists and is verified");
190 Status = UpdaterStatus.Downloaded;
197 #region Protected helper methods 212 string downloadUri =
ReleaseInfo.DownloadUri.ToString();
213 Logger.Info(
"GetDestinationFileName: Examining {0}", downloadUri);
215 Regex r =
new Regex(
@"(?<fn>[^/]+?\.exe)");
216 Match m = r.Match(downloadUri);
219 fn = m.Groups[
"fn"].Value;
223 Logger.Warn(
"GetDestinationFileName: Did not find file name pattern in download URI!");
226 Logger.Warn(
"GetDestinationFileName: {0}", fn);
227 if (String.IsNullOrEmpty(DestinationFolder))
229 Logger.Warn(
"GetDestinationFileName: No destination folder!");
234 return Path.Combine(DestinationFolder, fn);
244 return _destinationFileName;
253 return "/UPDATE /SP- /SILENT /SUPPRESSMSGBOXES";
263 string installFolder = AppDomain.CurrentDomain.BaseDirectory;
267 Logger.Info(
"CheckAuthorization: Attempting write to assembly's folder");
268 Logger.Info(
"CheckAuthorization: {0}", installFolder);
269 string fn = Path.Combine(installFolder,
"bovender-framework-check-auth.txt");
270 using (FileStream f =
new FileStream(fn, FileMode.Create, FileAccess.Write))
275 Logger.Warn(
"CheckAuthorization: Successfully created and deleted test file");
280 Logger.Warn(
"CheckAuthorization: Evidently not authorized");
294 bool verified =
false;
295 Logger.Info(
"Verify: Expected: {0}",
ReleaseInfo.ExpectedHash);
305 Logger.Info(
"Verify: Actual: {0}", actual);
309 Logger.Info(
"Verify: OK");
313 Logger.Warn(
"Verify: Checksum mismacth!");
322 protected override void OnCancelling()
325 if (_webClient != null && _webClient.IsBusy)
327 _webClient.CancelAsync();
333 #region Private event handlers 335 private void WebClient_DownloadProgressChanged(
object sender, DownloadProgressChangedEventArgs args)
337 PercentDownloaded = args.ProgressPercentage;
338 DownloadBytesReceived = args.BytesReceived;
339 DownloadBytesTotal = args.TotalBytesToReceive;
342 private void WebClient_DownloadFileCompleted(
object sender,
System.ComponentModel.AsyncCompletedEventArgs args)
344 lock (args.UserState)
346 Monitor.Pulse(args.UserState);
350 Logger.Info(
"WebClient_DownloadFileCompleted: Cancelled");
353 System.IO.File.Delete(_destinationFileName);
354 Logger.Info(
"WebClient_DownloadFileCompleted: Deleted partially downloaded file");
358 Logger.Warn(
"WebClient_DownloadFileCompleted: Could not remove partially downloaded file");
361 Status = UpdaterStatus.DownloadCancelled;
365 if (args.Error == null)
367 Logger.Info(
"WebClient_DownloadFileCompleted: Downloaded");
368 Status = UpdaterStatus.Downloaded;
372 Logger.Warn(
"WebClient_DownloadFileCompleted: Error!");
373 Logger.Warn(args.Error);
374 Status = UpdaterStatus.DownloadFailed;
375 Exception = args.Error;
382 #region Private fields 384 private bool _disposed;
385 private WebClient _webClient;
386 private string _destinationFileName;
392 private static NLog.Logger Logger {
get {
return _logger.Value; } }
394 private static readonly Lazy<
NLog.Logger> _logger =
new Lazy<
NLog.Logger>(() =>
NLog.LogManager.GetCurrentClassLogger());
override bool Execute()
This method may be called by a ProcessViewModelBase-derived class in a worker task that wraps this me...
virtual bool CheckAuthorization()
Determines whether the current user is authorized to write to the folder where the addin files are st...
static string Sha1Hash(string file)
Computes the Sha1 hash of a given file.
Interface for classes that fetch current release information.
virtual string GetInstallerCommand()
Returns the command to execute in the shell to install the update.
virtual string GetDestinationFileName()
Builds the destination file name from the download URI and the destination folder (which is stored in...
virtual bool Verify()
Compares the actual and expected checksum hashes and sets the IsVerifiedDownload property accordingly...
virtual string GetInstallerParameters()
Returns commandline parameters for the update installer.
static string Sha256Hash(string file)
Computes the Sha256 hash of a given file.
Class that handles semantic versioning.
Fetches version information from the internet and raises an UpdateAvailable event if a new version is...
Fetches and digests release information.
override string ToString()
Returns the full version string.