THUAI6/installer/Installer/Model.cs

2266 lines
100 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using COSXML.Auth;
using COSXML.CosException;
using COSXML.Model.Object;
using COSXML;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System;
using COSXML.Model.Bucket;
using System.Runtime.InteropServices;
using System.Text.Json.Nodes;
using System.Net.Http.Json;
using System.Text.Json;
using System.Xml.Schema;
using static Downloader.Program;
using System.Threading.Tasks;
using System.Net.Http;
using System.Windows;
using System.Windows.Shapes;
using System.Collections.Concurrent;
//using System.Windows.Forms;
using System.Threading;
using MessageBox = System.Windows.MessageBox;
using Downloader;
using COSXML.Transfer;
using WebConnect;
using System.IO.Compression;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.GZip;
using static System.Net.WebRequestMethods;
using File = System.IO.File;
using System.Linq;
using Installer;
using starter.viewmodel.settings;
using System.Security.Permissions;
using System.Windows.Media;
namespace starter.viewmodel.settings
{
/// <summary>
/// Settings Window Model
/// </summary>
public class SettingsModel
{
/// <summary>
/// downloader function
/// </summary>
private Data configData = new Data("");
private Tencent_cos_download cloud = new Tencent_cos_download();
private HttpClient client = new HttpClient();
private WebConnect.Web web = new WebConnect.Web();
public SettingsModel()
{
Route = Data.FilePath;
Username = "";
Password = "";
updates = "";
CodeRoute = "";
PlayerNum = "nSelect";
UploadReady = false;
LoginFailed = false;
launchLanguage = LaunchLanguage.cpp;
usingOS = ReadUsingOS();
}
/// <summary>
/// save settings
/// </summary>
public bool install()
{
if (Tencent_cos_download.CheckAlreadyDownload())
{
MessageBoxResult repeatOption = MessageBox.Show($"文件已存在于{Downloader.Program.Data.FilePath},是否移动到新位置?", "重复安装", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
// ask if abort install, with warning sign, defalut move instead of abort;
if (repeatOption == MessageBoxResult.No)
{
Route = Data.FilePath;
return false;
}
else
{
Downloader.Program.Tencent_cos_download.MoveProgram(Route);
return true;
}
}
else
{
Data.ResetFilepath(Route);
Tencent_cos_download.DownloadAll();
return true;
}
}
public int move()
{
int state = Tencent_cos_download.MoveProgram(Route);
if (state != 0)
Route = Data.FilePath;
return state;
}
///<summary>
///check for update
/// </summary>
static bool ProfileAvailable
{
get; set;
}
/// <summary>
/// 检查更新
/// </summary>
/// <returns></returns>
public Status checkUpdate()
{
UpdateInfo updateInfo = Tencent_cos_download.Check(usingOS);
if (updateInfo.newFileCount == -1)
{
if (updateInfo.changedFileCount == -1)
{
return Status.error;
}
else
{
return Status.disconnected;
}
}
else
{
if (updateInfo.changedFileCount != 0 || updateInfo.newFileCount != 0)
{
Updates = $"{updateInfo.newFileCount}个新文件,{updateInfo.changedFileCount}个文件变化";
}
return Status.menu;
}
}
public async Task<int> Login()
{
return await web.LoginToEEsast(client, Username, Password);
}
public bool RememberUser()
{
int result = 0;
result |= Web.WriteJson("email", Username);
result |= Web.WriteJson("password", Password);
return result == 0;
}
public bool RecallUser()
{
var username = Web.ReadJson("email");
if (username == null || username.Equals(""))
{
Username = "";
return false;
}
Username = username;
var password = Web.ReadJson("password");
if (password == null || password.Equals(""))
{
Password = "";
return false;
}
Password = password;
return true;
}
public bool ForgetUser()
{
int result = 0;
result |= Web.WriteJson("email", "");
result |= Web.WriteJson("password", "");
return result == 0;
}
public bool Update()
{
try
{
return Tencent_cos_download.Update();
}
catch
{
return false;
}
}
public int Uninst()
{
return Tencent_cos_download.DeleteAll();
}
public bool Launch()
{
if (Tencent_cos_download.CheckAlreadyDownload())
{
//Process.Start(System.IO.Path.Combine(Data.FilePath, startName));
switch (RunProgram.RunInfo.mode)
{
case RunProgram.RunMode.ServerOnly:
RunProgram.StartServer(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
break;
case RunProgram.RunMode.ServerForDebugOnly:
RunProgram.StartServerForDebug(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
break;
case RunProgram.RunMode.GUIAttendGameOnly:
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID,
false, RunProgram.RunInfo.occupation, RunProgram.RunInfo.type);
break;
case RunProgram.RunMode.GUIVisit:
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, 0, true, 1, 1);
break;
case RunProgram.RunMode.GUIAndAICpp:
RunProgram.StartServerForDebug(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunCpp(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID,
false, RunProgram.RunInfo.occupation, RunProgram.RunInfo.type);
break;
case RunProgram.RunMode.GUIAndAIPython:
RunProgram.StartServerForDebug(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunPython(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID,
false, RunProgram.RunInfo.occupation, RunProgram.RunInfo.type);
break;
case RunProgram.RunMode.ServerAndCpp:
RunProgram.StartServer(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunCpp(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
break;
case RunProgram.RunMode.ServerAndPython:
RunProgram.StartServer(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunPython(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
break;
case RunProgram.RunMode.ServerAndCppVisit:
RunProgram.StartServer(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunCpp(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID, true, 0, 1);
break;
case RunProgram.RunMode.ServerAndPythonVisit:
RunProgram.StartServer(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunPython(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID, true, 0, 1);
break;
case RunProgram.RunMode.ServerDebugAndCppVisit:
RunProgram.StartServerForDebug(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunCpp(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID, true, 0, 1);
break;
case RunProgram.RunMode.ServerDebugAndPythonVisit:
RunProgram.StartServerForDebug(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.gameTimeSec, RunProgram.RunInfo.playbackFileName);
Task.Delay(100);
RunProgram.RunPython(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.studentCount,
RunProgram.RunInfo.trickerCount, RunProgram.RunInfo.saveDebugLog, RunProgram.RunInfo.showDebugLog,
RunProgram.RunInfo.warningOnly, RunProgram.RunInfo.playerId, RunProgram.RunInfo.filePath);
RunProgram.RunInfo.playerId = null;
RunProgram.RunInfo.filePath = null;
RunProgram.RunGUIClient(RunProgram.RunInfo.IP, RunProgram.RunInfo.port, RunProgram.RunInfo.characterID, true, 0, 1);
break;
}
return true;
}
else
{
MessageBox.Show($"文件还不存在,请安装主体文件", "文件不存在", MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
return false;
}
}
public async Task<int> Upload()
{
switch (CodeRoute.Substring(CodeRoute.LastIndexOf('.') + 1))
{
case "cpp":
case "h":
Language = "cpp";
break;
case "py":
Language = "python";
break;
default:
return -8;
}
if (PlayerNum.Equals("nSelect"))
return -9;
return await web.UploadFiles(client, CodeRoute, Language, PlayerNum);
}
public bool WriteUsingOS()
{
string OS = "";
switch (usingOS)
{
case UsingOS.Win:
OS = "win";
break;
case UsingOS.Linux:
OS = "linux";
break;
case UsingOS.OSX:
OS = "osx";
break;
}
return Web.WriteJson("OS", OS) == 0;
}
public UsingOS ReadUsingOS()
{
return Web.ReadJson("OS") switch
{
"linux" => UsingOS.Linux,
"osx" => UsingOS.OSX,
_ => UsingOS.Win,
};
}
/// <summary>
/// Route of files
/// </summary>
public string Route
{
get; set;
}
public string Username
{
get; set;
}
public string Password
{
get; set;
}
public string CodeRoute
{
get; set;
}
public string? Language
{
get; set;
}
public string PlayerNum
{
get; set;
}
/// <summary>
/// 关于更新的屏幕显示信息
/// </summary>
private string updates;
public string Updates
{
get
{
return updates;
}
set
{
updates = value;
}
}
/// <summary>
/// 关于介绍的屏幕显示信息
/// </summary>
public enum Status { newUser, menu, move, working, initializing, disconnected, error, successful, login, web, launch };
public Status status
{
get; set;
}
public bool Working
{
get; set;
}
/// <summary>
/// if an update is planned
/// </summary>
public bool UpdatePlanned
{
get
{
return Program.UpdatePlanned;
}
}
public bool CombatCompleted
{
get
{
return false;
}
}
public bool LoginFailed
{
get; set;
}
public bool UploadReady
{
get; set;
}
public bool RememberMe
{
get; set;
}
public enum LaunchLanguage { cpp, python };
public LaunchLanguage launchLanguage
{
get; set;
}
public enum UsingOS { Win, Linux, OSX };
public UsingOS usingOS
{
get; set;
}
}
}
namespace Downloader
{
class UserInfo
{
static public string _id = "";
static public string email = "";
}
class Program
{
static ConcurrentQueue<string> newFileName = new ConcurrentQueue<string>();
//static List<string> newFileName = new List<string>(); // 新文件名
static ConcurrentQueue<string> updateFileName = new ConcurrentQueue<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"; // 启动的程序名
public struct UpdateInfo // 更新信息,包括新版本版本号、更改文件数和新文件数
{
public string status;
public int changedFileCount;
public int newFileCount;
}
public static bool UpdatePlanned
{
get; set;
}
static int filenum = 0; // 总文件个数
public class Data
{
public static string path = ""; // 标记路径记录文件THUAI6.json的路径
public static string FilePath = ""; // 最后一级为THUAI6文件夹所在目录
public static string dataPath = ""; // C盘的文档文件夹
public Data(string path)
{
dataPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//dataPath = new DirectoryInfo(".").FullName;
Data.path = System.IO.Path.Combine(dataPath, "THUAI6.json");
if (File.Exists(Data.path))
{
Dictionary<string, string>? dict;
using (StreamReader r = new StreamReader(Data.path))
{
string json = r.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json);
if (dict != null && dict.ContainsKey("installpath"))
{
FilePath = dict["installpath"].Replace('\\', '/');
} //读取安装路径
}
dict?.TryAdd("installpath", @path);
using FileStream fs = new FileStream(Data.path, FileMode.Create, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs);
sw.Write(JsonConvert.SerializeObject(dict));
sw.Flush();
}
else
{
FilePath = System.IO.Path.GetDirectoryName(@path)
?? throw new Exception("Failed to get the path of the file");
//将dat文件写入程序运行路径
string json;
Dictionary<string, string>? dict;
using FileStream fs = new FileStream(Data.path, FileMode.Create, FileAccess.ReadWrite);
using (StreamReader r = new StreamReader(fs))
{
json = r.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json);
dict?.Add("installpath", path);
}
using FileStream fs2 = new FileStream(Data.path, FileMode.Create, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs2);
sw.Write(JsonConvert.SerializeObject(dict));
sw.Flush();
}
}
public static void ResetFilepath(string newPath)
{
string json;
Dictionary<string, string>? dict;
FilePath = newPath.Replace('\\', '/');
path = System.IO.Path.Combine(dataPath, "THUAI6.json");
using FileStream fs = new FileStream(Data.path, FileMode.Create, FileAccess.ReadWrite);
using (StreamReader r = new StreamReader(fs))
{
json = r.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json);
if (dict != null && dict.ContainsKey("installpath"))
{
dict["installpath"] = newPath;
}
else
{
dict?.Add("installpath", newPath);
}
if (dict == null || !dict.ContainsKey("download"))
{
dict?.Add("download", "true");
}
else
{
dict["download"] = "true";
}
}
using FileStream fs2 = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs2);
fs2.SetLength(0);
sw.Write(JsonConvert.SerializeObject(dict));
sw.Flush();
}
}
public class Tencent_cos_download
{
public 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) // 本地文件夹
?? throw new Exception("本地文件夹路径获取失败");
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;
}
catch
{
MessageBox.Show($"下载{download_dir}时出现未知问题,请反馈");
}
}
public static void GetNewHash()
{
Tencent_cos_download Downloader = new Tencent_cos_download();
Downloader.download(System.IO.Path.Combine(Data.FilePath, "hash.json"), "hash.json");
}
public static string GetFileMd5Hash(string strFileFullPath)
{
FileStream? fst = null;
try
{
fst = new FileStream(strFileFullPath, FileMode.Open, FileAccess.Read);
byte[] data = MD5.Create().ComputeHash(fst);
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
fst.Close();
return sBuilder.ToString().ToLower();
}
catch (Exception)
{
if (fst != null)
fst.Close();
if (File.Exists(strFileFullPath))
return "conflict";
return "";
}
finally
{
}
}
public static bool IsUserFile(string filename)
{
if (filename.Substring(filename.Length - 3, 3).Equals(".sh") || filename.Substring(filename.Length - 4, 4).Equals(".cmd"))
return true;
if (filename.Equals("AI.cpp") || filename.Equals("AI.py"))
return true;
return false;
}
public static UpdateInfo Check(SettingsModel.UsingOS OS)
{
string json, MD5, jsonName;
int newFile = 0, updateFile = 0;
newFileName.Clear();
updateFileName.Clear();
jsonName = "hash.json";
UpdateInfo updateInfo;
Tencent_cos_download Downloader = new Tencent_cos_download();
try
{
// 如果json存在就删了重新下
if (File.Exists(System.IO.Path.Combine(Data.FilePath, jsonName)))
{
File.Delete(System.IO.Path.Combine(Data.FilePath, jsonName));
Downloader.download(System.IO.Path.Combine(Data.FilePath, jsonName), jsonName);
}
else
{
Downloader.download(System.IO.Path.Combine(Data.FilePath, jsonName), jsonName);
}
}
catch (CosClientException clientEx)
{
// 请求失败
updateInfo.status = "ClientEx: " + clientEx.ToString();
updateInfo.newFileCount = -1;
updateInfo.changedFileCount = 0;
return updateInfo;
}
catch (CosServerException serverEx)
{
// 请求失败
updateInfo.status = "ServerEx: " + serverEx.ToString();
updateInfo.newFileCount = -1;
updateInfo.changedFileCount = 0;
return updateInfo;
}
using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, jsonName)))
json = r.ReadToEnd();
json = json.Replace("\r", string.Empty).Replace("\n", string.Empty);
var jsonDict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
string updatingFolder = "";
switch (OS)
{
case SettingsModel.UsingOS.Win:
updatingFolder = "THUAI6/win";
break;
case SettingsModel.UsingOS.Linux:
updatingFolder = "THUAI6/lin";
break;
case SettingsModel.UsingOS.OSX:
updatingFolder = "THUAI6/osx";
break;
}
foreach (KeyValuePair<string, string> pair in jsonDict)
{
if (pair.Key.Length > 10 && (pair.Key.Substring(0, 10).Equals(updatingFolder)) || pair.Key.Substring(pair.Key.Length - 4, 4).Equals(".pdf"))
{
MD5 = GetFileMd5Hash(System.IO.Path.Combine(Data.FilePath, pair.Key.TrimStart(new char[] { '.', '/' })));
if (MD5.Length == 0) // 文档不存在
newFileName.Enqueue(pair.Key);
else if (MD5.Equals("conflict"))
{
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.Equals(pair.Value) && !IsUserFile(System.IO.Path.GetFileName(pair.Key))) // MD5不匹配
updateFileName.Enqueue(pair.Key);
}
}
newFile = newFileName.Count;
updateFile = updateFileName.Count;
filenum = newFile + updateFile;
//Console.WriteLine("----------------------" + Environment.NewLine);
if (newFile + updateFile == 0)
{
updateInfo.status = "latest";
updateInfo.newFileCount = 0;
updateInfo.changedFileCount = 0;
newFileName.Clear();
updateFileName.Clear();
}
else
{
updateInfo.status = "old";
//TODO:获取版本号
updateInfo.newFileCount = newFile;
/*
foreach (string filename in newFileName)
{
Console.WriteLine(filename);
}
*/
updateInfo.changedFileCount = updateFile;
/*
foreach (string filename in updateFileName)
{
Console.WriteLine(filename);
}
Console.Write(Environment.NewLine + "是否下载新文件? y/n");
if (Console.Read() != 'y')
Console.WriteLine("下载取消!");
else
Download();
*/
UpdatePlanned = true;
}
return updateInfo;
}
public static bool Update()
{
if (UpdatePlanned)
{
Download();
if (updateFailed.Count == 0)
return true;
}
return false;
}
private static void Download()
{
Tencent_cos_download Downloader = new Tencent_cos_download();
int newFile = 0;
int totalnew = newFileName.Count, totalupdate = updateFileName.Count;
filenum = totalnew + totalupdate;
updateFailed.Clear();
if (newFileName.Count > 0 || updateFileName.Count > 0)
{
try
{
int cnt = newFileName.Count;
if (cnt <= 20)
{
while (newFileName.TryDequeue(out var filename))
{
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename.TrimStart(new char[] { '.', '/' }));
//Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
Interlocked.Increment(ref newFile);
}
}
else
{
const int nthread = 8;
var thrds = new List<Thread>();
for (int i = 0; i < nthread; i++)
{
var thrd = new Thread(() =>
{
while (newFileName.TryDequeue(out var filename))
{
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename.TrimStart(new char[] { '.', '/' }));
//Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
Interlocked.Increment(ref newFile);
}
});
thrd.Start();
thrds.Add(thrd);
}
foreach (var thrd in thrds)
{
thrd.Join();
}
}
// 读取 Interlocked.CompareExchange(ref newFile, 0, 0);
int upcnt = updateFileName.Count;
if (upcnt <= 20)
{
while (updateFileName.TryDequeue(out var filename))
{
try
{
File.Delete(System.IO.Path.Combine(@Data.FilePath, filename));
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename.TrimStart(new char[] { '.', '/' }));
}
catch (System.IO.IOException)
{
updateFailed = updateFailed.Append(filename).ToList();
}
catch
{
if (filename.Substring(filename.Length - 4, 4).Equals(".pdf"))
{
MessageBox.Show($"由于曾经发生过的访问冲突,下载器无法更新{filename}\n"
+ $"请手动删除{filename},然后再试一次。");
}
else
MessageBox.Show($"更新{filename}时遇到未知问题,请反馈");
updateFailed = updateFailed.Append(filename).ToList();
}
Interlocked.Increment(ref newFile);
}
}
else
{
const int nthread = 8;
var thrds = new List<Thread>();
for (int i = 0; i < nthread; i++)
{
var thrd = new Thread(() =>
{
while (updateFileName.TryDequeue(out var filename))
{
try
{
File.Delete(System.IO.Path.Combine(@Data.FilePath, filename));
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename.TrimStart(new char[] { '.', '/' }));
}
catch (System.IO.IOException)
{
updateFailed = updateFailed.Append(filename).ToList();
}
catch
{
if (filename.Substring(filename.Length - 4, 4).Equals(".pdf"))
{
MessageBox.Show($"由于曾经发生过的访问冲突,下载器无法更新{filename}\n"
+ $"请手动删除{filename},然后再试一次。");
}
else
MessageBox.Show($"更新{filename}时遇到未知问题,请反馈");
updateFailed = updateFailed.Append(filename).ToList();
}
Interlocked.Increment(ref newFile);
}
});
thrd.Start();
thrds.Add(thrd);
}
foreach (var thrd in thrds)
{
thrd.Join();
}
}
if (updateFailed.Count == 0)
UpdatePlanned = false;
}
catch (CosClientException clientEx)
{
// 请求失败
MessageBox.Show("连接错误:" + clientEx.ToString());
Console.WriteLine("CosClientException: " + clientEx.ToString() + Environment.NewLine);
return;
}
catch (CosServerException serverEx)
{
// 请求失败
MessageBox.Show("连接错误:" + serverEx.ToString());
Console.WriteLine("CosClientException: " + serverEx.ToString() + Environment.NewLine);
return;
}
catch (Exception)
{
MessageBox.Show("未知错误且无法定位到出错文件,请反馈");
throw;
}
}
else
Console.WriteLine("当前平台已是最新版本!" + Environment.NewLine);
newFileName.Clear();
updateFileName.Clear();
}
public static bool CheckAlreadyDownload() // 检查是否已经下载
{
string existpath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
if (!File.Exists(existpath)) // 文件不存在
{
using FileStream fs = new FileStream(existpath, FileMode.Create, FileAccess.ReadWrite);
return false;
}
else // 文件存在
{
using FileStream fs = new FileStream(existpath, FileMode.Open, FileAccess.Read);
using StreamReader sr = new StreamReader(fs);
string json = sr.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
var dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json);
if (dict == null || !dict.ContainsKey("download") || "false" == dict["download"])
{
return false;
}
else if (dict["download"] == "true")
{
return true;
}
else
{
return false;
}
}
}
public static void DownloadAll() // 下载全部文件
{
string jsonName = "hash.json";
string json;
Tencent_cos_download Downloader = new Tencent_cos_download();
try
{
// 如果json存在就删了重新下
if (File.Exists(System.IO.Path.Combine(Data.FilePath, jsonName)))
{
File.Delete(System.IO.Path.Combine(Data.FilePath, jsonName));
Downloader.download(System.IO.Path.Combine(Data.FilePath, jsonName), jsonName);
}
else
{
Downloader.download(System.IO.Path.Combine(Data.FilePath, jsonName), jsonName);
}
}
catch (CosClientException clientEx)
{
// 请求失败
Console.WriteLine("CosClientException: " + clientEx.ToString() + Environment.NewLine);
return;
}
catch (CosServerException serverEx)
{
// 请求失败
Console.WriteLine("CosClientException: " + serverEx.ToString() + Environment.NewLine);
return;
}
using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, jsonName)))
json = r.ReadToEnd();
json = json.Replace("\r", string.Empty).Replace("\n", string.Empty);
// var jsonDict = Utils.DeserializeJson<Dictionary1<string, string>>(json);
newFileName.Clear();
updateFileName.Clear();
newFileName.Enqueue("THUAI6.tar.gz");
Download();
Stream? inStream = null;
Stream? gzipStream = null;
TarArchive? tarArchive = null;
try
{
using (inStream = File.OpenRead(System.IO.Path.Combine(Data.FilePath, "THUAI6.tar.gz")))
{
using (gzipStream = new GZipInputStream(inStream))
{
tarArchive = TarArchive.CreateInputTarArchive(gzipStream);
tarArchive.ExtractContents(Data.FilePath);
tarArchive.Close();
}
}
}
catch
{
//出错
}
finally
{
if (null != tarArchive) tarArchive.Close();
if (null != gzipStream) gzipStream.Close();
if (null != inStream) inStream.Close();
}
FileInfo fileInfo = new FileInfo(System.IO.Path.Combine(Data.FilePath, "THUAI6.tar.gz"));
fileInfo.Delete();
string json2;
Dictionary<string, string>? dict;
string existpath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
using FileStream fs = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite);
using (StreamReader r = new StreamReader(fs))
{
json2 = r.ReadToEnd();
if (json2 == null || json2 == "")
{
json2 += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json2);
if (dict == null || !dict.ContainsKey("download"))
{
dict?.Add("download", "true");
}
else
{
dict["download"] = "true";
}
}
using FileStream fs2 = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs2);
fs2.SetLength(0);
sw.Write(JsonConvert.SerializeObject(dict));
Check(SettingsModel.UsingOS.Win);
Download();
if (File.Exists(Data.FilePath + "/THUAI6/AI.cpp"))
{
FileInfo userCpp = new FileInfo((Data.FilePath + "/THUAI6/AI.cpp").Replace("/", "\\"));
userCpp.MoveTo(Data.FilePath + "/THUAI6/win/CAPI/cpp/API/src/AI.cpp", true);
}
if (File.Exists(Data.FilePath + "/THUAI6/AI.py"))
{
FileInfo userCpp = new FileInfo((Data.FilePath + "/THUAI6/AI.py").Replace("/", "\\"));
userCpp.MoveTo(Data.FilePath + "/THUAI6/win/CAPI/python/PyAPI/AI.cpp", true);
}
}
public static void Change_all_hash(string topDir, Dictionary<string, string> jsonDict) // 更改HASH
{
DirectoryInfo theFolder = new DirectoryInfo(@topDir);
bool ifexist = false;
// 遍历文件
foreach (FileInfo NextFile in theFolder.GetFiles())
{
string filepath = topDir + @"/" + NextFile.Name; // 文件路径
//Console.WriteLine(filepath);
foreach (KeyValuePair<string, string> pair in jsonDict)
{
if (System.IO.Path.Equals(filepath, System.IO.Path.Combine(Data.FilePath, pair.Key).Replace('\\', '/')))
{
ifexist = true;
string MD5 = GetFileMd5Hash(filepath);
jsonDict[pair.Key] = MD5;
}
}
if (!ifexist && NextFile.Name != "hash.json")
{
string MD5 = GetFileMd5Hash(filepath);
string relapath = filepath.Replace(Data.FilePath + '/', string.Empty);
jsonDict.Add(relapath, MD5);
}
ifexist = false;
}
// 遍历文件夹
foreach (DirectoryInfo NextFolder in theFolder.GetDirectories())
{
if (System.IO.Path.Equals(NextFolder.FullName, System.IO.Path.GetFullPath(System.IO.Path.Combine(Data.FilePath, playerFolder))))
{
foreach (FileInfo NextFile in NextFolder.GetFiles())
{
if (NextFile.Name == "AI.cpp" || NextFile.Name == "AI.py")
{
string MD5 = GetFileMd5Hash(NextFile.FullName);
string relapath = NextFile.FullName.Replace('\\', '/').Replace(Data.FilePath + '/', string.Empty);
jsonDict.Add(relapath, MD5);
}
}
continue; // 如果是选手文件夹就忽略
}
Change_all_hash(NextFolder.FullName.Replace('\\', '/'), jsonDict);
}
}
public static void UpdateHash()
{
while (true)
{
if (Directory.Exists(Data.FilePath))
{
string json;
if (!File.Exists(System.IO.Path.Combine(Data.FilePath, "hash.json")))
{
Console.WriteLine("hash.json文件丢失即将重新下载该文件");
GetNewHash();
}
using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, "hash.json")))
json = r.ReadToEnd();
json = json.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("/", @"\\");
Dictionary<string, string> jsonDict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
Change_all_hash(Data.FilePath, jsonDict);
OverwriteHash(jsonDict);
break;
}
else
{
Console.WriteLine("读取路径失败!请重新输入文件路径:");
Data.ResetFilepath(Console.ReadLine() ?? "");
}
}
}
public static int DeleteAll()
{
DirectoryInfo di = new DirectoryInfo(Data.FilePath + "/THUAI6");
//DirectoryInfo player = new DirectoryInfo(System.IO.Path.GetFullPath(System.IO.Path.Combine(Data.FilePath, playerFolder)));
FileInfo[] allfile = di.GetFiles();
try
{
foreach (FileInfo file in allfile)
{
//if(file.Name == "AI.cpp" || file.Name == "AI.py")
//{
// string filename = System.IO.Path.GetFileName(file.FullName);
// file.MoveTo(System.IO.Path.Combine(Data.FilePath, filename));
// continue;
//}
file.Delete();
}
FileInfo userFileCpp = new FileInfo(Data.FilePath + "/THUAI6/win/CAPI/cpp/API/src/AI.cpp");
FileInfo userFilePy = new FileInfo(Data.FilePath + "/THUAI6/win/CAPI/python/PyAPI/AI.py");
userFileCpp.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", System.IO.Path.GetFileName(userFileCpp.FullName)));
userFilePy.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", System.IO.Path.GetFileName(userFilePy.FullName)));
foreach (DirectoryInfo subdi in di.GetDirectories())
{
subdi.Delete(true);
}
FileInfo hashFile = new FileInfo(Data.FilePath + "/hash.json");
hashFile.Delete();
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("权限不足,无法删除!");
return -2;
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("文件夹没有找到,请检查是否已经手动更改路径");
return -3;
}
catch (IOException)
{
Console.WriteLine("文件已经打开,请关闭后再删除");
return -1;
}
string json2;
Dictionary<string, string>? dict;
string existpath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
using FileStream fs = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite);
using (StreamReader r = new StreamReader(fs))
{
json2 = r.ReadToEnd();
if (json2 == null || json2 == "")
{
json2 += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json2);
if (dict == null || !dict.ContainsKey("download"))
{
dict?.Add("download", "false");
}
else
{
dict["download"] = "false";
}
}
using FileStream fs2 = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs2);
fs2.SetLength(0);
sw.Write(JsonConvert.SerializeObject(dict));
sw.Close();
fs2.Close();
try
{
File.Delete(Data.path);
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("权限不足,无法删除!");
return -2;
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("文件夹没有找到,请检查是否已经手动更改路径");
return -3;
}
catch (IOException)
{
Console.WriteLine("文件已经打开,请关闭后再删除");
return -1;
}
return 0;
}
public static void OverwriteHash(Dictionary<string, string> jsonDict)
{
string Contentjson = JsonConvert.SerializeObject(jsonDict);
Contentjson = Contentjson.Replace("\r", String.Empty).Replace("\n", String.Empty).Replace(@"\\", "/");
File.WriteAllText(@System.IO.Path.Combine(Data.FilePath, "hash.json"), Contentjson);
}
public static int MoveProgram(string newPath)
{
DirectoryInfo newdi = new DirectoryInfo(newPath + "/THUAI6");
DirectoryInfo olddi = new DirectoryInfo(Data.FilePath + "/THUAI6");
try
{
if (!Directory.Exists(newPath + "/THUAI6"))
Directory.CreateDirectory(newPath + "/THUAI6");
foreach (DirectoryInfo direct in olddi.GetDirectories())
{
direct.MoveTo(System.IO.Path.Combine(newPath + "/THUAI6", direct.Name));
}
foreach (FileInfo file in olddi.GetFiles())
{
file.MoveTo(System.IO.Path.Combine(newPath + "/THUAI6", file.Name));
}
olddi.Delete();
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("原路径未找到!请检查文件是否损坏");
if (newdi.GetDirectories().Length != 0)
{
foreach (DirectoryInfo newdirect in newdi.GetDirectories())
{
newdirect.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", newdirect.Name));
}
}
if (newdi.GetFiles().Length != 0)
{
foreach (FileInfo file in newdi.GetFiles())
{
file.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", file.Name));
}
}
Console.WriteLine("移动失败!");
if (newdi.Exists)
newdi.Delete();
return -2;
}
catch (IOException)
{
Console.WriteLine("文件已打开或者目标路径下有同名文件!");
if (newdi.GetDirectories().Length != 0)
{
foreach (DirectoryInfo newdirect in newdi.GetDirectories())
{
newdirect.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", newdirect.Name));
}
}
if (newdi.GetFiles().Length != 0)
{
foreach (FileInfo file in newdi.GetFiles())
{
file.MoveTo(System.IO.Path.Combine(Data.FilePath + "/THUAI6", file.Name));
}
}
if (newdi.Exists)
newdi.Delete();
Console.WriteLine("移动失败!");
return -1;
}
FileInfo hashFile = new FileInfo(Data.FilePath + "/hash.json");
hashFile.MoveTo(newPath + "/hash.json");
Data.ResetFilepath(newPath);
Console.WriteLine("更改路径成功!");
return 0;
}
public static async Task main(string[] args)
{
var client = new HttpClient();
var web = new WebConnect.Web();
Data date = new Data("");
while (true)
{
Console.WriteLine($"1. 更新hash.json 2. 检查更新 3.下载{ProgramName} 4.删除{ProgramName} 5.启动进程 6.移动{ProgramName}到其它路径");
string choose = Console.ReadLine() ?? "";
if (choose == "1")
{
if (!CheckAlreadyDownload())
{
Console.WriteLine($"未下载{ProgramName},请先执行下载操作!");
continue;
}
UpdateHash();
}
else if (choose == "2")
{
if (!CheckAlreadyDownload())
{
Console.WriteLine($"未下载{ProgramName},请先执行下载操作!");
continue;
}
while (true)
{
if (Data.FilePath != null && Directory.Exists(Data.FilePath))
{
Check(SettingsModel.UsingOS.Win);
break;
}
else
{
Console.WriteLine("读取路径失败!请重新输入文件路径:");
Data.ResetFilepath(Console.ReadLine() ?? "");
}
}
}
else if (choose == "3")
{
if (CheckAlreadyDownload())
{
Console.WriteLine($"已经将{ProgramName}下载到{Data.FilePath}!若要重新下载请先完成删除操作!");
}
else
{
string newpath;
Console.WriteLine("请输入下载路径:");
newpath = Console.ReadLine() ?? "";
Data.ResetFilepath(newpath);
DownloadAll();
}
}
else if (choose == "4")
{
DeleteAll();
}
else if (choose == "5")
{
if (CheckAlreadyDownload())
{
Process.Start(System.IO.Path.Combine(Data.FilePath, startName));
}
else
{
Console.WriteLine($"未下载{ProgramName},请先执行下载操作!");
}
}
else if (choose == "6")
{
string newPath;
newPath = Console.ReadLine() ?? "";
MoveProgram(newPath);
}
else if (choose == "7")
{
Console.WriteLine("请输入email");
string username = Console.ReadLine() ?? "";
Console.WriteLine("请输入密码:");
string password = Console.ReadLine() ?? "";
await web.LoginToEEsast(client, username, password);
}
else if (choose == "8")
{
await web.UserDetails(client);
}
else if (choose == "9")
{
await web.UploadFiles(client, "", "", "");
}
else if (choose == "exit")
{
return;
}
}
}
public static int CheckSelfVersion()
{
string keyHead = "Installer/";
Tencent_cos_download downloader = new Tencent_cos_download();
string hashName = "installerHash.json";
string dir = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)
?? throw new Exception("Failed to get current directory");
int result = 0;
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);
var jsonDict = Utils.TryDeserializeJson<Dictionary<string, string>>(json);
string md5 = "";
List<string> awaitUpdate = new List<string>();
if (jsonDict != null)
{
foreach (KeyValuePair<string, string> pair in jsonDict)
{
md5 = GetFileMd5Hash(System.IO.Path.Combine(dir, pair.Key));
if (md5.Length == 0) // 文档不存在
{
downloader.download(System.IO.Path.Combine(dir, pair.Key), keyHead + pair.Key);
}
else if (md5.Equals("conflict"))
{
MessageBox.Show($"检查{pair.Key}更新时遇到问题,请反馈", "读取出错", MessageBoxButton.OK, MessageBoxImage.Error);
}
else if (md5 != pair.Value) // MD5不匹配
{
if (pair.Key.Substring(0, 12).Equals("InstallerUpd"))
{
File.Delete(System.IO.Path.Combine(dir, pair.Key));
downloader.download(System.IO.Path.Combine(dir, pair.Key), keyHead + pair.Key);
}
else
{
result = 1;
awaitUpdate = awaitUpdate.Append(pair.Key).ToList();
}
}
}
}
else
return -1;
string Contentjson = JsonConvert.SerializeObject(awaitUpdate);
Contentjson = Contentjson.Replace("\r", String.Empty).Replace("\n", String.Empty).Replace(@"\\", "/");
File.WriteAllText(@System.IO.Path.Combine(dir, "updateList.json"), Contentjson);
return result;
}
static public bool SelfUpdateDismissed()
{
string json;
string dir = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)
?? throw new Exception("Failed to get directory!");
if (!File.Exists(System.IO.Path.Combine(dir, "updateList.json")))
return false;
using (StreamReader r = new StreamReader(System.IO.Path.Combine(dir, "updateList.json")))
json = r.ReadToEnd();
json = json.Replace("\r", string.Empty).Replace("\n", string.Empty);
List<string>? jsonList;
if (json != null)
jsonList = Utils.TryDeserializeJson<List<string>>(json);
else
return false;
if (jsonList != null && jsonList.Contains("Dismiss"))
{
listJsonClear(System.IO.Path.Combine(dir, "updateList.json"));
return true;
}
return false;
}
static private void listJsonClear(string directory)
{
List<string> list = new List<string>();
list.Add("None");
StreamWriter sw = new StreamWriter(directory, false);
sw.WriteLine(JsonConvert.SerializeObject(list));
sw.Close();
}
}
public class RunProgram
{
public enum RunMode
{
ServerOnly, //只启动Server
ServerForDebugOnly, //只启动ServerForDebug
GUIAttendGameOnly, //只用GUIClient参与游戏
GUIVisit, //只用GUIClient观战
GUIAndAICpp, //用GUI参与游戏并且让cpp的AI同时参与
GUIAndAIPython, //用GUI参与游戏并且让python的AI同时参与
ServerAndCpp, //只运行Server和cpp
ServerAndPython, //只运行Server和python
ServerAndCppVisit, //运行Server和Cpp并用GUI观战
ServerAndPythonVisit, //运行Server和python并用GUI观战
ServerDebugAndCpp, //运行ServerForDebug...
ServerDebugAndPython,
ServerDebugAndCppVisit,
ServerDebugAndPythonVisit,
}
// !!! 目前此类的各个静态成员从未被赋值过
public class RunInfo //UI需要在调用Launch函数前保证其中数据已经更新并有效
{
public static RunMode mode = default;
public static string? IP = null;
public static int port = 0;
public static int studentCount = 0;
public static int trickerCount = 0;
public static int gameTimeSec = 0;
public static string? playbackFileName = null;
public static int characterID = 0;
public static int type = 0;
public static bool saveDebugLog = false;
public static bool showDebugLog = false;
public static bool warningOnly = false;
public static bool visiting = false;
public static int occupation = 0;
public static List<int>? playerId = new List<int>(); //两者长度必须与studentCount + trickerCount一致
public static List<string>? filePath = new List<string>();
}
/// <summary>
/// 运行cmd命令
/// 会显示命令窗口
/// </summary>
/// <param name="cmdExe">指定应用程序的完整路径</param>
/// <param name="cmdStr">执行命令行参数</param>
static bool RunCmd(string cmdExe, string cmdStr)
{
bool result = false;
try
{
using (Process myPro = new Process())
{
//指定启动进程是调用的应用程序和命令行参数
ProcessStartInfo psi = new ProcessStartInfo(cmdExe, cmdStr);
myPro.StartInfo = psi;
myPro.Start();
//myPro.WaitForExitAsync();
result = true;
}
}
catch
{
}
return result;
}
/// <summary>
/// 启动Server
/// 会显示命令窗口
/// </summary>
/// <param name="IP">指定Server运行的IPV4地址</param>
/// <param name="port">指定Server运行的端口</param>
/// <param name="studentCount">指定学生人数</param>
/// <param name="trickerCount">指定捣蛋鬼人数</param>
/// <param name="gameTimeSec">指定游戏最大时长</param>
/// <param name="playbackFileName">指定回放文件名称</param>
public static int StartServer(string? IP, int port, int studentCount, int trickerCount, int gameTimeSec, string? playbackFileName)
{
if (System.Diagnostics.Process.GetProcessesByName("Server").ToList().Count > 0)
{
System.Diagnostics.Process.GetProcessesByName("Server")[0].Kill();
}
string cmdExe = $"{Data.FilePath}\\THUAI6\\win\\win64\\Server.exe";
string cmdPara = $"--ip {IP} --port {port} --studentCount {studentCount} --trickerCount {trickerCount}" +
$" --gameTimeInSecond {gameTimeSec} --fileName {playbackFileName}";
RunCmd(cmdExe, cmdPara);
return 0;
}
/// <summary>
/// 启动Debug用的Server
/// 会显示命令窗口
/// </summary>
/// <param name="IP">指定Server运行的IPV4地址</param>
/// <param name="port">指定Server运行的端口</param>
/// <param name="studentCount">指定学生人数</param>
/// <param name="trickerCount">指定捣蛋鬼人数</param>
/// <param name="gameTimeSec">指定游戏最大时长</param>
/// <param name="playbackFileName">指定回放文件名称</param>
public static int StartServerForDebug(string? IP, int port, int studentCount, int trickerCount, int gameTimeSec, string? playbackFileName)
{
if (System.Diagnostics.Process.GetProcessesByName("Server").ToList().Count > 0)
{
System.Diagnostics.Process.GetProcessesByName("Server")[0].Kill();
}
string cmdExe = $"{Data.FilePath}\\THUAI6\\win\\win64\\Debug\\Server.exe";
string cmdPara = $"--ip {IP} --port {port} --studentCount {studentCount} --trickerCount {trickerCount} " +
$"--gameTimeInSecond {gameTimeSec} --fileName {playbackFileName}";
RunCmd(cmdExe, cmdPara);
return 0;
}
/// <summary>
/// 启动cpp在这之前要先启动Server,可能还需要一些延时
/// 会显示命令窗口
/// </summary>
/// <param name="IP">指定Server运行的IPV4地址</param>
/// <param name="port">指定Server运行的端口</param>
/// <param name="studentCount">指定学生人数</param>
/// <param name="trickerCount">指定捣蛋鬼人数</param>
/// <param name="saveDebugLog">是否保存Debug日志文件</param>
/// <param name="showDebugLog">是否将日志输出到屏幕上</param>
/// <param name="warningOnly">在showDebugLog == true时是否只输出警告或者报错不影响日志保存</param>
/// <param name="playerIp">默认为空如果不为空playerIp将会按照顺序代替默认从0~3的IP</param>
public static int RunCpp(string? IP, int port, int studentCount, int trickerCount, bool saveDebugLog,
bool showDebugLog, bool warningOnly, List<int>? playerIp = null, List<string>? filePath = null)
{
string cmdExe;
string cmdBase = $"-I {IP} -P {port} ";
for (int i = 0; i < studentCount; i++)
{
string cmdPara;
if (playerIp == null)
{
cmdPara = cmdBase + $" -p {i}";
}
else
{
cmdPara = cmdBase + $" -p {playerIp[i]}";
}
if (saveDebugLog)
{
cmdPara = cmdPara + " -d";
}
if (showDebugLog)
{
cmdPara = cmdPara + " -o";
}
if (warningOnly)
{
cmdPara = cmdPara + " -w";
}
if (filePath == null)
{
cmdExe = $"{Data.FilePath}\\THUAI6\\win\\CAPI\\cpp\\x64\\Debug\\API.exe";
}
else
{
cmdExe = filePath[i];
}
RunCmd(cmdExe, cmdPara);
}
if (trickerCount != 0)
{
string cmdPara;
cmdPara = cmdBase + " -p 4";
if (saveDebugLog)
{
cmdPara = cmdPara + " -d";
}
if (showDebugLog)
{
cmdPara = cmdPara + " -o";
}
if (warningOnly)
{
cmdPara = cmdPara + " -w";
}
if (filePath == null)
{
cmdExe = $"{Data.FilePath}\\THUAI6\\win\\CAPI\\cpp\\x64\\Debug\\API.exe";
}
else
{
cmdExe = filePath[studentCount];
}
RunCmd(cmdExe, cmdPara);
}
return 0;
}
/// <summary>
/// 启动客户端
/// 会显示命令窗口
/// </summary>
/// <param name="IP">指定Server运行的IPV4地址</param>
/// <param name="port">指定Server运行的端口</param>
/// <param name="characterID">进入游戏时的角色ID 0~40~3为学生4为捣蛋鬼</param>
/// <param name="visiting">是否观战当值为true时characterID无效</param>
/// <param name="occupation">指定参加游戏时的角色职业,详情见说明文档</param>
/// <param name="type">角色类别type = 1 表示学生type = 2 表示捣蛋鬼</param>
public static int RunGUIClient(string? IP, int port, int characterID, bool visiting, int occupation = 1, int type = 1)
{
string cmdExe = $"{Data.FilePath}\\THUAI6\\win\\win64\\Client.exe";
string cmdBase = $"--port {port} --ip {IP} --type {type} --occupation {occupation}";
if (visiting)
{
cmdBase = cmdBase + " --characterID 200000";
}
else
{
cmdBase = cmdBase + $" --characterID {characterID}";
}
cmdBase = cmdBase + " --cl";
RunCmd(cmdExe, cmdBase);
return 0;
}
//启动python参数同RunCpp
public static int RunPython(string? IP, int port, int studentCount, int trickerCount, bool saveDebugLog,
bool showDebugLog, bool warningOnly, List<int>? playerIp = null, List<string>? filePath = null)
{
string cmdExe = $"python";
string cmdBase;
for (int i = 0; i < studentCount; i++)
{
string cmdPara;
if (filePath == null)
{
cmdBase = $" {Data.FilePath}\\THUAI6\\win\\CAPI\\python\\PyAPI\\main.py -I {IP} -P {port} ";
}
else
{
cmdBase = " " + filePath[i] + $" -I {IP} -P {port} ";
}
if (playerIp == null)
{
cmdPara = cmdBase + $" -p {i}";
}
else
{
cmdPara = cmdBase + $" -p {playerIp[i]}";
}
if (saveDebugLog)
{
cmdPara = cmdPara + " -d";
}
if (showDebugLog)
{
cmdPara = cmdPara + " -o";
}
if (warningOnly)
{
cmdPara = cmdPara + " -w";
}
RunCmd(cmdExe, cmdPara);
}
if (trickerCount != 0)
{
string cmdPara;
if (filePath == null)
{
cmdBase = $" {Data.FilePath}\\THUAI6\\win\\CAPI\\python\\PyAPI\\main.py -I {IP} -P {port} ";
}
else
{
cmdBase = " " + filePath[studentCount] + $" -I {IP} -P {port} ";
}
cmdPara = cmdBase + " -p 4";
if (saveDebugLog)
{
cmdPara = cmdPara + " -d";
}
if (showDebugLog)
{
cmdPara = cmdPara + " -o";
}
if (warningOnly)
{
cmdPara = cmdPara + " -w";
}
RunCmd(cmdExe, cmdPara);
}
return 0;
}
}
}
}
namespace WebConnect
{
class Web
{
public enum language { cpp, py };
public static string logintoken = "";
async public Task<int> LoginToEEsast(HttpClient client, string useremail, string password)
{
string token = "";
try
{
using (var response = await client.PostAsync("https://api.eesast.com/users/login", JsonContent.Create(new
{
email = useremail,
password = password,
})))
{
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
//Console.WriteLine("Success login");
token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
}) as LoginResponse)
?.Token ??
throw new Exception("no token!");
logintoken = token;
SaveToken();
var info = Utils.DeserializeJson1<Dictionary<string, string>>(await response.Content.ReadAsStringAsync());
Downloader.UserInfo._id = info["_id"];
Downloader.UserInfo.email = info["email"];
break;
default:
int code = ((int)response.StatusCode);
//Console.WriteLine(code);
if (code == 401)
{
//Console.WriteLine("邮箱或密码错误!");
return -1;
}
break;
}
return 0;
}
}
catch
{
return -2;
}
}
/// <summary>
///
/// </summary>
/// <param name="client">http client</param>
/// <param name="tarfile">代码源位置</param>
/// <param name="type">编程语言,格式为"cpp"或"python"</param>
/// <param name="plr">第x位玩家格式为"player_x"</param>
/// <returns>-1:tokenFail;-2:FileNotExist;-3:CosFail;-4:loginTimeout;-5:Fail;-6:ReadFileFail;-7:networkError</returns>
async public Task<int> UploadFiles(HttpClient client, string tarfile, string type, string plr) //用来上传文件
{
if (!ReadToken()) //读取token失败
{
return -1;
}
try
{
string content;
client.DefaultRequestHeaders.Authorization = new("Bearer", logintoken);
if (!File.Exists(tarfile))
{
//Console.WriteLine("文件不存在!");
return -2;
}
using FileStream fs = new FileStream(tarfile, FileMode.Open, FileAccess.Read);
using StreamReader sr = new StreamReader(fs);
content = sr.ReadToEnd();
string targetUrl = $"https://api.eesast.com/static/player?team_id={await GetTeamId()}";
using (var response = await client.GetAsync(targetUrl))
{
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
var res = Utils.DeserializeJson1<Dictionary<string, string>>(await response.Content.ReadAsStringAsync());
string appid = "1255334966"; // 设置腾讯云账户的账户标识APPID
string region = "ap-beijing"; // 设置一个默认的存储桶地域
CosXmlConfig config = new CosXmlConfig.Builder()
.IsHttps(true) // 设置默认 HTTPS 请求
.SetAppid(appid) // 设置腾讯云账户的账户标识 APPID
.SetRegion(region) // 设置一个默认的存储桶地域
.SetDebugLog(true) // 显示日志
.Build(); // 创建 CosXmlConfig 对象
string tmpSecretId = res["TmpSecretId"]; //"临时密钥 SecretId";
string tmpSecretKey = res["TmpSecretKey"]; //"临时密钥 SecretKey";
string tmpToken = res["SecurityToken"]; //"临时密钥 token";
long tmpExpiredTime = Convert.ToInt64(res["ExpiredTime"]); //临时密钥有效截止时间,精确到秒
QCloudCredentialProvider cosCredentialProvider = new DefaultSessionQCloudCredentialProvider(
tmpSecretId, tmpSecretKey, tmpExpiredTime, tmpToken
);
// 初始化 CosXmlServer
CosXmlServer cosXml = new CosXmlServer(config, cosCredentialProvider);
// 初始化 TransferConfig
TransferConfig transferConfig = new TransferConfig();
// 初始化 TransferManager
TransferManager transferManager = new TransferManager(cosXml, transferConfig);
string bucket = "eesast-1255334966"; //存储桶格式BucketName-APPID
string cosPath = $"/THUAI6/{GetTeamId()}/{type}/{plr}"; //对象在存储桶中的位置标识符,即称对象键
string srcPath = tarfile;//本地文件绝对路径
// 上传对象
COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, cosPath);
uploadTask.SetSrcPath(srcPath);
uploadTask.progressCallback = delegate (long completed, long total)
{
//Console.WriteLine(string.Format("progress = {0:##.##}%", completed * 100.0 / total));
};
try
{
COSXMLUploadTask.UploadTaskResult result = await transferManager.UploadAsync(uploadTask);
//Console.WriteLine(result.GetResultInfo());
string eTag = result.eTag;
//到这里应该是成功了但是因为我没有试过也不知道具体情况可能还要根据result的内容判断
}
catch (Exception)
{
return -3;
}
break;
case System.Net.HttpStatusCode.Unauthorized:
//Console.WriteLine("您未登录或登录过期,请先登录");
return -4;
default:
//Console.WriteLine("上传失败!");
return -5;
}
}
}
catch (IOException)
{
//Console.WriteLine("文件读取错误!请检查文件是否被其它应用占用!");
return -6;
}
catch
{
//Console.WriteLine("请求错误!请检查网络连接!");
return -7;
}
return 0;
}
async public Task UserDetails(HttpClient client) // 用来测试访问网站
{
if (!ReadToken()) // 读取token失败
{
return;
}
try
{
client.DefaultRequestHeaders.Authorization = new("Bearer", logintoken);
Console.WriteLine(logintoken);
using (var response = await client.GetAsync("https://api.eesast.com/application/info")) // JsonContent.Create(new
//{
//})))
{
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
Console.WriteLine("Require OK");
Console.WriteLine(await response.Content.ReadAsStringAsync());
break;
default:
int code = ((int)response.StatusCode);
if (code == 401)
{
Console.WriteLine("您未登录或登录过期,请先登录");
}
return;
}
}
}
catch
{
Console.WriteLine("请求错误!请检查网络连接!");
}
}
public void SaveToken() // 保存token
{
string savepath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
try
{
string json;
Dictionary<string, string> dict = new Dictionary<string, string>();
using FileStream fs = new FileStream(savepath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
using (StreamReader r = new StreamReader(fs))
{
json = r.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
if (dict.ContainsKey("token"))
{
dict.Remove("token");
}
dict.Add("token", logintoken);
}
using FileStream fs2 = new FileStream(savepath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
using StreamWriter sw = new StreamWriter(fs2);
fs2.SetLength(0);
sw.Write(JsonConvert.SerializeObject(dict)); //将token写入文件
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("保存token时未找到下载器地址请检查下载器是否被移动");
}
catch (PathTooLongException)
{
Console.WriteLine("下载器的路径名太长!请尝试移动下载器!");
}
catch (ArgumentNullException)
{
Console.WriteLine("下载器路径初始化失败!");
}
catch (IOException)
{
Console.WriteLine("写入token.dat发生冲突请检查token.dat是否被其它程序占用");
}
}
public static int WriteJson(string key, string data)
{
try
{
string savepath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
FileStream fs = new FileStream(savepath, FileMode.Open, FileAccess.ReadWrite);
StreamReader sr = new StreamReader(fs);
string json = sr.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
Dictionary<string, string> dict = new Dictionary<string, string>();
dict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
if (!dict.ContainsKey(key))
{
dict.Add(key, data);
}
else
{
dict[key] = data;
}
sr.Close();
fs.Close();
FileStream fs2 = new FileStream(savepath, FileMode.Open, FileAccess.ReadWrite);
StreamWriter sw = new StreamWriter(fs2);
sw.WriteLine(JsonConvert.SerializeObject(dict));
sw.Close();
fs2.Close();
return 0;//成功
}
catch
{
return -1;//失败
}
}
public static string? ReadJson(string key)
{
try
{
string savepath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
FileStream fs = new FileStream(savepath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
string json = sr.ReadToEnd();
Dictionary<string, string> dict = new Dictionary<string, string>();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
fs.Close();
sr.Close();
return dict[key];
}
catch
{
return null; //文件不存在或者已被占用
}
}
public bool ReadToken() // 读取token
{
try
{
string json;
Dictionary<string, string> dict = new Dictionary<string, string>();
string savepath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json");
using FileStream fs = new FileStream(savepath, FileMode.Open, FileAccess.Read);
using StreamReader sr = new StreamReader(fs);
json = sr.ReadToEnd();
if (json == null || json == "")
{
json += @"{""THUAI6""" + ":" + @"""2023""}";
}
dict = Utils.DeserializeJson1<Dictionary<string, string>>(json);
if (!dict.ContainsKey("token"))
{
return false;
}
else
{
logintoken = dict["token"];
return true;
}
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("读取token时未找到下载器地址请检查下载器是否被移动");
return false;
}
catch (FileNotFoundException)
{
//没有登陆
Console.WriteLine("请先登录!");
return false;
}
catch (PathTooLongException)
{
Console.WriteLine("下载器的路径名太长!请尝试移动下载器!");
return false;
}
catch (ArgumentNullException)
{
Console.WriteLine("下载器路径初始化失败!");
return false;
}
catch (IOException)
{
Console.WriteLine("写入token.dat发生冲突请检查token.dat是否被其它程序占用");
return false;
}
}
async public Task<string> GetTeamId()
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.eesast.com/dev/v1/graphql");
request.Headers.Add("x-hasura-admin-secret", "hasuraDevAdminSecret");
//var content = new StringContent($@"
// {{
// ""query"": ""query MyQuery {{contest_team_member(where: {{user_id: {{_eq: \""{Downloader.UserInfo._id}\""}}}}) {{ team_id }}}}"",
// ""variables"": {{}},
// }}", null, "application/json");
var content = new StringContent("{\"query\":\"query MyQuery {\\r\\n contest_team_member(where: {user_id: {_eq: \\\"" + Downloader.UserInfo._id + "\\\"}}) {\\r\\n team_id\\r\\n }\\r\\n}\",\"variables\":{}}", null, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var info = await response.Content.ReadAsStringAsync();
var s1 = Utils.DeserializeJson1<Dictionary<string, object>>(info)["data"];
var s2 = Utils.DeserializeJson1<Dictionary<string, List<object>>>(s1.ToString() ?? "")["contest_team_member"];
var sres = Utils.DeserializeJson1<Dictionary<string, string>>(s2[0].ToString() ?? "")["team_id"];
return sres;
}
async public Task<string> GetUserId(string learnNumber)
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.eesast.com/dev/v1/graphql");
request.Headers.Add("x-hasura-admin-secret", "hasuraDevAdminSecret");
var content = new StringContent("{\"query\":\"query MyQuery {\r\n user(where: {id: {_eq: \""
+ learnNumber + "\"}}) {\r\n _id\r\n }\r\n}\r\n\",\"variables\":{}}", null, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
[Serializable]
record LoginResponse
{
// Map `Token` to `token` when serializing
public string Token { get; set; } = "";
}
internal static class Utils
{
public static T DeserializeJson1<T>(string json)
where T : notnull
{
return JsonConvert.DeserializeObject<T>(json)
?? throw new Exception("Failed to deserialize json.");
}
public static T? TryDeserializeJson<T>(string json)
where T : notnull
{
return JsonConvert.DeserializeObject<T>(json);
}
}
}