diff --git a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs index 7cad45a..ebe73f9 100644 --- a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs +++ b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.Designer.cs @@ -31,14 +31,16 @@ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormLiteLoaderQQNT)); this.splitContainer1 = new System.Windows.Forms.SplitContainer(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.btnChoose = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); this.btnCheckUpdateAll = new System.Windows.Forms.Button(); this.btnPath = new System.Windows.Forms.Button(); this.btnRestore = new System.Windows.Forms.Button(); this.txtQQNTPath = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.btnChoose = new System.Windows.Forms.Button(); this.splitter1 = new System.Windows.Forms.Splitter(); + this.cboGithubProxy = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); this.splitContainer1.Panel1.SuspendLayout(); this.splitContainer1.Panel2.SuspendLayout(); @@ -59,6 +61,7 @@ // // splitContainer1.Panel2 // + this.splitContainer1.Panel2.Controls.Add(this.cboGithubProxy); this.splitContainer1.Panel2.Controls.Add(this.btnChoose); this.splitContainer1.Panel2.Controls.Add(this.label2); this.splitContainer1.Panel2.Controls.Add(this.btnCheckUpdateAll); @@ -66,8 +69,9 @@ this.splitContainer1.Panel2.Controls.Add(this.btnRestore); this.splitContainer1.Panel2.Controls.Add(this.txtQQNTPath); this.splitContainer1.Panel2.Controls.Add(this.label1); - this.splitContainer1.Size = new System.Drawing.Size(446, 280); - this.splitContainer1.SplitterDistance = 161; + this.splitContainer1.Panel2.Controls.Add(this.label3); + this.splitContainer1.Size = new System.Drawing.Size(446, 297); + this.splitContainer1.SplitterDistance = 157; this.splitContainer1.TabIndex = 0; // // dataGridView1 @@ -82,13 +86,32 @@ this.dataGridView1.Name = "dataGridView1"; this.dataGridView1.ReadOnly = true; this.dataGridView1.RowTemplate.Height = 23; - this.dataGridView1.Size = new System.Drawing.Size(446, 161); + this.dataGridView1.Size = new System.Drawing.Size(446, 157); this.dataGridView1.TabIndex = 2; // + // btnChoose + // + this.btnChoose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnChoose.Location = new System.Drawing.Point(394, 74); + this.btnChoose.Name = "btnChoose"; + this.btnChoose.Size = new System.Drawing.Size(38, 23); + this.btnChoose.TabIndex = 6; + this.btnChoose.Text = "..."; + this.btnChoose.UseVisualStyleBackColor = true; + this.btnChoose.Click += new System.EventHandler(this.btnChoose_Click); + // + // label2 + // + this.label2.Location = new System.Drawing.Point(12, 11); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(424, 26); + this.label2.TabIndex = 5; + this.label2.Text = "这只是一个安装器,所有功能都来自于 LiteLoaderQQNT 和其相关插件。"; + // // btnCheckUpdateAll // - this.btnCheckUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.btnCheckUpdateAll.Location = new System.Drawing.Point(12, 80); + this.btnCheckUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCheckUpdateAll.Location = new System.Drawing.Point(357, 45); this.btnCheckUpdateAll.Name = "btnCheckUpdateAll"; this.btnCheckUpdateAll.Size = new System.Drawing.Size(75, 23); this.btnCheckUpdateAll.TabIndex = 4; @@ -99,7 +122,7 @@ // btnPath // this.btnPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnPath.Location = new System.Drawing.Point(359, 80); + this.btnPath.Location = new System.Drawing.Point(359, 101); this.btnPath.Name = "btnPath"; this.btnPath.Size = new System.Drawing.Size(75, 23); this.btnPath.TabIndex = 3; @@ -110,7 +133,7 @@ // btnRestore // this.btnRestore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnRestore.Location = new System.Drawing.Point(278, 80); + this.btnRestore.Location = new System.Drawing.Point(278, 101); this.btnRestore.Name = "btnRestore"; this.btnRestore.Size = new System.Drawing.Size(75, 23); this.btnRestore.TabIndex = 2; @@ -122,7 +145,7 @@ // this.txtQQNTPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.txtQQNTPath.Location = new System.Drawing.Point(97, 53); + this.txtQQNTPath.Location = new System.Drawing.Point(95, 74); this.txtQQNTPath.Name = "txtQQNTPath"; this.txtQQNTPath.Size = new System.Drawing.Size(293, 21); this.txtQQNTPath.TabIndex = 1; @@ -130,44 +153,44 @@ // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 56); + this.label1.Location = new System.Drawing.Point(10, 77); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(89, 12); this.label1.TabIndex = 0; this.label1.Text = "QQNT安装路径:"; // - // label2 - // - this.label2.Location = new System.Drawing.Point(12, 11); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(424, 26); - this.label2.TabIndex = 5; - this.label2.Text = "这只是一个安装器,所有功能都来自于 LiteLoaderQQNT 和其相关插件。"; - // - // btnChoose - // - this.btnChoose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnChoose.Location = new System.Drawing.Point(396, 53); - this.btnChoose.Name = "btnChoose"; - this.btnChoose.Size = new System.Drawing.Size(38, 23); - this.btnChoose.TabIndex = 6; - this.btnChoose.Text = "..."; - this.btnChoose.UseVisualStyleBackColor = true; - this.btnChoose.Click += new System.EventHandler(this.btnChoose_Click); - // // splitter1 // this.splitter1.Location = new System.Drawing.Point(0, 0); this.splitter1.Name = "splitter1"; - this.splitter1.Size = new System.Drawing.Size(3, 280); + this.splitter1.Size = new System.Drawing.Size(3, 297); this.splitter1.TabIndex = 1; this.splitter1.TabStop = false; // + // cboGithubProxy + // + this.cboGithubProxy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cboGithubProxy.FormattingEnabled = true; + this.cboGithubProxy.Location = new System.Drawing.Point(95, 48); + this.cboGithubProxy.Name = "cboGithubProxy"; + this.cboGithubProxy.Size = new System.Drawing.Size(256, 20); + this.cboGithubProxy.TabIndex = 7; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(9, 51); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(65, 12); + this.label3.TabIndex = 8; + this.label3.Text = "更新代理:"; + // // FormLiteLoaderQQNT // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(446, 280); + this.ClientSize = new System.Drawing.Size(446, 297); this.Controls.Add(this.splitter1); this.Controls.Add(this.splitContainer1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); @@ -196,5 +219,7 @@ private System.Windows.Forms.Label label2; private System.Windows.Forms.Button btnChoose; private System.Windows.Forms.Splitter splitter1; + private System.Windows.Forms.ComboBox cboGithubProxy; + private System.Windows.Forms.Label label3; } } \ No newline at end of file diff --git a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs index 22ee354..49740fc 100644 --- a/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs +++ b/RevokeMsgPatcher/Forms/FormLiteLoaderQQNT.cs @@ -1,19 +1,15 @@ -using System; +using Newtonsoft.Json; +using RevokeMsgPatcher.Model; +using RevokeMsgPatcher.Utils; +using System; using System.Collections.Generic; -using System.ComponentModel; using System.Data; using System.Diagnostics; -using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using System.Xml.Linq; -using Newtonsoft.Json; -using RevokeMsgPatcher.Model; -using RevokeMsgPatcher.Modifier; -using RevokeMsgPatcher.Utils; namespace RevokeMsgPatcher.Forms { @@ -26,6 +22,28 @@ namespace RevokeMsgPatcher.Forms InitializeComponent(); InitializeDataGridView(); txtQQNTPath.Text = FindInstallPath(); + + InitCboProxyList(); + } + + private void InitCboProxyList() + { + // 添加代理 URL 到下拉菜单 + foreach (var proxy in ProxySpeedTester.ProxyUrls) + { + cboGithubProxy.Items.Add(proxy); + } + + // 异步测试代理速度并设置默认选项 + Task.Run(async () => + { + var fastestProxy = await ProxySpeedTester.GetFastestProxyAsync(); + Debug.WriteLine(fastestProxy); + if (!string.IsNullOrEmpty(fastestProxy)) + { + cboGithubProxy.Invoke(new Action(() => cboGithubProxy.SelectedItem = fastestProxy)); + } + }); } @@ -150,7 +168,8 @@ namespace RevokeMsgPatcher.Forms } data[e.RowIndex].Row.Cells["StatusColumn"].Value = "正在更新"; - Task.Run(() => data[e.RowIndex].CheckAndUpdate()); + var proxyUrl = cboGithubProxy.Text; + Task.Run(() => data[e.RowIndex].CheckAndUpdate(proxyUrl)); } else if (e.ColumnIndex == dataGridView1.Columns["NameColumn"].Index || e.ColumnIndex == dataGridView1.Columns["AuthorColumn"].Index) { @@ -162,9 +181,10 @@ namespace RevokeMsgPatcher.Forms private void btnCheckUpdateAll_Click(object sender, EventArgs e) { + var proxyUrl = cboGithubProxy.Text; foreach (var item in data) { - Task.Run(() => item.CheckAndUpdate()); + Task.Run(() => item.CheckAndUpdate(proxyUrl)); } } @@ -176,6 +196,7 @@ namespace RevokeMsgPatcher.Forms MessageBox.Show("请选择正确的QQNT安装路径!"); return; } + try { string appPath = GetAppPath(installPath); diff --git a/RevokeMsgPatcher/Model/LiteLoaderRowData.cs b/RevokeMsgPatcher/Model/LiteLoaderRowData.cs index 8ebfb90..76b539c 100644 --- a/RevokeMsgPatcher/Model/LiteLoaderRowData.cs +++ b/RevokeMsgPatcher/Model/LiteLoaderRowData.cs @@ -127,11 +127,12 @@ namespace RevokeMsgPatcher.Model } } - public async Task GetRemoteVersion() + public async Task GetRemoteVersion(string proxyUrl = null) { using (var client = new HttpClient()) { - var response = await client.GetAsync(VersionJsonUrl); + var url = string.IsNullOrEmpty(proxyUrl) ? VersionJsonUrl : proxyUrl + "/" + VersionJsonUrl; + var response = await client.GetAsync(url); if (response.IsSuccessStatusCode) { var json = await response.Content.ReadAsStringAsync(); @@ -143,7 +144,7 @@ namespace RevokeMsgPatcher.Model } } - public async Task CheckAndUpdate() + public async Task CheckAndUpdate(string proxyUrl = null) { try { @@ -153,13 +154,15 @@ namespace RevokeMsgPatcher.Model } string localVersion = GetLocalVersion(); - string remoteVersion = await GetRemoteVersion(); + string remoteVersion = await GetRemoteVersion(proxyUrl); if (localVersion == null || new Version(remoteVersion) > new Version(localVersion)) { UpdateStatus($"存在新版本{remoteVersion},正在下载..."); Debug.WriteLine("发现新版本,正在下载..."); - string downloadedFilePath = await DownloadLatestPackage(DownloadUrl.Replace("#{version}", remoteVersion), Path.Combine(Application.StartupPath, "Public/Download")); + var url = DownloadUrl.Replace("#{version}", remoteVersion); + url = string.IsNullOrEmpty(proxyUrl) ? url : proxyUrl + "/" + url; + string downloadedFilePath = await DownloadLatestPackage(url, Path.Combine(Application.StartupPath, "Public/Download")); Debug.WriteLine("下载到:" + downloadedFilePath); UpdateStatus($"下载成功,解压中..."); @@ -170,6 +173,7 @@ namespace RevokeMsgPatcher.Model { Directory.Delete(extractPath, true); } + Directory.CreateDirectory(extractPath); ZipFile.ExtractToDirectory(downloadedFilePath, extractPath); @@ -190,10 +194,12 @@ namespace RevokeMsgPatcher.Model { File.Delete(downloadedFilePath); } + if (Directory.Exists(extractPath)) { Directory.Delete(extractPath, true); } + Debug.WriteLine("清理完成。"); UpdateStatus($"{remoteVersion}更新完成"); } @@ -208,7 +214,6 @@ namespace RevokeMsgPatcher.Model Debug.WriteLine(e.ToString()); UpdateStatus(Status + " 后发生异常:" + e.Message); } - } private string FindDirectoryWithJson(string extractPath, int maxDepth = 2) diff --git a/RevokeMsgPatcher/RevokeMsgPatcher.csproj b/RevokeMsgPatcher/RevokeMsgPatcher.csproj index 636b276..c5ca5c3 100644 --- a/RevokeMsgPatcher/RevokeMsgPatcher.csproj +++ b/RevokeMsgPatcher/RevokeMsgPatcher.csproj @@ -108,6 +108,7 @@ + FormMain.cs diff --git a/RevokeMsgPatcher/Utils/ProxySpeedTester.cs b/RevokeMsgPatcher/Utils/ProxySpeedTester.cs new file mode 100644 index 0000000..1f4a958 --- /dev/null +++ b/RevokeMsgPatcher/Utils/ProxySpeedTester.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace RevokeMsgPatcher.Utils +{ + public class ProxySpeedTester + { + private static readonly string TargetUrl = "https://raw.githubusercontent.com/LiteLoaderQQNT/LiteLoaderQQNT/refs/heads/main/package.json"; + + private static readonly HttpClient _httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) }; + + public static readonly List ProxyUrls = new List() + { + "https://mirror.ghproxy.com", + "https://hub.gitmirror.com", + "https://ghproxy.cc", + "https://www.ghproxy.cc", + "https://ghproxy.cn", + "https://ghproxy.net", + }; + + public static async Task GetFastestProxyAsync() + { + return await GetFastestProxyAsync(ProxyUrls); + } + + public static async Task GetFastestProxyAsync(List proxyAddresses) + { + var tasks = new List>(); + var cts = new CancellationTokenSource(); + + foreach (var proxy in proxyAddresses) + { + tasks.Add(TestProxyAsync(proxy, cts.Token)); + } + + var firstCompletedTask = await Task.WhenAny(tasks); + cts.Cancel(); // 取消所有其他请求 + + try + { + return await firstCompletedTask; // 返回第一个完成的代理地址 + } + catch (OperationCanceledException) + { + return null; // 如果第一个任务被取消,返回 null + } + } + + private static async Task TestProxyAsync(string proxyAddress, CancellationToken cancellationToken) + { + try + { + // 模拟代理测试请求 + var response = await _httpClient.GetAsync(proxyAddress, cancellationToken); + response.EnsureSuccessStatusCode(); + return proxyAddress; + } + catch (Exception) + { + return null; + } + } + } +} \ No newline at end of file