From 7b1441fa6ce6bace32d6fe6bc84fafc430388756 Mon Sep 17 00:00:00 2001 From: MistEO Date: Mon, 27 Sep 2021 00:11:41 +0800 Subject: [PATCH] =?UTF-8?q?feat.=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAsstGui/App.xaml.cs | 25 +- src/MeoAsstGui/ViewModels/RootViewModel.cs | 32 ++- .../ViewModels/VersionUpdateViewModel.cs | 252 +++++++++++++++--- src/MeoAsstGui/Views/VersionUpdateView.xaml | 6 +- src/MeoAsstGui/packages.config | 1 + 5 files changed, 261 insertions(+), 55 deletions(-) diff --git a/src/MeoAsstGui/App.xaml.cs b/src/MeoAsstGui/App.xaml.cs index 28be7624b6..b5845b6ca7 100644 --- a/src/MeoAsstGui/App.xaml.cs +++ b/src/MeoAsstGui/App.xaml.cs @@ -1,4 +1,7 @@ -using System.Windows; +using Microsoft.Toolkit.Uwp.Notifications; +using System.Windows; +using Windows.ApplicationModel.Activation; +using Windows.UI.Notifications; namespace MeoAsstGui { @@ -7,5 +10,25 @@ namespace MeoAsstGui /// public partial class App : Application { + //protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args) + //{ + // var deferral = args.TaskInstance.GetDeferral(); + + // switch (args.TaskInstance.Task.Name) + // { + // case "ToastBackgroundTask": + // var details = args.TaskInstance.TriggerDetails as ToastNotificationActionTriggerDetail; + // if (details != null) + // { + // ToastArguments arguments = ToastArguments.Parse(details.Argument); + // var userInput = details.UserInput; + + // // Perform tasks + // } + // break; + // } + + // deferral.Complete(); + //} } } \ No newline at end of file diff --git a/src/MeoAsstGui/ViewModels/RootViewModel.cs b/src/MeoAsstGui/ViewModels/RootViewModel.cs index b6683caddb..84df7b6627 100644 --- a/src/MeoAsstGui/ViewModels/RootViewModel.cs +++ b/src/MeoAsstGui/ViewModels/RootViewModel.cs @@ -17,9 +17,10 @@ namespace MeoAsstGui protected override void OnViewLoaded() { + CheckAndUpdateNow(); InitProxy(); - CheckUpdate(); InitViewModels(); + ShowUpdateOrDownload(); } private void InitProxy() @@ -37,20 +38,27 @@ namespace MeoAsstGui Items.Add(rvm); ActiveItem = mfvm; } - - private async void CheckUpdate() + private bool CheckAndUpdateNow() + { + var vuvm = _container.Get(); + return vuvm.CheckAndUpdateNow(); + } + private async void ShowUpdateOrDownload() { var vuvm = _container.Get(); - var task = Task.Run(() => - { - return vuvm.CheckUpdate(); - }); - - var needUpdate = await task; - if (needUpdate) - { - _windowManager.ShowWindow(vuvm); + if (vuvm.IsFirstBootAfterUpdate) + { + _windowManager.ShowWindow(vuvm); + } + else + { + var task = Task.Run(() => + { + return vuvm.CheckAndDownloadUpdate(); + }); + + await task; } } } diff --git a/src/MeoAsstGui/ViewModels/VersionUpdateViewModel.cs b/src/MeoAsstGui/ViewModels/VersionUpdateViewModel.cs index f2ae03d9aa..20c2eeb972 100644 --- a/src/MeoAsstGui/ViewModels/VersionUpdateViewModel.cs +++ b/src/MeoAsstGui/ViewModels/VersionUpdateViewModel.cs @@ -1,12 +1,15 @@ -using Newtonsoft.Json; +using Microsoft.Toolkit.Uwp.Notifications; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Stylet; using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.InteropServices; using System.Text; - +using System.Windows; + namespace MeoAsstGui { public class VersionUpdateViewModel : Screen @@ -23,7 +26,7 @@ namespace MeoAsstGui private string _curVersion = Marshal.PtrToStringAnsi(AsstGetVersion()); private string _latestVersion; - private string _updateTag; + private string _updateTag = ViewStatusStorage.Get("VersionUpdate.name", string.Empty); public string UpdateTag { get @@ -33,10 +36,11 @@ namespace MeoAsstGui set { SetAndNotify(ref _updateTag, value); + ViewStatusStorage.Set("VersionUpdate.name", value); } } - private string _updateInfo; + private string _updateInfo = ViewStatusStorage.Get("VersionUpdate.body", string.Empty); public string UpdateInfo { @@ -47,16 +51,176 @@ namespace MeoAsstGui set { SetAndNotify(ref _updateInfo, value); + ViewStatusStorage.Set("VersionUpdate.body", value); } - } - private string RequestApi() + } + + private bool _isFirstBootAfterUpdate = Convert.ToBoolean(ViewStatusStorage.Get("VersionUpdate.firstboot", Boolean.FalseString)); + public bool IsFirstBootAfterUpdate { - HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create( - "https://api.github.com/repos/MistEO/MeoAssistance/releases/latest"); + get + { + return _isFirstBootAfterUpdate; + } + set + { + SetAndNotify(ref _isFirstBootAfterUpdate, value); + ViewStatusStorage.Set("VersionUpdate.firstboot", value.ToString()); + } + } + + private const string _requestUrl = "https://api.github.com/repos/MistEO/MeoAssistance/releases/latest"; + private JObject _lastestJson; + private string _downloadUrl; + string _extractDir = Directory.GetCurrentDirectory() + "\\NewVersion"; + + // 检查是否有已下载的更新包,如果有立即更新并重启进程 + public bool CheckAndUpdateNow() + { + if (UpdateTag == string.Empty || !Directory.Exists(_extractDir)) + { + return false; + } + var uncopiedList = new List(); + // 复制新版本的所有文件到当前路径下 + foreach (var file in Directory.GetFiles(_extractDir)) + { + try + { + File.Copy(file, Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(file)), true); + } + catch (Exception) + { + uncopiedList.Add(file); + } + } + foreach (var directory in Directory.GetDirectories(_extractDir)) + { + CopyFilesRecursively(directory, Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(directory))); + } + + // 程序正在运行中,部分文件是无法覆写的,这里曲线操作下 + // 先将当前这些文件重命名,然后再把新的复制过来 + foreach (var oldfile in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.old")) + { + File.Delete(oldfile); + } + foreach (var file in uncopiedList) + { + string curFileName = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(file)); + File.Move(curFileName, curFileName + ".old"); + File.Copy(file, curFileName); + } + + // 操作完了,把更新包里的文件删了 + Directory.Delete(_extractDir, true); + // 保存更新信息,下次启动后会弹出已更新完成的提示 + IsFirstBootAfterUpdate = true; + ViewStatusStorage.Save(); + + // 重启进程(启动的是更新后的程序了) + System.Diagnostics.Process newProcess = new System.Diagnostics.Process(); + newProcess.StartInfo.FileName = System.AppDomain.CurrentDomain.FriendlyName; + newProcess.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory(); + newProcess.Start(); + Application.Current.Shutdown(); + + return true; + } + // 检查更新,并下载更新包 + public bool CheckAndDownloadUpdate() + { + // 检查更新 + if (!CheckUpdate()) + { + return false; + } + var openUrlToastButton = new ToastButton(); + openUrlToastButton.SetContent("前往页面查看"); + new ToastContentBuilder() + .AddText("检测到新版本:" + _lastestJson["name"].ToString() + ",正在后台下载……") + .AddText(_lastestJson["body"].ToString()) + .AddButton(openUrlToastButton) + .Show(); + // 下载压缩包 + const int downloadRetryMaxTimes = 20; + string downloadFilename = _downloadUrl.Substring(_downloadUrl.LastIndexOf('/') + 1); + string downloadTempFilename = downloadFilename + ".tmp"; + bool downloaded = false; + for (int i = 0; i != downloadRetryMaxTimes; ++i) + { + if (DownloadFile(_downloadUrl, downloadTempFilename)) + { + downloaded = true; + break; + } + } + if (!downloaded) + { + new ToastContentBuilder() + .AddText("新版本下载失败,请尝试手动下载_(:з」∠)_") + .AddButton(openUrlToastButton) + .Show(); + return false; + } + // 解压并删除压缩包 + File.Copy(downloadTempFilename, downloadFilename, true); + File.Delete(downloadTempFilename); + System.IO.Compression.ZipFile.ExtractToDirectory(downloadFilename, _extractDir); + File.Delete(downloadFilename); + // 把相关信息存下来,更新完之后启动的时候显示 + UpdateTag = "版本已自动更新:" + _lastestJson["name"].ToString(); + UpdateInfo = _lastestJson["body"].ToString(); + new ToastContentBuilder() + .AddText("新版本下载完成,将在下次启动辅助时自动更新!✿✿ヽ(°▽°)ノ✿") + .Show(); + return true; + } + + public bool CheckUpdate() + { + string response = string.Empty; + const int requestRetryMaxTimes = 20; + for (int i = 0; i != requestRetryMaxTimes; ++i) + { + response = RequestApi(_requestUrl); + if (response.Length != 0) + { + break; + } + } + if (response.Length == 0) + { + return false; + } + JObject json = (JObject)JsonConvert.DeserializeObject(response); + + _latestVersion = json["tag_name"].ToString(); + if (string.Compare(_latestVersion, _curVersion) <= 0 + || ViewStatusStorage.Get("VersionUpdate.Ignore", string.Empty) == _latestVersion) + { + return false; + } + foreach (JObject asset in json["assets"]) + { + string downUrl = asset["browser_download_url"].ToString(); + if (downUrl.IndexOf("MeoAssistance") != -1) + { + _downloadUrl = downUrl; + _lastestJson = json; + return true; + } + } + return false; + } + + private string RequestApi(string url) + { + HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); httpWebRequest.Method = "GET"; httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36"; httpWebRequest.Accept = "application/vnd.github.v3+json"; - httpWebRequest.Timeout = 20000; + //httpWebRequest.Timeout = 20000; try { HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); @@ -71,47 +235,57 @@ namespace MeoAsstGui return string.Empty; } } - - private string _latestUrl = "https://github.com/MistEO/MeoAssistance/releases/latest"; - - public bool CheckUpdate() + private bool DownloadFile(string url, string path) { - string response = RequestApi(); - if (response.Length == 0) + HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); + httpWebRequest.Method = "GET"; + httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36"; + httpWebRequest.Accept = "application/vnd.github.v3+json"; + httpWebRequest.Timeout = 20 * 1000; + try + { + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + Stream reponseStream = httpWebResponse.GetResponseStream(); + Stream fileStream = new FileStream(path, FileMode.Create); + byte[] bArr = new byte[4096]; + int size = reponseStream.Read(bArr, 0, (int)bArr.Length); + while (size > 0) + { + fileStream.Write(bArr, 0, size); + size = reponseStream.Read(bArr, 0, (int)bArr.Length); + }; + fileStream.Close(); + reponseStream.Close(); + httpWebResponse.Close(); + return true; + } + catch (Exception) { return false; } - JObject json = (JObject)JsonConvert.DeserializeObject(response); - - _latestVersion = json["tag_name"].ToString(); - if (string.Compare(_latestVersion, _curVersion) <= 0 - || ViewStatusStorage.Get("VersionUpdate.Ignore", string.Empty) == _latestVersion) - { - return false; - } - - UpdateTag = "新版本:" + json["name"].ToString(); - UpdateInfo = json["body"].ToString(); - _latestUrl = json["html_url"].ToString(); - - return true; } - public void Download() - { - System.Diagnostics.Process.Start(_latestUrl); - RequestClose(); + private static void CopyFilesRecursively(string sourcePath, string targetPath) + { + //Now Create all of the directories + foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) + { + Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath)); + } + + //Copy all the files & Replaces any files with the same name + foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + { + File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true); + } } public void Close() { RequestClose(); - } - - public void Ignore() - { - ViewStatusStorage.Set("VersionUpdate.Ignore", _latestVersion); - RequestClose(); + IsFirstBootAfterUpdate = false; + UpdateTag = ""; + UpdateInfo = ""; } } } \ No newline at end of file diff --git a/src/MeoAsstGui/Views/VersionUpdateView.xaml b/src/MeoAsstGui/Views/VersionUpdateView.xaml index de2601b43c..1a58c81e57 100644 --- a/src/MeoAsstGui/Views/VersionUpdateView.xaml +++ b/src/MeoAsstGui/Views/VersionUpdateView.xaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:s="https://github.com/canton7/Stylet" mc:Ignorable="d" - Title="有新版本" Height="500" Width="600"> + Title="版本已自动更新" Height="500" Width="600"> @@ -21,9 +21,9 @@ -