using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Security.Cryptography; using System.Threading; using System.Xml; using Eto.Forms; using UpToolEto.Forms; using UpToolLib; using UpToolLib.DataStructures; using UpToolLib.v1; using UpToolLib.v1.Tool; using UpToolLib.v2; namespace UpToolEto { public class Main { private readonly IExternalFunctionality _platform; private readonly Application _application; private readonly Action _activityExistsException; private readonly InitScreen _init; private readonly bool _skipFetch; public static bool DebugColors { get; private set; } public Main(Application application, Action activityExistsException, string[] args) { _skipFetch = args.Contains("--skip-fetch"); DebugColors = args.Contains("--debug-colors"); _platform = new UTLibFunctions(application); _application = application; _activityExistsException = activityExistsException; _init = new(application, _platform); } public void Entry() { new Thread(InitThread).Start(); _application.Run(_init); } private void InitThread() { UpToolLibMain lib = null; try { lib = new UpToolLibMain(_platform); _init.SetText("Initializing paths"); if (!Directory.Exists(lib.V1.PathTool.Dir)) Directory.CreateDirectory(lib.V1.PathTool.Dir); FixXml(lib.V1.XmlTool, lib.V1.PathTool); _init.SetText("Performing checks"); bool online = false; UpdateCheck updateCheck = null; try { updateCheck = lib.V2.UpdateChecker.Check(); online = true; } catch { _platform.Log("Could not perform update check, starting offline"); } if (online && UpdateCheck(updateCheck, lib.V1.PathTool, _init)) _platform.Log("Quitting"); else { if (!Directory.Exists(lib.V1.PathTool.GetRelative("Apps"))) Directory.CreateDirectory(lib.V1.PathTool.GetRelative("Apps")); if (!_skipFetch && online) { _init.SetText("Fetching repos"); lib.V2.RepoManagement.FetchRepos(); } lib.V2.RepoManagement.GetReposFromDisk(); _init.SetText("Opening"); _application.Invoke(() => _application.Run(new MainForm(_init, lib, _platform, online))); } } catch (MutexLockLockedException) { _application.Invoke(() => { _init.Close(); _platform.OkDialog("Mutex property of other process, quitting"); _activityExistsException(); }); } catch (Exception e) { lib?.Dispose(); _platform.Log(e.ToString()); } finally { lib?.Dispose(); _application.Invoke(() => _application.Quit()); } } public void FixXml(XmlTool xmlTool, PathTool pathTool, bool throwOnError = false) { try { xmlTool.FixXml(); } catch (XmlException) { if (throwOnError) throw; _platform.OkDialog("Something went wrong while trying to parse XML. Retrying..."); File.Delete(pathTool.InfoXml); FixXml(xmlTool, pathTool); } } private bool UpdateCheck(UpdateCheck updateCheck, PathTool pathTool, InitScreen init) { init.SetText("Comparing online version"); if (Assembly.GetExecutingAssembly().GetName().Version >= updateCheck.OnlineVersion) return false; if (PlatformCheck.IsWindows) { init.SetText("Downloading latest"); (bool success, byte[] dl) = _platform.Download(updateCheck.Installer); if (!success) throw new Exception("Failed to update"); init.SetText("Verifying"); using (SHA256CryptoServiceProvider sha256 = new()) { string pkgHash = BitConverter.ToString(sha256.ComputeHash(dl)).Replace("-", string.Empty).ToUpper(); if (pkgHash != updateCheck.InstallerHash) throw new Exception( $"The hash is not equal to the one stored in the repo:\r\nPackage: {pkgHash}\r\nOnline: {updateCheck.InstallerHash}"); } init.SetText("Installing"); if (Directory.Exists(pathTool.GetRelative("Install", "tmp"))) Directory.Delete(pathTool.GetRelative("Install", "tmp"), true); Directory.CreateDirectory(pathTool.GetRelative("Install", "tmp")); using (MemoryStream ms = new(dl)) { using ZipArchive ar = new(ms); ar.ExtractToDirectory(pathTool.GetRelative("Install", "tmp"), true); } init.Close(); Process.Start(new ProcessStartInfo { FileName = pathTool.GetRelative("Install", "tmp", "Installer.exe"), Arguments = "i -p", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, WorkingDirectory = pathTool.GetRelative("Install") }); return true; } else { _platform.OkDialog("A new version is available. Please install it"); return false; } } } }