| @@ -6,9 +6,11 @@ | |||
| <Nullable>enable</Nullable> | |||
| <UseWPF>true</UseWPF> | |||
| <UseWindowsForms>true</UseWindowsForms> | |||
| <AppHostDotNetRoot>dotNetRuntime</AppHostDotNetRoot> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="dotnetCampus.AppHost" Version="1.0.0-alpha10" /> | |||
| <PackageReference Include="ICSharpCode.SharpZipLib.dll" Version="0.85.4.369" /> | |||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> | |||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | |||
| @@ -49,7 +49,7 @@ | |||
| <Button Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="2" Name="UninstBtn" Content="卸载选手包" Command="{Binding ClickUninstCommand}" Visibility="{Binding MenuVis}" /> | |||
| <Button Grid.Row="7" Grid.Column="2" Grid.ColumnSpan="2" Name="MenuBackBtn" Content="回到登陆界面" Command="{Binding ClickBackCommand}" Visibility="{Binding MenuVis}" /> | |||
| <TextBlock Grid.Row="3" Grid.Column="3" Text="正在下载……" Grid.ColumnSpan="2" Visibility="{Binding ProgressVis}"/> | |||
| <TextBlock Grid.Row="3" Grid.Column="3" Text="正在处理……" Grid.ColumnSpan="2" Visibility="{Binding ProgressVis}"/> | |||
| <ProgressBar Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="7" Minimum="0" Maximum="100" Name="Progress" Visibility="{Binding ProgressVis}" IsIndeterminate="True"/> | |||
| <TextBlock Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="4" Text="操作完成!你可以继续操作或退出" Visibility="{Binding CompleteVis}"/> | |||
| @@ -33,6 +33,8 @@ using ICSharpCode.SharpZipLib.Tar; | |||
| using ICSharpCode.SharpZipLib.GZip; | |||
| using static System.Net.WebRequestMethods; | |||
| using File = System.IO.File; | |||
| using System.Linq; | |||
| using Installer; | |||
| namespace starter.viewmodel.settings | |||
| { | |||
| @@ -318,6 +320,15 @@ namespace Downloader | |||
| { | |||
| static List<string> newFileName = new List<string>(); // 新文件名 | |||
| static List<string> updateFileName = new List<string>(); // 更新文件名 | |||
| static List<string> updateFailed = new List<string>(); //更新失败的文件名 | |||
| static public List<string> UpdateFailed | |||
| { | |||
| get { return updateFailed; } | |||
| } | |||
| static public void ResetUpdateFailedInfo() | |||
| { | |||
| updateFailed.Clear(); | |||
| } | |||
| public static string ProgramName = "THUAI6"; // 要运行或下载的程序名称 | |||
| public static string playerFolder = "player"; // 选手代码保存文件夹路径 | |||
| public static string startName = "maintest.exe"; // 启动的程序名 | |||
| @@ -495,7 +506,7 @@ namespace Downloader | |||
| FileStream fst = null; | |||
| try | |||
| { | |||
| fst = new FileStream(strFileFullPath, FileMode.Open); | |||
| fst = new FileStream(strFileFullPath, FileMode.Open, FileAccess.Read); | |||
| byte[] data = MD5.Create().ComputeHash(fst); | |||
| StringBuilder sBuilder = new StringBuilder(); | |||
| @@ -571,7 +582,19 @@ namespace Downloader | |||
| if (MD5.Length == 0) // 文档不存在 | |||
| newFileName.Add(pair.Key); | |||
| else if (MD5.Equals("conflict")) | |||
| MessageBox.Show($"文件{pair.Key}已打开,无法检查是否为最新,若需要,请关闭文件稍后手动检查更新", "文件正在使用", MessageBoxButton.OK, MessageBoxImage.Warning); | |||
| { | |||
| if (pair.Key.Equals("THUAI6/win/CAPI/cpp/.vs/CAPI/v17/Browse.VC.db")) | |||
| { | |||
| MessageBox.Show($"visual studio未关闭:\n" + | |||
| $"对于visual studio 2022,可以更新,更新会覆盖visual studio中已经打开的选手包;\n" + | |||
| $"若使用其他版本的visual studio是继续更新出现问题,请汇报;\n" + | |||
| $"若您自行修改了选手包,请注意备份;\n" + | |||
| $"若关闭visual studio后仍弹出,请汇报。\n\n", | |||
| "visual studio未关闭", MessageBoxButton.OK, MessageBoxImage.Information); | |||
| } | |||
| else | |||
| MessageBox.Show($"检查{pair.Key}更新时遇到问题,请反馈", "读取出错", MessageBoxButton.OK, MessageBoxImage.Error); | |||
| } | |||
| else if (MD5 != pair.Value && System.IO.Path.GetFileName(pair.Key) != "AI.cpp" && System.IO.Path.GetFileName(pair.Key) != "AI.py") // MD5不匹配 | |||
| updateFileName.Add(pair.Key); | |||
| } | |||
| @@ -622,19 +645,20 @@ namespace Downloader | |||
| if (UpdatePlanned) | |||
| { | |||
| Download(); | |||
| UpdatePlanned = false; | |||
| return true; | |||
| if (updateFailed.Count == 0) | |||
| return true; | |||
| else | |||
| Check(); | |||
| } | |||
| return false; | |||
| } | |||
| private static void Download() | |||
| { | |||
| Tencent_cos_download Downloader = new Tencent_cos_download(); | |||
| int newFile = 0, updateFile = 0; | |||
| int totalnew = newFileName.Count, totalupdate = updateFileName.Count; | |||
| filenum = totalnew + totalupdate; | |||
| updateFailed.Clear(); | |||
| if (newFileName.Count > 0 || updateFileName.Count > 0) | |||
| { | |||
| try | |||
| @@ -649,12 +673,20 @@ namespace Downloader | |||
| foreach (string filename in updateFileName) | |||
| { | |||
| //Console.WriteLine(updateFile + 1 + "/" + totalupdate + ":开始下载" + filename); | |||
| File.Delete(System.IO.Path.Combine(@Data.FilePath, filename)); | |||
| Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename); | |||
| try | |||
| { | |||
| File.Delete(System.IO.Path.Combine(@Data.FilePath, filename)); | |||
| Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename); | |||
| } | |||
| catch (System.IO.IOException) | |||
| { | |||
| updateFailed = updateFailed.Append(filename).ToList(); | |||
| } | |||
| //Console.WriteLine(filename + "下载完毕!" + Environment.NewLine); | |||
| updateFile++; | |||
| } | |||
| UpdatePlanned = false; | |||
| if (updateFailed.Count == 0) | |||
| UpdatePlanned = false; | |||
| } | |||
| catch (CosClientException clientEx) | |||
| { | |||
| @@ -1160,6 +1192,50 @@ namespace Downloader | |||
| } | |||
| } | |||
| } | |||
| public static int CheckSelfVersion() | |||
| { | |||
| Tencent_cos_download downloader = new Tencent_cos_download(); | |||
| string hashName = "installerHash.json"; | |||
| string dir = Directory.GetCurrentDirectory(); | |||
| try | |||
| { | |||
| if (File.Exists(System.IO.Path.Combine(dir, hashName))) | |||
| File.Delete(System.IO.Path.Combine(dir, hashName)); | |||
| downloader.download(System.IO.Path.Combine(dir, hashName), hashName); | |||
| } | |||
| catch | |||
| { | |||
| return -1; | |||
| } | |||
| string json; | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(dir, hashName))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty); | |||
| Dictionary<string, string> jsonDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json); | |||
| if (jsonDict != null) | |||
| { | |||
| if (jsonDict.ContainsKey("InstallerUpdater.exe")) | |||
| { | |||
| string updaterHash = GetFileMd5Hash(System.IO.Path.Combine(dir, "InstallerUpdater.exe")); | |||
| if (updaterHash != null && !jsonDict["InstallerUpdater.exe"].Equals(updaterHash)) | |||
| downloader.download(System.IO.Path.Combine(dir, "InstallerUpdater.exe"), "InstallerUpdater.exe"); | |||
| } | |||
| else | |||
| return -1; | |||
| if (jsonDict.ContainsKey("Installer.exe")) | |||
| { | |||
| string selfHash = GetFileMd5Hash(System.IO.Path.Combine(dir, "Installer.exe")); | |||
| if (selfHash != null && !jsonDict["Installer.exe"].Equals(selfHash)) | |||
| return 1; | |||
| } | |||
| else | |||
| return -1; | |||
| } | |||
| else | |||
| return -1; | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -13,6 +13,7 @@ using Installer; | |||
| using static System.Windows.Forms.VisualStyles.VisualStyleElement; | |||
| using System.IO; | |||
| using System.Windows.Automation.Provider; | |||
| using System.Diagnostics; | |||
| namespace starter.viewmodel.settings | |||
| { | |||
| @@ -34,6 +35,22 @@ namespace starter.viewmodel.settings | |||
| //Program.Tencent_cos_download.UpdateHash(); | |||
| Status = SettingsModel.Status.working; | |||
| switch (Program.Tencent_cos_download.CheckSelfVersion()) | |||
| { | |||
| case 1: | |||
| if (MessageBoxResult.Yes == MessageBox.Show("下载器需要更新,是否现在更新", "需要更新", MessageBoxButton.YesNo)) | |||
| { | |||
| Process.Start(Path.Combine(Directory.GetCurrentDirectory(), "InstallerUpdater.exe")); | |||
| Environment.Exit(0); | |||
| } | |||
| break; | |||
| case -1: | |||
| MessageBox.Show("下载器更新检查出错,将继续启动现有下载器"); | |||
| break; | |||
| } | |||
| //实例化BackgroundWorker | |||
| asyncDownloader = new BackgroundWorker(); | |||
| asyncUpdater = new BackgroundWorker(); | |||
| @@ -113,6 +130,20 @@ namespace starter.viewmodel.settings | |||
| this.RaisePropertyChanged("LaunchBtnCont"); | |||
| this.RaisePropertyChanged("UpdateInfo"); | |||
| } | |||
| else | |||
| { | |||
| string updateFailList = ""; | |||
| foreach (var Filename in Program.UpdateFailed) | |||
| { | |||
| updateFailList += Filename + "\n"; | |||
| } | |||
| MessageBox.Show($"以下文件因被占用而未能成功更新:\n{updateFailList}请关闭它们,并再试一次"); | |||
| Program.ResetUpdateFailedInfo(); | |||
| Status = SettingsModel.Status.successful; | |||
| this.RaisePropertyChanged("UpdateBtnCont"); | |||
| this.RaisePropertyChanged("UpdateInfo"); | |||
| this.RaisePropertyChanged("LaunchBtnCont"); | |||
| } | |||
| } | |||
| } | |||
| @@ -649,8 +680,8 @@ namespace starter.viewmodel.settings | |||
| { | |||
| UpdateInfoVis = Visibility.Visible; | |||
| this.RaisePropertyChanged("UpdateInfoVis"); | |||
| Status = SettingsModel.Status.working; | |||
| this.RaisePropertyChanged("ProgressVis"); | |||
| //Status = SettingsModel.Status.working; | |||
| //this.RaisePropertyChanged("ProgressVis"); | |||
| Status = obj.checkUpdate(); | |||
| this.RaisePropertyChanged("UpdateBtnCont"); | |||
| this.RaisePropertyChanged("UpdateInfo"); | |||
| @@ -0,0 +1,9 @@ | |||
| <Application x:Class="InstallerUpdater.App" | |||
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
| xmlns:local="clr-namespace:InstallerUpdater" | |||
| StartupUri="MainWindow.xaml"> | |||
| <Application.Resources> | |||
| </Application.Resources> | |||
| </Application> | |||
| @@ -0,0 +1,17 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Configuration; | |||
| using System.Data; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using System.Windows; | |||
| namespace InstallerUpdater | |||
| { | |||
| /// <summary> | |||
| /// Interaction logic for App.xaml | |||
| /// </summary> | |||
| public partial class App : Application | |||
| { | |||
| } | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| using System.Windows; | |||
| [assembly: ThemeInfo( | |||
| ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located | |||
| //(used if a resource is not found in the page, | |||
| // or application resource dictionaries) | |||
| ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located | |||
| //(used if a resource is not found in the page, | |||
| // app, or any theme specific resource dictionaries) | |||
| )] | |||
| @@ -0,0 +1,19 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <OutputType>WinExe</OutputType> | |||
| <TargetFramework>net6.0-windows</TargetFramework> | |||
| <Nullable>enable</Nullable> | |||
| <UseWPF>true</UseWPF> | |||
| <AppHostDotNetRoot>dotNetRuntime</AppHostDotNetRoot> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="dotnetCampus.AppHost" Version="1.0.0-alpha10" /> | |||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | |||
| <PackageReference Include="Tencent.QCloud.Cos.Sdk" Version="5.4.34"> | |||
| <TreatAsUsed>true</TreatAsUsed> | |||
| </PackageReference> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,25 @@ | |||
| <Window x:Class="InstallerUpdater.MainWindow" | |||
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
| xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
| xmlns:local="clr-namespace:InstallerUpdater" | |||
| mc:Ignorable="d" | |||
| Title="MainWindow" Height="180" Width="300"> | |||
| <Grid> | |||
| <Grid.RowDefinitions> | |||
| <RowDefinition Height="40"/> | |||
| <RowDefinition Height="20"/> | |||
| <RowDefinition Height="40"/> | |||
| <RowDefinition Height="20"/> | |||
| <RowDefinition Height="*"/> | |||
| </Grid.RowDefinitions> | |||
| <Grid.ColumnDefinitions> | |||
| <ColumnDefinition Width="40"/> | |||
| <ColumnDefinition Width="*"/> | |||
| <ColumnDefinition Width="40"/> | |||
| </Grid.ColumnDefinitions> | |||
| <TextBlock Grid.Row="1" Grid.Column="1" TextAlignment="Center">正在尝试更新下载器</TextBlock> | |||
| <ProgressBar Grid.Row="3" Grid.Column="1" IsIndeterminate="True"/> | |||
| </Grid> | |||
| </Window> | |||
| @@ -0,0 +1,77 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using System.Windows; | |||
| using System.Windows.Controls; | |||
| using System.Windows.Data; | |||
| using System.Windows.Documents; | |||
| using System.Windows.Input; | |||
| using System.Windows.Media; | |||
| using System.Windows.Media.Imaging; | |||
| using System.Windows.Navigation; | |||
| using System.Windows.Shapes; | |||
| using Program; | |||
| using System.Diagnostics; | |||
| using System.IO; | |||
| using System.ComponentModel; | |||
| namespace InstallerUpdater | |||
| { | |||
| /// <summary> | |||
| /// Interaction logic for MainWindow.xaml | |||
| /// </summary> | |||
| public partial class MainWindow : Window | |||
| { | |||
| BackgroundWorker asyncDownloader = new BackgroundWorker(); | |||
| public MainWindow() | |||
| { | |||
| InitializeComponent(); | |||
| asyncDownloader.DoWork += AsyncDownloader_DoWork; | |||
| asyncDownloader.RunWorkerCompleted += AsyncDownloader_RunWorkerCompleted; | |||
| if (asyncDownloader.IsBusy) | |||
| { | |||
| MessageBox.Show("更新失败,请汇报"); | |||
| Process.Start(System.IO.Path.Combine(Updater.Dir, "Installer.exe")); | |||
| Application.Current.Shutdown(); | |||
| } | |||
| else | |||
| asyncDownloader.RunWorkerAsync(); | |||
| } | |||
| private void AsyncDownloader_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e) | |||
| { | |||
| if (e.Result == null) | |||
| { | |||
| MessageBox.Show("更新失败,请汇报"); | |||
| } | |||
| else if ((bool)e.Result) | |||
| { | |||
| MessageBox.Show("已成功更新下载器,即将启动下载器"); | |||
| } | |||
| else | |||
| { | |||
| MessageBox.Show("更新失败,请汇报"); | |||
| } | |||
| Process.Start(System.IO.Path.Combine(Updater.Dir, "Installer.exe")); | |||
| Application.Current.Shutdown(); | |||
| } | |||
| private void AsyncDownloader_DoWork(object? sender, DoWorkEventArgs e) | |||
| { | |||
| if (asyncDownloader.CancellationPending) | |||
| { | |||
| e.Cancel = true; | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| if (Updater.UpdateInstaller()) | |||
| e.Result = true; | |||
| else | |||
| e.Result = false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,89 @@ | |||
| using COSXML.Auth; | |||
| using COSXML.CosException; | |||
| using COSXML.Model.Object; | |||
| using COSXML; | |||
| using System.Collections.Generic; | |||
| using System.IO; | |||
| using System.Net; | |||
| using System.Text; | |||
| using Newtonsoft.Json; | |||
| using System.Windows.Markup; | |||
| using System; | |||
| using System.Security.Cryptography; | |||
| using System.Diagnostics; | |||
| namespace Program | |||
| { | |||
| class Updater | |||
| { | |||
| public static string Dir = Directory.GetCurrentDirectory(); | |||
| public static string InstallerName = "Installer.exe"; | |||
| public static string jsonKey = "installerHash.json"; | |||
| public static bool UpdateInstaller() | |||
| { | |||
| try | |||
| { | |||
| download(Path.Combine(Dir, "newInstaller.exe"), InstallerName); | |||
| File.Delete(Path.Combine(Dir, InstallerName)); | |||
| File.Move(Path.Combine(Dir, "newInstaller.exe"), Path.Combine(Dir, InstallerName)); | |||
| } | |||
| catch | |||
| { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| public static void download(string download_dir, string key) | |||
| { | |||
| // download_dir标记根文件夹路径,key为相对根文件夹的路径(不带./) | |||
| // 初始化CosXmlConfig(提供配置SDK接口) | |||
| string appid = "1314234950"; // 设置腾讯云账户的账户标识(APPID) | |||
| string region = "ap-beijing"; // 设置一个默认的存储桶地域 | |||
| CosXmlConfig config = new CosXmlConfig.Builder() | |||
| .IsHttps(true) // 设置默认 HTTPS 请求 | |||
| .SetAppid(appid) // 设置腾讯云账户的账户标识 APPID | |||
| .SetRegion(region) // 设置一个默认的存储桶地域 | |||
| .SetDebugLog(true) // 显示日志 | |||
| .Build(); // 创建 CosXmlConfig 对象 | |||
| // 永久密钥访问凭证 | |||
| string secretId = "***"; //"云 API 密钥 SecretId"; | |||
| string secretKey = "***"; //"云 API 密钥 SecretKey"; | |||
| long durationSecond = 1000; // 每次请求签名有效时长,单位为秒 | |||
| QCloudCredentialProvider cosCredentialProvider = new DefaultQCloudCredentialProvider( | |||
| secretId, secretKey, durationSecond | |||
| ); | |||
| // 初始化 CosXmlServer | |||
| CosXmlServer cosXml = new CosXmlServer(config, cosCredentialProvider); | |||
| // 创建存储桶 | |||
| try | |||
| { | |||
| string bucket = "thuai6-1314234950"; // 格式:BucketName-APPID | |||
| string localDir = System.IO.Path.GetDirectoryName(download_dir); // 本地文件夹 | |||
| string localFileName = System.IO.Path.GetFileName(download_dir); // 指定本地保存的文件名 | |||
| GetObjectRequest request = new GetObjectRequest(bucket, key, localDir, localFileName); | |||
| Dictionary<string, string> test = request.GetRequestHeaders(); | |||
| request.SetCosProgressCallback(delegate (long completed, long total) | |||
| { | |||
| //Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total)); | |||
| }); | |||
| // 执行请求 | |||
| GetObjectResult result = cosXml.GetObject(request); | |||
| // 请求成功 | |||
| } | |||
| catch (CosClientException clientEx) | |||
| { | |||
| throw clientEx; | |||
| } | |||
| catch (CosServerException serverEx) | |||
| { | |||
| throw serverEx; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.32014.148 | |||
| MinimumVisualStudioVersion = 10.0.40219.1 | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Installer", "Installer\Installer.csproj", "{C10AF177-0883-4D9D-B2DC-3516BE04DF81}" | |||
| EndProject | |||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstallerUpdater", "InstallerUpdater\InstallerUpdater.csproj", "{B2E61AB9-F7BF-4C48-ABFC-60F7F214BB14}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|Any CPU = Debug|Any CPU | |||
| @@ -15,6 +17,10 @@ Global | |||
| {C10AF177-0883-4D9D-B2DC-3516BE04DF81}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {C10AF177-0883-4D9D-B2DC-3516BE04DF81}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {C10AF177-0883-4D9D-B2DC-3516BE04DF81}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {B2E61AB9-F7BF-4C48-ABFC-60F7F214BB14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {B2E61AB9-F7BF-4C48-ABFC-60F7F214BB14}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {B2E61AB9-F7BF-4C48-ABFC-60F7F214BB14}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {B2E61AB9-F7BF-4C48-ABFC-60F7F214BB14}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||