using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace CarManagerV3.Manager { internal class Updater { private static readonly string GitApiUrl = "https://git.jaro.digital/api/v1"; private static readonly string GitRepoOwner = "frozd"; private static readonly string GitRepoName = "carmanager-3"; private static readonly string GitApiRepoUrl = $"{GitApiUrl}/repos/{GitRepoOwner}/{GitRepoName}"; private static readonly string LatestReleaseEndpoint = $"{GitApiRepoUrl}/releases/latest"; private static readonly string PreReleaseEndpoint = $"{GitApiRepoUrl}/releases?limit=1&pre-release=true"; private static string latestVersionCache = null; private static DateTime lastChecked = DateTime.MinValue; private static readonly int CacheDurationMinutes = 60; private static bool cacheIncludesPrerelease = false; private static readonly string debugVersion = null;//"1.2.0"; public static string GetCurrentVersion() { //DEBUG:: if(debugVersion != null) { return debugVersion; } var asm = Assembly.GetEntryAssembly()!; Version v = asm.GetName().Version ?? new Version(0, 0, 0, 0); return v.ToString(); } private static bool IsCacheValid(bool includePreRelease = false) { return includePreRelease == cacheIncludesPrerelease && latestVersionCache != null && (DateTime.Now - lastChecked).TotalMinutes < CacheDurationMinutes; } private static void InvalidateCache() { latestVersionCache = null; lastChecked = DateTime.MinValue; } private static void SetCache(string version, bool includePreRelease = false) { latestVersionCache = version; cacheIncludesPrerelease = includePreRelease; lastChecked = DateTime.Now; } public static string GetLatestVersion(bool includePreRelease = false) { if (IsCacheValid(includePreRelease)) { System.Diagnostics.Debug.WriteLine("Using cached latest version: " + latestVersionCache); return latestVersionCache; } string latestVersion = null; // Get the latest stable version first using (var client = new System.Net.Http.HttpClient()) { var response = client.GetAsync(LatestReleaseEndpoint).Result; if (response.IsSuccessStatusCode) { var content = response.Content.ReadAsStringAsync().Result; dynamic release = Newtonsoft.Json.JsonConvert.DeserializeObject(content); latestVersion = release.tag_name; } } // If pre-release is requested, check for the latest pre-release version if (includePreRelease) { using (var client = new System.Net.Http.HttpClient()) { var response = client.GetAsync(PreReleaseEndpoint).Result; if (response.IsSuccessStatusCode) { var content = response.Content.ReadAsStringAsync().Result; dynamic releases = Newtonsoft.Json.JsonConvert.DeserializeObject(content); if (releases.Count > 0) { var preReleaseVersion = releases[0].tag_name; // Compare versions and return the newer one if (IsNewerVersion(preReleaseVersion, latestVersion)) { latestVersion = preReleaseVersion; } } } } } SetCache(latestVersion, includePreRelease); return latestVersion; } public static bool IsNewerVersion(string versionA, string versionB) { if (versionA == null) return false; if (versionB == null) return true; Version vA = new Version(versionA.TrimStart('v')); Version vB = new Version(versionB.TrimStart('v')); return vA > vB; } public static void DownloadNewestInstaller(bool includePreRelease = false) { string latestVersion = GetLatestVersion(includePreRelease); if (latestVersion == null) { throw new Exception("Could not fetch latest version from Git API."); } string releaseUrl = $"{GitApiRepoUrl}/releases/tags/{latestVersion}"; using (var client = new System.Net.Http.HttpClient()) { var response = client.GetAsync(releaseUrl).Result; if (response.IsSuccessStatusCode) { var content = response.Content.ReadAsStringAsync().Result; dynamic release = Newtonsoft.Json.JsonConvert.DeserializeObject(content); string downloadUrl = null; foreach (var asset in release.assets) { // file that ends with .msi if (asset.name.ToString().EndsWith(".msi")) { downloadUrl = asset.browser_download_url; break; } } if (downloadUrl != null) { // Download the installer to the users set Data dir, run it, and then exit the application. string tempFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"CarManagerInstaller_{latestVersion}.msi"); using (var downloadClient = new System.Net.WebClient()) { downloadClient.DownloadFile(downloadUrl, tempFilePath); } // Use ProcessStartInfo with UseShellExecute to launch the MSI file var processStartInfo = new System.Diagnostics.ProcessStartInfo { FileName = tempFilePath, UseShellExecute = true }; System.Diagnostics.Process.Start(processStartInfo); Application.Exit(); } else { throw new Exception("Could not find installer asset in the latest release."); } } else { throw new Exception("Could not fetch release information from Git API."); } } } public static bool IsUpdateAvailable(bool includePreRelease = false) { string currentVersion = GetCurrentVersion(); string latestVersion = GetLatestVersion(includePreRelease); return IsNewerVersion(latestVersion, currentVersion); } public static void openReleasePage(string version = null) { if(version == null) { version = GetLatestVersion(true); } string releaseUrl = $"https://git.jaro.digital/{GitRepoOwner}/{GitRepoName}/releases/tag/{version}"; System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = releaseUrl, UseShellExecute = true }); } } }