实现WebUtil

Beta 更新检查
订阅更新异常提示
This commit is contained in:
ChsBuffer
2020-07-30 02:36:29 +08:00
parent 87adf4de1e
commit f61827a575
12 changed files with 321 additions and 305 deletions

View File

@@ -1,19 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using Netch.Models.GitHubRelease;
using Netch.Utils;
using Newtonsoft.Json;
namespace Netch.Controllers
{
public class UpdateChecker
{
private const string DefaultUserAgent = @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36";
private const int DefaultGetTimeout = 30000;
public const string Owner = @"NetchX";
public const string Repo = @"Netch";
@@ -28,14 +24,14 @@ namespace Netch.Controllers
public event EventHandler NewVersionFoundFailed;
public event EventHandler NewVersionNotFound;
public async void Check(bool notifyNoFound, bool isPreRelease)
public void Check(bool notifyNoFound, bool isPreRelease)
{
try
{
var updater = new GitHubRelease(Owner, Repo);
var url = updater.AllReleaseUrl;
var json = await GetAsync(url, true);
var json = WebUtil.DownloadString(WebUtil.CreateRequest(url));
var releases = JsonConvert.DeserializeObject<List<Release>>(json);
var latestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
@@ -53,29 +49,9 @@ namespace Netch.Controllers
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
Logging.Error(e.ToString());
if (notifyNoFound) NewVersionFoundFailed?.Invoke(this, new EventArgs());
}
}
private static async Task<string> GetAsync(string url, bool useProxy, string userAgent = @"", double timeout = DefaultGetTimeout)
{
var httpClientHandler = new HttpClientHandler
{
UseProxy = useProxy
};
var httpClient = new HttpClient(httpClientHandler)
{
Timeout = TimeSpan.FromMilliseconds(timeout)
};
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add(@"User-Agent", string.IsNullOrWhiteSpace(userAgent) ? DefaultUserAgent : userAgent);
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var resultStr = await response.Content.ReadAsStringAsync();
return resultStr;
}
}
}
}

View File

@@ -77,12 +77,7 @@ namespace Netch.Forms
if (_isFirstCloseWindow)
{
// 显示提示语
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
i18N.Translate(
"Netch is now minimized to the notification bar, double click this icon to restore."),
ToolTipIcon.Info);
NotifyTip(i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."));
_isFirstCloseWindow = false;
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
@@ -10,7 +12,6 @@ using Netch.Models;
using Netch.Utils;
using Trojan = Netch.Forms.Server.Trojan;
using VMess = Netch.Forms.Server.VMess;
using WebClient = Netch.Override.WebClient;
namespace Netch.Forms
{
@@ -97,31 +98,20 @@ namespace Netch.Forms
private void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
{
var bak_State = State;
var bak_StateText = StatusLabel.Text;
if (Global.Settings.UseProxyToUpdateSubscription && ServerComboBox.SelectedIndex == -1)
Global.Settings.UseProxyToUpdateSubscription = false;
if (Global.Settings.UseProxyToUpdateSubscription)
if (Global.Settings.UseProxyToUpdateSubscription && ServerComboBox.SelectedIndex == -1)
{
// 当前 ServerComboBox 中至少有一项
if (ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
ControlButton.Text = "...";
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
if (Global.Settings.SubscribeLink.Count > 0)
{
StatusText(i18N.Translate("Starting update subscription"));
DeleteServerPictureBox.Enabled = false;
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = false;
Task.Run(() =>
{
if (Global.Settings.UseProxyToUpdateSubscription)
@@ -131,96 +121,72 @@ namespace Netch.Forms
Remark = "ProxyUpdate",
Type = 5
};
_mainController = new MainController();
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
State = State.Starting;
if (_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode))
StatusText(i18N.Translate("Starting update subscription"));
}
else
StatusText(i18N.Translate("Starting update subscription"));
foreach (var item in Global.Settings.SubscribeLink)
Task.WaitAll(Global.Settings.SubscribeLink.Select(item => Task.Factory.StartNew(() =>
{
using var client = new WebClient();
try
{
if (!string.IsNullOrEmpty(item.UserAgent))
{
client.Headers.Add("User-Agent", item.UserAgent);
}
else
{
client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36");
}
var request = WebUtil.CreateRequest(item.Link);
if (Global.Settings.UseProxyToUpdateSubscription)
{
client.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
}
if (!string.IsNullOrEmpty(item.UserAgent)) request.UserAgent = item.UserAgent;
if (Global.Settings.UseProxyToUpdateSubscription) request.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
var response = client.DownloadString(item.Link);
var str = WebUtil.DownloadString(request);
try
{
response = ShareLink.URLSafeBase64Decode(response);
str = ShareLink.URLSafeBase64Decode(str);
}
catch (Exception)
catch
{
// ignored
}
Global.Settings.Server = Global.Settings.Server.Where(server => server.Group != item.Remark).ToList();
var result = ShareLink.Parse(response);
var result = ShareLink.Parse(str);
if (result != null)
{
foreach (var x in result)
{
x.Group = item.Remark;
}
foreach (var x in result) x.Group = item.Remark;
Global.Settings.Server.AddRange(result);
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
string.Format(i18N.Translate("Update {1} server(s) from {0}"), item.Remark, result.Count),
ToolTipIcon.Info);
}
else
{
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
string.Format(i18N.Translate("Update servers error from {0}"), item.Remark),
ToolTipIcon.Error);
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, result.Count));
}
}
catch (Exception)
catch (WebException e)
{
NotifyTip($"{i18N.TranslateFormat("Update servers error from {0}", item.Remark)}\n{e.Message}", info: false);
}
}
})).ToArray());
InitServer();
DeleteServerPictureBox.Enabled = true;
if (Global.Settings.UseProxyToUpdateSubscription)
{
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
ControlButton.Text = i18N.Translate("Start");
_mainController.Stop();
NatTypeStatusLabel.Text = "";
}
Configuration.Save();
StatusText(i18N.Translate("Subscription updated"));
NotifyTip(i18N.Translate("Subscription updated"));
if (Global.Settings.UseProxyToUpdateSubscription)
{
_mainController.Stop();
State = State.Stopped;
}
State = State.Waiting;
DeleteModePictureBox.Enabled = true;
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = true;
State = bak_State;
StatusLabel.Text = bak_StateText;
}).ContinueWith(task => { BeginInvoke(new Action(() => { UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true; })); });
UpdateServersFromSubscribeLinksToolStripMenuItem.Enabled = true;
});
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
i18N.Translate("Updating in the background"),
ToolTipIcon.Info);
NotifyTip(i18N.Translate("Updating in the background"));
}
else
{
MessageBoxX.Show(i18N.Translate("No subscription link"));
}
}
@@ -228,6 +194,98 @@ namespace Netch.Forms
#region
private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
Utils.Utils.Open(".\\");
}
private void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
DNS.Cache.Clear();
NotifyTip(i18N.Translate("DNS cache cleanup succeeded"));
});
}
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
SaveConfigs();
Task.Run(() =>
{
InitMode();
NotifyTip(i18N.Translate("Modes have been reload"));
Enabled = true;
});
}
private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateACL(true, sender);
}
private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateACL(false, sender);
}
private void UpdateACL(bool useProxy, object sender)
{
if (useProxy && ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
((ToolStripMenuItem) sender).Enabled = false;
Task.Run(async () =>
{
if (useProxy)
{
var mode = new Models.Mode
{
Remark = "ProxyUpdate",
Type = 5
};
State = State.Starting;
if (_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode))
StatusText(i18N.Translate("Updating in the background"));
}
try
{
var req = WebUtil.CreateRequest(Global.Settings.ACL);
if (useProxy)
req.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
await WebUtil.DownloadFileAsync(req, Path.Combine(Global.NetchDir, "bin\\default.acl"));
NotifyTip(i18N.Translate("ACL updated successfully"));
}
catch (Exception e)
{
NotifyTip(i18N.Translate("ACL update failed") + "\n" + e.Message, info: false);
Logging.Error("更新 ACL 失败!" + e);
if (!(e is WebException))
throw;
}
finally
{
((ToolStripMenuItem) sender).Enabled = true;
if (useProxy)
{
_mainController.Stop();
State = State.Stopped;
}
State = State.Waiting;
}
});
}
private void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
@@ -244,52 +302,15 @@ namespace Netch.Forms
}
catch (Exception e)
{
MessageBoxX.Show(e.ToString(),LogLevel.ERROR);
MessageBoxX.Show(e.ToString(), LogLevel.ERROR);
Console.WriteLine(e);
throw;
}
Enabled = true;
});
}
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
{
Enabled = false;
SaveConfigs();
Task.Run(() =>
{
InitMode();
MessageBoxX.Show(i18N.Translate("Modes have been reload"), owner: this);
Enabled = true;
});
}
private void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
{
var bak_State = State;
var bak_StateText = StatusLabel.Text;
try
{
Enabled = false;
DNS.Cache.Clear();
MessageBoxX.Show(i18N.Translate("DNS cache cleanup succeeded"), owner: this);
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
Enabled = true;
}
finally
{
State = bak_State;
StatusLabel.Text = bak_StateText;
}
}
private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
Utils.Utils.Open(@".\");
}
private void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
{
Task.Run(() =>
@@ -300,15 +321,11 @@ namespace Netch.Forms
{
Configuration.deltapall();
Configuration.addtap();
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name, i18N.Translate("Reinstall TUN/TAP driver successfully"),
ToolTipIcon.Info);
NotifyTip(i18N.Translate("Reinstall TUN/TAP driver successfully"));
}
catch
{
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name, i18N.Translate("Reinstall TUN/TAP driver failed"),
ToolTipIcon.Error);
NotifyTip(i18N.Translate("Reinstall TUN/TAP driver failed"), info: false);
}
finally
{
@@ -318,56 +335,6 @@ namespace Netch.Forms
});
}
private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
{
updateACLWithProxyToolStripMenuItem.Enabled = false;
// 当前 ServerComboBox 中至少有一项
if (ServerComboBox.SelectedIndex == -1)
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ControlButton.Enabled = SettingsButton.Enabled = false;
ControlButton.Text = "...";
Task.Run(() =>
{
var mode = new Models.Mode
{
Remark = "ProxyUpdate",
Type = 5
};
_mainController = new MainController();
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
using var client = new WebClient();
client.Proxy = new WebProxy($"http://127.0.0.1:{Global.Settings.HTTPLocalPort}");
StatusText(i18N.Translate("Updating in the background"));
try
{
client.DownloadFile(Global.Settings.ACL, "bin\\default.acl");
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name, i18N.Translate("ACL updated successfully"),
ToolTipIcon.Info);
}
catch (Exception e)
{
Logging.Error("使用代理更新 ACL 失败!" + e);
MessageBoxX.Show(i18N.Translate("ACL update failed") + "\n" + e);
}
finally
{
State = State.Waiting;
_mainController.Stop();
}
});
}
#endregion
@@ -378,12 +345,12 @@ namespace Netch.Forms
private void RelyToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("https://mega.nz/file/9OQ1EazJ#0pjJ3xt57AVLr29vYEEv15GSACtXVQOGlEOPpi_2Ico");
Utils.Utils.Open("https://mega.nz/file/9OQ1EazJ#0pjJ3xt57AVLr29vYEEv15GSACtXVQOGlEOPpi_2Ico");
}
private void VersionLabel_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
Utils.Utils.Open($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
}
private void AboutToolStripButton_Click(object sender, EventArgs e)
@@ -392,39 +359,6 @@ namespace Netch.Forms
Hide();
}
private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
{
var bak_State = State;
var bak_StateText = StatusLabel.Text;
StatusText(i18N.Translate("Starting update ACL"));
using var client = new WebClient();
client.DownloadFileTaskAsync(Global.Settings.ACL, "bin\\default.acl");
client.DownloadFileCompleted += ((sender, args) =>
{
try
{
if (args.Error == null)
{
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name, i18N.Translate("ACL updated successfully"),
ToolTipIcon.Info);
}
else
{
Logging.Error("ACL 更新失败!" + args.Error);
MessageBoxX.Show(i18N.Translate("ACL update failed") + "\n" + args.Error);
}
}
finally
{
State = bak_State;
StatusLabel.Text = bak_StateText;
}
});
}
#endregion
}
}

View File

@@ -1,5 +1,5 @@
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading.Tasks;
using Netch.Controllers;
using Netch.Utils;
@@ -11,22 +11,18 @@ namespace Netch.Forms
/// <summary lang="zh">
/// 此类用于禁用设计器
/// </summary>
[DesignerCategory("")] public partial class Dummy { }
[DesignerCategory("")]
public partial class Dummy
{
}
partial class MainForm
{
private void CheckUpdate()
{
var updater = new UpdateChecker();
updater.NewVersionFound += (o, args) =>
{
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
$"{i18N.Translate(@"New version available",": ")}{updater.LatestVersionNumber}",
ToolTipIcon.Info);
};
updater.Check(false, false);
updater.NewVersionFound += (o, args) => { NotifyTip($"{i18N.Translate(@"New version available", ": ")}{updater.LatestVersionNumber}"); };
updater.Check(false, Global.Settings.CheckBetaUpdate);
}
}
}

View File

@@ -73,6 +73,11 @@ namespace Netch.Forms
// 加载快速配置
InitProfile();
// 打开软件时启动加速,产生开始按钮点击事件
if (Global.Settings.StartWhenOpened)
{
ControlButton.PerformClick();
}
// 自动检测延迟
Task.Run(() =>
@@ -92,17 +97,14 @@ namespace Netch.Forms
}
});
// 打开软件时启动加速,产生开始按钮点击事件
if (Global.Settings.StartWhenOpened)
Task.Run(() =>
{
ControlButton.PerformClick();
}
// 检查更新
if (Global.Settings.CheckUpdateWhenOpened)
{
CheckUpdate();
}
// 检查更新
if (Global.Settings.CheckUpdateWhenOpened)
{
CheckUpdate();
}
});
}
@@ -122,11 +124,7 @@ namespace Netch.Forms
if (_isFirstCloseWindow)
{
// 显示提示语
NotifyIcon.ShowBalloonTip(5,
UpdateChecker.Name,
i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."),
ToolTipIcon.Info);
NotifyTip(i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."));
_isFirstCloseWindow = false;
}
@@ -451,6 +449,14 @@ namespace Netch.Forms
Activate();
}
private void NotifyTip(string text, int timeout = 5, bool info = true)
{
NotifyIcon.ShowBalloonTip(timeout,
UpdateChecker.Name,
text,
info ? ToolTipIcon.Info : ToolTipIcon.Error);
}
#endregion
#endregion

View File

@@ -54,6 +54,7 @@
this.BehaviorGroupBox = new System.Windows.Forms.GroupBox();
this.LanguageLabel = new System.Windows.Forms.Label();
this.LanguageComboBox = new System.Windows.Forms.ComboBox();
this.ModifySystemDNSCheckBox = new System.Windows.Forms.CheckBox();
this.BootShadowsocksFromDLLCheckBox = new System.Windows.Forms.CheckBox();
this.AclAddrTextBox = new System.Windows.Forms.TextBox();
this.AclLabel = new System.Windows.Forms.Label();
@@ -68,11 +69,11 @@
this.MinimizeWhenStartedCheckBox = new System.Windows.Forms.CheckBox();
this.ProfileCountLabel = new System.Windows.Forms.Label();
this.ProfileCountTextBox = new System.Windows.Forms.TextBox();
this.CheckBetaUpdateCheckBox = new System.Windows.Forms.CheckBox();
this.CheckUpdateWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
this.StartWhenOpenedCheckBox = new System.Windows.Forms.CheckBox();
this.StopWhenExitedCheckBox = new System.Windows.Forms.CheckBox();
this.ExitWhenClosedCheckBox = new System.Windows.Forms.CheckBox();
this.ModifySystemDNSCheckBox = new System.Windows.Forms.CheckBox();
this.PortGroupBox.SuspendLayout();
this.TUNTAPGroupBox.SuspendLayout();
this.BehaviorGroupBox.SuspendLayout();
@@ -316,6 +317,7 @@
this.BehaviorGroupBox.Controls.Add(this.MinimizeWhenStartedCheckBox);
this.BehaviorGroupBox.Controls.Add(this.ProfileCountLabel);
this.BehaviorGroupBox.Controls.Add(this.ProfileCountTextBox);
this.BehaviorGroupBox.Controls.Add(this.CheckBetaUpdateCheckBox);
this.BehaviorGroupBox.Controls.Add(this.CheckUpdateWhenOpenedCheckBox);
this.BehaviorGroupBox.Controls.Add(this.StartWhenOpenedCheckBox);
this.BehaviorGroupBox.Controls.Add(this.StopWhenExitedCheckBox);
@@ -345,17 +347,27 @@
this.LanguageComboBox.Size = new System.Drawing.Size(121, 25);
this.LanguageComboBox.TabIndex = 22;
//
// ModifySystemDNSCheckBox
//
this.ModifySystemDNSCheckBox.AutoSize = true;
this.ModifySystemDNSCheckBox.Location = new System.Drawing.Point(12, 129);
this.ModifySystemDNSCheckBox.Name = "ModifySystemDNSCheckBox";
this.ModifySystemDNSCheckBox.Size = new System.Drawing.Size(143, 21);
this.ModifySystemDNSCheckBox.TabIndex = 21;
this.ModifySystemDNSCheckBox.Text = "Modify System DNS";
this.ModifySystemDNSCheckBox.UseVisualStyleBackColor = true;
//
// BootShadowsocksFromDLLCheckBox
//
this.BootShadowsocksFromDLLCheckBox.AutoSize = true;
this.BootShadowsocksFromDLLCheckBox.Location = new System.Drawing.Point(12, 102);
this.BootShadowsocksFromDLLCheckBox.Name = "BootShadowsocksFromDLLCheckBox";
this.BootShadowsocksFromDLLCheckBox.Size = new System.Drawing.Size(321, 21);
this.BootShadowsocksFromDLLCheckBox.Size = new System.Drawing.Size(168, 21);
this.BootShadowsocksFromDLLCheckBox.TabIndex = 21;
this.BootShadowsocksFromDLLCheckBox.Text = "Start Shadowsocks from DLL (No support for ACL)";
this.BootShadowsocksFromDLLCheckBox.Text = "SS DLL(No ACL support)";
this.BootShadowsocksFromDLLCheckBox.UseVisualStyleBackColor = true;
//
// AclAddr
// AclAddrTextBox
//
this.AclAddrTextBox.Location = new System.Drawing.Point(120, 273);
this.AclAddrTextBox.Name = "AclAddrTextBox";
@@ -372,7 +384,7 @@
this.AclLabel.TabIndex = 20;
this.AclLabel.Text = "Custom ACL";
//
// DetectionInterval_Label
// DetectionIntervalLabel
//
this.DetectionIntervalLabel.AutoSize = true;
this.DetectionIntervalLabel.Location = new System.Drawing.Point(228, 215);
@@ -381,7 +393,7 @@
this.DetectionIntervalLabel.TabIndex = 18;
this.DetectionIntervalLabel.Text = "Detection interval(sec)";
//
// DetectionInterval_TextBox
// DetectionIntervalTextBox
//
this.DetectionIntervalTextBox.Location = new System.Drawing.Point(366, 212);
this.DetectionIntervalTextBox.Name = "DetectionIntervalTextBox";
@@ -389,7 +401,7 @@
this.DetectionIntervalTextBox.TabIndex = 17;
this.DetectionIntervalTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// EnableStartedTcping_CheckBox
// TcpingAtStartedCheckBox
//
this.TcpingAtStartedCheckBox.AutoSize = true;
this.TcpingAtStartedCheckBox.Location = new System.Drawing.Point(15, 214);
@@ -426,7 +438,7 @@
this.STUNServerLabel.TabIndex = 10;
this.STUNServerLabel.Text = "STUN Server";
//
// RunAtStartup
// RunAtStartupCheckBox
//
this.RunAtStartupCheckBox.AutoSize = true;
this.RunAtStartupCheckBox.Location = new System.Drawing.Point(12, 75);
@@ -454,7 +466,7 @@
this.MinimizeWhenStartedCheckBox.Text = "Minimize when started";
this.MinimizeWhenStartedCheckBox.UseVisualStyleBackColor = true;
//
// ProfileCount_Label
// ProfileCountLabel
//
this.ProfileCountLabel.AutoSize = true;
this.ProfileCountLabel.Location = new System.Drawing.Point(12, 188);
@@ -463,7 +475,7 @@
this.ProfileCountLabel.TabIndex = 8;
this.ProfileCountLabel.Text = "ProfileCount";
//
// ProfileCount_TextBox
// ProfileCountTextBox
//
this.ProfileCountTextBox.Location = new System.Drawing.Point(120, 185);
this.ProfileCountTextBox.Name = "ProfileCountTextBox";
@@ -471,6 +483,17 @@
this.ProfileCountTextBox.TabIndex = 9;
this.ProfileCountTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// CheckBetaUpdateCheckBox
//
this.CheckBetaUpdateCheckBox.AutoSize = true;
this.CheckBetaUpdateCheckBox.Location = new System.Drawing.Point(206, 102);
this.CheckBetaUpdateCheckBox.Name = "CheckBetaUpdateCheckBox";
this.CheckBetaUpdateCheckBox.Size = new System.Drawing.Size(137, 21);
this.CheckBetaUpdateCheckBox.TabIndex = 8;
this.CheckBetaUpdateCheckBox.Text = "Check Beta update";
this.CheckBetaUpdateCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.CheckBetaUpdateCheckBox.UseVisualStyleBackColor = true;
//
// CheckUpdateWhenOpenedCheckBox
//
this.CheckUpdateWhenOpenedCheckBox.AutoSize = true;
@@ -515,16 +538,6 @@
this.ExitWhenClosedCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.ExitWhenClosedCheckBox.UseVisualStyleBackColor = true;
//
// ModifySystemDNSCheckBox
//
this.ModifySystemDNSCheckBox.AutoSize = true;
this.ModifySystemDNSCheckBox.Location = new System.Drawing.Point(12, 129);
this.ModifySystemDNSCheckBox.Name = "ModifySystemDNSCheckBox";
this.ModifySystemDNSCheckBox.Size = new System.Drawing.Size(143, 21);
this.ModifySystemDNSCheckBox.TabIndex = 21;
this.ModifySystemDNSCheckBox.Text = "Modify System DNS";
this.ModifySystemDNSCheckBox.UseVisualStyleBackColor = true;
//
// SettingForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -601,5 +614,6 @@
private System.Windows.Forms.Label LanguageLabel;
private System.Windows.Forms.ComboBox LanguageComboBox;
private System.Windows.Forms.CheckBox ModifySystemDNSCheckBox;
private System.Windows.Forms.CheckBox CheckBetaUpdateCheckBox;
}
}

View File

@@ -106,6 +106,7 @@ namespace Netch.Forms
CheckUpdateWhenOpenedCheckBox.Checked = Global.Settings.CheckUpdateWhenOpened;
BootShadowsocksFromDLLCheckBox.Checked = Global.Settings.BootShadowsocksFromDLL;
ModifySystemDNSCheckBox.Checked = Global.Settings.ModifySystemDNS;
CheckBetaUpdateCheckBox.Checked = Global.Settings.CheckBetaUpdate;
ProfileCountTextBox.Text = Global.Settings.ProfileCount.ToString();
TcpingAtStartedCheckBox.Checked = Global.Settings.StartedTcping;
@@ -133,6 +134,7 @@ namespace Netch.Forms
ControlButton.Text = i18N.Translate(ControlButton.Text);
BootShadowsocksFromDLLCheckBox.Text = i18N.Translate(BootShadowsocksFromDLLCheckBox.Text);
ModifySystemDNSCheckBox.Text = i18N.Translate(ModifySystemDNSCheckBox.Text);
CheckBetaUpdateCheckBox.Text = i18N.Translate(CheckBetaUpdateCheckBox.Text);
BehaviorGroupBox.Text = i18N.Translate(BehaviorGroupBox.Text);
ExitWhenClosedCheckBox.Text = i18N.Translate(ExitWhenClosedCheckBox.Text);
StopWhenExitedCheckBox.Text = i18N.Translate(StopWhenExitedCheckBox.Text);
@@ -173,6 +175,7 @@ namespace Netch.Forms
Global.Settings.StopWhenExited = StopWhenExitedCheckBox.Checked;
Global.Settings.StartWhenOpened = StartWhenOpenedCheckBox.Checked;
Global.Settings.CheckUpdateWhenOpened = CheckUpdateWhenOpenedCheckBox.Checked;
Global.Settings.CheckBetaUpdate = CheckBetaUpdateCheckBox.Checked;
Global.Settings.MinimizeWhenStarted = MinimizeWhenStartedCheckBox.Checked;
Global.Settings.RunAtStartup = RunAtStartupCheckBox.Checked;
Global.Settings.BootShadowsocksFromDLL = BootShadowsocksFromDLLCheckBox.Checked;

View File

@@ -12,6 +12,7 @@ namespace Netch.Models.GitHubRelease
{
releases = releases.Where(release => !release.prerelease);
}
releases = releases.Where(release => IsVersionString(release.tag_name));
var ordered = releases.OrderByDescending(release => release.tag_name, new VersionComparer());
return ordered.ElementAt(0);
@@ -19,6 +20,8 @@ namespace Netch.Models.GitHubRelease
private static bool IsVersionString(string str)
{
if (Global.Settings.CheckBetaUpdate)
str = str.Split('-')[0];
return Version.TryParse(str, out _);
}
@@ -27,10 +30,28 @@ namespace Netch.Models.GitHubRelease
/// <returns> &lt;0:version2 is greater</returns>
public static int CompareVersion(string v1, string v2)
{
var version1 = new Version(v1);
var version2 = new Version(v2);
var version1 = ToVersion(v1);
var version2 = ToVersion(v2);
var res = version1.CompareTo(version2);
return res;
}
private static Version ToVersion(string versionStr)
{
var v = versionStr.Split('-');
var version = Version.Parse(v[0]);
if (v.Length == 1)
return version;
var beta = v[1];
var result = string.Empty;
foreach (var c in beta)
{
if (int.TryParse(c.ToString(), out var n))
result += n;
}
return new Version(version.Major, version.Minor, version.Build, int.Parse(result));
}
}
}
}

View File

@@ -87,12 +87,22 @@ namespace Netch.Models
/// 是否打开软件时检查更新
/// </summary>
public bool CheckUpdateWhenOpened = true;
/// <summary>
/// 是否检查 Beta 更新
/// </summary>
public bool CheckBetaUpdate = false;
/// <summary>
/// 修改系统 DNS
/// </summary>
public bool ModifySystemDNS = false;
/// <summary>
/// 网页请求超时 毫秒
/// </summary>
public int RequestTimeout = 10000;
/// <summary>
/// 使用何种模式文件名
/// 0 为自定义文件名1 为使用和备注一致的文件名2 为使用时间数据作为文件名

View File

@@ -1,17 +0,0 @@
using System;
using System.Net;
namespace Netch.Override
{
public class WebClient : System.Net.WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
request.Timeout = 10000;
((HttpWebRequest)request).ReadWriteTimeout = 10000;
return request;
}
}
}

View File

@@ -5,6 +5,7 @@
"If this is your first time using this software,\n please check https://netch.org to install supports first,\n or the program may report errors.": "如果你是第一次使用本软件,\n请务必前往https://netch.org安装程序所需依赖\n否则程序将无法正常运行",
"Netch is already running": "Netch 已经在运行中",
"Missing File or runtime components": "缺少文件或运行库",
"Start": "启动",
"Stop": "停止",
@@ -156,7 +157,8 @@
"Global Bypass IPs": "全局直连 IP",
"Port value illegal. Try again.": "端口值非法。请重试。",
"Check update when opened": "打开软件时检查更新",
"Start Shadowsocks from DLL (No support for ACL)": "SS DLL推荐使用不支持 ACL",
"Check Beta update": "检查 Beta 更新",
"SS DLL(No ACL support)": "SS DLL不支持 ACL",
"Modify System DNS": "修改系统 DNS",
"ProfileCount": "快捷配置数量",
"ProfileCount value illegal. Try again.": "快捷配置数值非法。请重试。",

76
Netch/Utils/WebUtil.cs Normal file
View File

@@ -0,0 +1,76 @@
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Netch.Utils
{
public class WebUtil
{
private const string DefaultUserAgent = @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36";
private static int DefaultGetTimeout => Global.Settings.RequestTimeout;
public static HttpWebRequest CreateRequest(string url, int? timeout = null, string userAgent = null)
{
var req = (HttpWebRequest) WebRequest.Create(url);
req.UserAgent = string.IsNullOrEmpty(userAgent) ? DefaultUserAgent : userAgent;
req.Accept = "*/*";
req.KeepAlive = true;
req.Timeout = timeout ?? DefaultGetTimeout;
req.ReadWriteTimeout = timeout ?? DefaultGetTimeout;
req.Headers.Add("Accept-Charset", "utf-8");
return req;
}
/// <param name="req"></param>
/// <returns></returns>
/// <exception cref="WebException"></exception>
public static async Task<string> DownloadStringAsync(HttpWebRequest req)
{
string content;
var response = (HttpWebResponse) await req.GetResponseAsync();
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")))
{
content = await sr.ReadToEndAsync();
}
}
response.Close();
return content;
}
/// <param name="req"></param>
/// <returns></returns>
/// <exception cref="WebException"></exception>
public static string DownloadString(HttpWebRequest req)
{
string content;
var response = (HttpWebResponse) req.GetResponse();
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")))
{
content = sr.ReadToEnd();
}
}
response.Close();
return content;
}
/// <param name="req"></param>
/// <param name="fileFullPath"></param>
/// <exception cref="WebException"></exception>
public static async Task DownloadFileAsync(HttpWebRequest req, string fileFullPath)
{
var dir = Path.GetDirectoryName(fileFullPath) ?? throw new ArgumentException();
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
File.WriteAllText(fileFullPath, await DownloadStringAsync(req));
}
}
}