From a8583c95d082d36f6d0665d0b25c2fc6c4b5e943 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 7 Apr 2017 18:33:36 -0400 Subject: Update Manager Use the "ShiftOS.Updater" as your startup project for this to work correctly. --- ShiftOS.WinForms/Applications/UpdateManager.cs | 279 +++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 ShiftOS.WinForms/Applications/UpdateManager.cs (limited to 'ShiftOS.WinForms/Applications/UpdateManager.cs') diff --git a/ShiftOS.WinForms/Applications/UpdateManager.cs b/ShiftOS.WinForms/Applications/UpdateManager.cs new file mode 100644 index 0000000..05ae9d0 --- /dev/null +++ b/ShiftOS.WinForms/Applications/UpdateManager.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using ShiftOS.Engine; +using ShiftOS.WinForms.Tools; +using static ShiftOS.Engine.SkinEngine; +using System.Net; +using Newtonsoft.Json; +using System.Reflection; +using System.IO; +using System.IO.Compression; + +namespace ShiftOS.WinForms.Applications +{ + [Launcher("Update Manager", true, "al_update_manager", "Networking")] + [DefaultTitle("Update Manager")] + [WinOpen("update_manager")] + public partial class UpdateManager : UserControl, IShiftOSWindow + { + public UpdateManager() + { + InitializeComponent(); + btnaction.Click += (o, a) => OnActionButtonClick?.Invoke(); + } + + public void OnLoad() + { + CheckForUpdate(); + } + + public void CheckForUpdate() + { + ConstructHtml(@"ShiftOS is grabbing information on the latest version. Please be patient."); + pgdownload.Show(); + btnaction.Show(); + lbupdatetitle.Text = "Checking for updates..."; + pgdownload.Value = 0; + pgdownload.Maximum = 100; + + var wc = new WebClient(); + + wc.DownloadProgressChanged += (o, a) => + { + this.Invoke(new Action(() => + { + pgdownload.Text = "Grabbing update data from multi-user-domain..."; + pgdownload.Value = a.ProgressPercentage; + })); + }; + + wc.DownloadStringCompleted += (o, a) => + { + var releases = JsonConvert.DeserializeObject(a.Result); + + var download = releases.OrderByDescending(x => x.PostDate).First(); + + var thisBuildDate = Assembly.GetExecutingAssembly().GetBuildDate(TimeZoneInfo.Utc); + + if(download.PostDate > thisBuildDate) + { + this.Invoke(new Action(() => + { + //This build is more recent than the currently running ShiftOS client. + SetupBuildUpdate(download); + })); + } + else + { + if (thisBuildDate > download.PostDate) + { + this.Invoke(new Action(() => ConstructHtml($@"### Unreleased build. + +You are currently running an unreleased build of ShiftOS, compiled on {thisBuildDate}, after the latest released version, {download.Name}, compiled on {download.PostDate}."))); + } + else + { + this.Invoke(new Action(() => ConstructHtml($@"### Up to date. + +You are currently running {download.Name}, compiled on {download.PostDate}."))); + + } + this.Invoke(new Action(() => + { + lbupdatetitle.Text = "No update available"; + pgdownload.Hide(); + btnaction.Hide(); + })); + } + }; + + wc.DownloadStringAsync(new Uri("http://getshiftos.ml/API/Releases?showUnstable=true&showObsolete=false")); + } + + public void OnSkinLoad() + { + ConstructHtml(CurrentMD); + } + + public bool OnUnload() + { + return true; + } + + public void OnUpgrade() + { + ConstructHtml(CurrentMD); + } + + public void SetupBuildUpdate(ShiftOS.Objects.Unite.Download download) + { + string devUpdate = ""; + if (!string.IsNullOrEmpty(download.DevUpdateId)) + { + devUpdate = $@"## Development update + + +"; + } + + string screenshot = ""; + + if(!string.IsNullOrEmpty(download.ScreenshotUrl)) + { + screenshot = $""; + } + + lbupdatetitle.Text = download.Name; + string markdown = $@"**Built on {download.PostDate}** + +{devUpdate} + +{screenshot} + +## Changelog + +{download.Changelog}"; + + ConstructHtml(markdown); + + pgdownload.Value = 0; + pgdownload.Text = "Waiting."; + btnaction.Text = "Update"; + btnaction.Show(); + OnActionButtonClick = () => + { + pgdownload.Show(); + var wc = new WebClient(); + wc.DownloadProgressChanged += (o, a) => + { + this.Invoke(new Action(() => + { + pgdownload.Text = "Downloading " + download.Name + "..."; + pgdownload.Value = a.ProgressPercentage; + })); + }; + + wc.DownloadDataCompleted += (o, a) => + { + if (Directory.Exists("updater-work")) + Directory.Delete("updater-work", true); + Directory.CreateDirectory("updater-work"); + + string temp_guid = Guid.NewGuid().ToString(); + + File.WriteAllBytes($"{temp_guid}.zip", a.Result); + + ZipFile.ExtractToDirectory($"{temp_guid}.zip", "updater-work"); + + File.Delete($"{temp_guid}.zip"); + + //Start the updater helper. + System.Diagnostics.Process.Start("ShiftOS.Updater.exe"); + + //Now we stop the engine. + TerminalBackend.InvokeCommand("sos.shutdown"); + + }; + + wc.DownloadDataAsync(new Uri($"http://getshiftos.ml{download.DownloadUrl}")); + }; + } + + public Action OnActionButtonClick = () => { }; + + public void ConstructHtml(string markdown) + { + CurrentMD = markdown; + var TerminalForeColor = ControlManager.ConvertColor(SkinEngine.LoadedSkin.TerminalForeColorCC); + var TerminalBackColor = ControlManager.ConvertColor(SkinEngine.LoadedSkin.TerminalBackColorCC); + string html = $@" + + + + + + +"; + + string body = CommonMark.CommonMarkConverter.Convert(markdown); + + html = html.Replace("", body); + wbstatus.DocumentText = html; + } + + public string CurrentMD = ""; + + private void btnclose_Click(object sender, EventArgs e) + { + AppearanceManager.Close(this); + } + } + + public static class UpdateHelpers + { + /// + /// Grabs the build date from the assembly's PE header. + /// + /// The assembly to probe. + /// The target timezone. + /// The assembly's build date. + public static DateTime GetBuildDate(this Assembly assembly, TimeZoneInfo target = null) + { + var filePath = assembly.Location; + const int c_PeHeaderOffset = 60; + const int c_LinkerTimestampOffset = 8; + + var buffer = new byte[2048]; + + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + stream.Read(buffer, 0, 2048); + + var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset); + var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset); + var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + var linkTimeUtc = epoch.AddSeconds(secondsSince1970); + + var tz = target ?? TimeZoneInfo.Local; + var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz); + + return localTime; + } + } +} -- cgit v1.2.3