using Newtonsoft.Json; using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection; using System.Text; namespace eSuite.WorkBench.Services { public static class StringExtensions { public static bool IsHigherVersion(this string currentValue, string potentialHigherValue) { var currentVersionSplit = currentValue.Split("."); var potentialHigherValueSplit = potentialHigherValue.Split("."); //Only checking the first three parts, as the revision is ignored by the MSI installer. for( var i = 0; i < 3; i++) { if (int.Parse(currentVersionSplit[i]) < int.Parse(potentialHigherValueSplit[i])) return true; } return false; } } public interface IUpdateChecker { string GetCurrentVersion(); void CheckForUpdates(string devopsPersonalAccessKey); } public class UpdateChecker : IUpdateChecker { private readonly string _baseUrl = "https://dev.azure.com/sunbranding/f0f62be4-80fd-4c1c-93b6-d019ae74c8cd/_apis"; public string GetCurrentVersion() { var productAssembly = Assembly.GetEntryAssembly(); var thisAssemblyName = productAssembly.GetName(); var assemblyVersion = thisAssemblyName.Version.ToString(); return assemblyVersion; } public void CheckForUpdates(string devopsPersonalAccessKey) { if (!string.IsNullOrWhiteSpace(devopsPersonalAccessKey)) { var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"esuite:{devopsPersonalAccessKey}")); var message = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"{_baseUrl}/pipelines/88/runs?api-version=7.0"), Headers = { {HttpRequestHeader.Authorization.ToString(), $"Basic {authValue}" } } }; try { var client = new HttpClient(); var response = client.Send(message).EnsureSuccessStatusCode(); var responseContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); var buildPipelineResults = JsonConvert.DeserializeObject(responseContent); var mostRecentBuild = buildPipelineResults.Value.Where(x => x.Result == "succeeded" && x.State == "completed").MaxBy(x=> x.Id); var mostRecentBuildVersion = ExtractVersion(mostRecentBuild.Name); var currentRunningVersion = GetCurrentVersion(); if (currentRunningVersion.IsHigherVersion(mostRecentBuildVersion)) { DownloadAndUpgrade(authValue, mostRecentBuild.Id); } } catch (Exception) { //If the above check fails for any reason, I don't want to raise an exception, just fail silently, the update check will be skipped. } } } private void DownloadAndUpgrade(string authValue, long buildId) { //Download the Zip file var message = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"{_baseUrl}/build/builds/{buildId}/artifacts?artifactName=installer&api-version=4.1&%24format=zip"), Headers = { {HttpRequestHeader.Authorization.ToString(), $"Basic {authValue}" } } }; var client = new HttpClient(); var response = client.Send(message).EnsureSuccessStatusCode(); //Uncompress the Zip file using var readStream = response.Content.ReadAsStream(); using var archive = new ZipArchive(readStream); const string installerFilename = "eSuite.WorkBench.Installer.msi"; var installerArchiveEntry = archive.Entries.Single(x => x.Name == installerFilename); using var unzippedMsi = installerArchiveEntry.Open(); var filePath = Path.Combine(Path.GetTempPath(), installerFilename); //Delete old installer if found. if (File.Exists(filePath)) File.Delete(filePath); //Save the installer MSI using Stream fs = File.Create(filePath); unzippedMsi.CopyTo(fs); fs.Flush(); fs.Close(); //Launch the msi Process process = new Process(); // Configure the process using the StartInfo properties. process.StartInfo.FileName = filePath; process.StartInfo.UseShellExecute = true; process.Start(); //shutdown var currentProcess = Process.GetCurrentProcess(); currentProcess.Kill(); } private string ExtractVersion(string name) { return name.Substring(2, name.IndexOf("-") - 2); } } }