Browse Source

Merge pull request #314 from OctaAcid/dev

chore: now allows self update
tags/0.1.0
shangfengh GitHub 2 years ago
parent
commit
62a2c8d2da
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 373 additions and 12 deletions
  1. +2
    -0
      installer/Installer/Installer.csproj
  2. +1
    -1
      installer/Installer/MainWindow.xaml
  3. +85
    -9
      installer/Installer/Model.cs
  4. +33
    -2
      installer/Installer/ViewModel.cs
  5. +9
    -0
      installer/InstallerUpdater/App.xaml
  6. +17
    -0
      installer/InstallerUpdater/App.xaml.cs
  7. +10
    -0
      installer/InstallerUpdater/AssemblyInfo.cs
  8. +19
    -0
      installer/InstallerUpdater/InstallerUpdater.csproj
  9. +25
    -0
      installer/InstallerUpdater/MainWindow.xaml
  10. +77
    -0
      installer/InstallerUpdater/MainWindow.xaml.cs
  11. +89
    -0
      installer/InstallerUpdater/Program.cs
  12. +6
    -0
      installer/installer.sln

+ 2
- 0
installer/Installer/Installer.csproj View File

@@ -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" />


+ 1
- 1
installer/Installer/MainWindow.xaml View File

@@ -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}"/>


+ 85
- 9
installer/Installer/Model.cs View File

@@ -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;
}
}
}
}


+ 33
- 2
installer/Installer/ViewModel.cs View File

@@ -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");


+ 9
- 0
installer/InstallerUpdater/App.xaml View File

@@ -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>

+ 17
- 0
installer/InstallerUpdater/App.xaml.cs View File

@@ -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
{
}
}

+ 10
- 0
installer/InstallerUpdater/AssemblyInfo.cs View File

@@ -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)
)]

+ 19
- 0
installer/InstallerUpdater/InstallerUpdater.csproj View File

@@ -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>

+ 25
- 0
installer/InstallerUpdater/MainWindow.xaml View File

@@ -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>

+ 77
- 0
installer/InstallerUpdater/MainWindow.xaml.cs View File

@@ -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;
}
}
}
}

+ 89
- 0
installer/InstallerUpdater/Program.cs View File

@@ -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;
}
}
}
}

+ 6
- 0
installer/installer.sln View File

@@ -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


Loading…
Cancel
Save