diff --git a/.editorconfig b/.editorconfig
index df3f71f7..d2e5b066 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,7 +1,7 @@
+root = true
# http://editorconfig.org/
# top-most EditorConfig file
-root = true
# all files
[*]
@@ -32,6 +32,7 @@ resharper_csharp_blank_lines_around_field = 0
resharper_csharp_blank_lines_around_invocable = 0
resharper_csharp_blank_lines_around_type = 0
resharper_csharp_int_align_comments = true
+resharper_csharp_keep_blank_lines_in_declarations = 1
resharper_csharp_max_line_length = 368
resharper_csharp_wrap_lines = false
resharper_place_expr_accessor_on_single_line = true
diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs
index 533fb891..7334709a 100644
--- a/Netch/Controllers/MainController.cs
+++ b/Netch/Controllers/MainController.cs
@@ -97,8 +97,8 @@ namespace Netch.Controllers
if (!await StartMode(mode))
throw new StartFailedException();
- if (mode.TestNatRequired())
- NatTest();
+ _ = Task.Run(Bandwidth.NetTraffic);
+ _ = Task.Run(NatTest);
return true;
}
@@ -210,7 +210,6 @@ namespace Netch.Controllers
ServerController = null;
}
-
///
/// 检查端口是否被占用,
/// 被占用则弹窗提示, 确认后抛出异常
@@ -239,6 +238,8 @@ namespace Netch.Controllers
///
public static void NatTest()
{
+ if (!Mode.TestNatRequired())
+ return;
NttTested = false;
Task.Run(() =>
{
diff --git a/Netch/Forms/MainForm.Control.cs b/Netch/Forms/MainForm.Control.cs
deleted file mode 100644
index 68c3f7bc..00000000
--- a/Netch/Forms/MainForm.Control.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Netch.Controllers;
-using Netch.Models;
-using Netch.Utils;
-
-namespace Netch.Forms
-{
- public partial class Dummy
- {
- }
-
- partial class MainForm
- {
- private bool _isFirstCloseWindow = true;
-
- ///
- /// 上一次下载的流量
- ///
- public ulong LastDownloadBandwidth;
-
- ///
- /// 上一次上传的流量
- ///
- public ulong LastUploadBandwidth;
-
- private async void ControlFun()
- {
- Configuration.Save();
- if (State == State.Waiting || State == State.Stopped)
- {
- // 服务器、模式 需选择
- if (!(ServerComboBox.SelectedItem is Server server))
- {
- MessageBoxX.Show(i18N.Translate("Please select a server first"));
- return;
- }
-
- if (!(ModeComboBox.SelectedItem is Models.Mode mode))
- {
- MessageBoxX.Show(i18N.Translate("Please select a mode first"));
- return;
- }
-
- // 清除模式搜索框文本选择
- ModeComboBox.Select(0, 0);
-
- State = State.Starting;
-
- if (await MainController.Start(server, mode))
- {
- State = State.Started;
- _ = Task.Run(() => { Bandwidth.NetTraffic(); });
- // 如果勾选启动后最小化
- if (Global.Settings.MinimizeWhenStarted)
- {
- WindowState = FormWindowState.Minimized;
-
- if (_isFirstCloseWindow)
- {
- // 显示提示语
- NotifyTip(i18N.Translate("Netch is now minimized to the notification bar, double click this icon to restore."));
- _isFirstCloseWindow = false;
- }
-
- Hide();
- }
-
- if (Global.Settings.StartedTcping)
- // 自动检测延迟
- _ = Task.Run(() =>
- {
- while (State == State.Started)
- {
- server.Test();
- // 重绘 ServerComboBox
- ServerComboBox.Invalidate();
-
- Thread.Sleep(Global.Settings.StartedTcping_Interval * 1000);
- }
- });
- }
- else
- {
- State = State.Stopped;
- StatusText(i18N.Translate("Start failed"));
- }
- }
- else
- {
- // 停止
- State = State.Stopping;
- await MainController.Stop();
- State = State.Stopped;
- }
- }
-
- public void OnBandwidthUpdated(ulong download)
- {
- if (InvokeRequired)
- {
- BeginInvoke(new Action(OnBandwidthUpdated), download);
- return;
- }
-
- try
- {
- UsedBandwidthLabel.Text = $"{i18N.Translate("Used", ": ")}{Bandwidth.Compute(download)}";
- //UploadSpeedLabel.Text = $"↑: {Utils.Bandwidth.Compute(upload - LastUploadBandwidth)}/s";
- DownloadSpeedLabel.Text = $"↑↓: {Bandwidth.Compute(download - LastDownloadBandwidth)}/s";
-
- //LastUploadBandwidth = upload;
- LastDownloadBandwidth = download;
- Refresh();
- }
- catch
- {
- // ignored
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Netch/Forms/MainForm.MenuStrip.cs b/Netch/Forms/MainForm.MenuStrip.cs
deleted file mode 100644
index 93599f55..00000000
--- a/Netch/Forms/MainForm.MenuStrip.cs
+++ /dev/null
@@ -1,375 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Netch.Controllers;
-using Netch.Forms.Mode;
-using Netch.Models;
-using Netch.Utils;
-
-namespace Netch.Forms
-{
- partial class Dummy
- {
- }
-
- partial class MainForm
- {
- #region MenuStrip
-
- #region 服务器
-
- private void ImportServersFromClipboardToolStripMenuItem_Click(object sender, EventArgs e)
- {
- var texts = Clipboard.GetText();
- if (!string.IsNullOrWhiteSpace(texts))
- {
- var servers = ShareLink.ParseText(texts);
- Global.Settings.Server.AddRange(servers);
- NotifyTip(i18N.TranslateFormat("Import {0} server(s) form Clipboard", servers.Count));
-
- InitServer();
- Configuration.Save();
- }
- }
-
- private void AddServerToolStripMenuItem_Click(object sender, EventArgs e)
- {
- var s = ((ToolStripMenuItem) sender).Text;
-
- var start = s.IndexOf("[", StringComparison.Ordinal) + 1;
- var end = s.IndexOf("]", start, StringComparison.Ordinal);
- var result = s.Substring(start, end - start);
-
- Hide();
- ServerHelper.GetUtilByFullName(result).Create();
-
- InitServer();
- Configuration.Save();
- Show();
- }
-
- #endregion
-
- #region 模式
-
- private void CreateProcessModeToolStripButton_Click(object sender, EventArgs e)
- {
- Hide();
- new Process().ShowDialog();
- Show();
- }
-
- private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Enabled = false;
- try
- {
- ModeHelper.Load();
- InitMode();
- NotifyTip(i18N.Translate("Modes have been reload"));
- }
- catch (Exception)
- {
- // ignored
- }
- finally
- {
- Enabled = true;
- }
- }
-
- #endregion
-
- #region 订阅
-
- private void ManageSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Hide();
- new SubscribeForm().ShowDialog();
- InitServer();
- Show();
- }
-
- private async void UpdateServersFromSubscribeLinksToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Global.Settings.UseProxyToUpdateSubscription = false;
- await UpdateServersFromSubscribe();
- }
-
- private async void UpdateServersFromSubscribeLinksWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Global.Settings.UseProxyToUpdateSubscription = true;
- await UpdateServersFromSubscribe(true);
- }
-
- private async Task UpdateServersFromSubscribe(bool useProxy = false)
- {
- void DisableItems(bool v)
- {
- MenuStrip.Enabled = ConfigurationGroupBox.Enabled = ProfileGroupBox.Enabled = ControlButton.Enabled = v;
- }
-
- if (useProxy && ServerComboBox.SelectedIndex == -1)
- {
- MessageBoxX.Show(i18N.Translate("Please select a server first"));
- return;
- }
-
- if (Global.Settings.SubscribeLink.Count <= 0)
- {
- MessageBoxX.Show(i18N.Translate("No subscription link"));
- return;
- }
-
- StatusText(i18N.Translate("Starting update subscription"));
- DisableItems(false);
- try
- {
- string proxyServer = null;
- if (useProxy)
- {
- var mode = new Models.Mode
- {
- Remark = "ProxyUpdate",
- Type = 5
- };
- await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
- proxyServer = $"http://127.0.0.1:{Global.Settings.HTTPLocalPort}";
- }
-
- await Subscription.UpdateServersAsync(proxyServer);
-
- InitServer();
- Configuration.Save();
- StatusText(i18N.Translate("Subscription updated"));
- }
- catch (Exception)
- {
- // ignored
- }
- finally
- {
- if (useProxy)
- try
- {
- await MainController.Stop();
- }
- catch
- {
- // ignored
- }
-
- DisableItems(true);
- }
- }
-
- #endregion
-
- #region 选项
-
- private void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Task.Run(() =>
- {
- void OnNewVersionNotFound(object o, EventArgs args)
- {
- UpdateChecker.NewVersionNotFound -= OnNewVersionNotFound;
- NotifyTip(i18N.Translate("Already latest version"));
- }
-
- void OnNewVersionFoundFailed(object o, EventArgs args)
- {
- UpdateChecker.NewVersionFoundFailed -= OnNewVersionFoundFailed;
- NotifyTip(i18N.Translate("New version found failed"), info: false);
- }
-
- UpdateChecker.NewVersionNotFound += OnNewVersionNotFound;
- UpdateChecker.NewVersionFoundFailed += OnNewVersionFoundFailed;
- CheckUpdate();
- });
- }
-
- private void OpenDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Utils.Utils.Open(".\\");
- }
-
- private async void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
- {
- try
- {
- await Task.Run(() =>
- {
- NativeMethods.FlushDNSResolverCache();
- DNS.Cache.Clear();
- });
-
- NotifyTip(i18N.Translate("DNS cache cleanup succeeded"));
- }
- catch (Exception)
- {
- // ignored
- }
- finally
- {
- StatusText();
- }
- }
-
- private void updateACLWithProxyToolStripMenuItem_Click(object sender, EventArgs e)
- {
- UpdateACL(true);
- }
-
- private void updateACLToolStripMenuItem_Click(object sender, EventArgs e)
- {
- UpdateACL(false);
- }
-
- private async void UpdateACL(bool useProxy)
- {
- if (useProxy && ServerComboBox.SelectedIndex == -1)
- {
- MessageBoxX.Show(i18N.Translate("Please select a server first"));
- return;
- }
-
- Enabled = false;
- StatusText(i18N.TranslateFormat("Updating {0}", "ACL"));
- try
- {
- if (useProxy)
- {
- var mode = new Models.Mode
- {
- Remark = "ProxyUpdate",
- Type = 5
- };
- State = State.Starting;
- await MainController.Start(ServerComboBox.SelectedItem as Server, mode);
- }
-
- 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);
- }
- finally
- {
- if (useProxy)
- {
- await MainController.Stop();
- State = State.Stopped;
- }
-
- StatusText();
- Enabled = true;
- }
- }
-
- private async void updatePACToolStripMenuItem_Click(object sender, EventArgs eventArgs)
- {
- Enabled = false;
-
- StatusText(i18N.TranslateFormat("Updating {0}", "PAC"));
- try
- {
- var req = WebUtil.CreateRequest(Global.Settings.PAC);
-
- var pac = Path.Combine(Global.NetchDir, "bin\\pac.txt");
-
- await WebUtil.DownloadFileAsync(req, pac);
-
- NotifyTip(i18N.Translate("PAC updated successfully"));
- }
- catch (Exception e)
- {
- NotifyTip(i18N.Translate("PAC update failed") + "\n" + e.Message, info: false);
- Logging.Error("更新 PAC 失败!" + e);
- }
- finally
- {
- StatusText();
- Enabled = true;
- }
- }
-
- private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Enabled = false;
- StatusText(i18N.TranslateFormat("Uninstalling {0}", "NF Service"));
- try
- {
- await Task.Run(() =>
- {
- if (NFController.UninstallDriver())
- NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "NF Service"));
- });
- }
- finally
- {
- StatusText();
- Enabled = true;
- }
- }
-
- private async void UninstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Enabled = false;
- StatusText(i18N.TranslateFormat("Uninstalling {0}", "TUN/TAP driver"));
- try
- {
- await Task.Run(TUNTAP.deltapall);
- NotifyTip(i18N.TranslateFormat("{0} has been uninstalled", "TUN/TAP driver"));
- }
- catch (Exception exception)
- {
- Logging.Error($"卸载 TUN/TAP 适配器失败: {exception}");
- }
- finally
- {
- StatusText();
- Enabled = true;
- }
- }
-
- #endregion
-
-
- ///
- /// 菜单栏强制退出
- ///
- private void exitToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Exit(true);
- }
-
- private void VersionLabel_Click(object sender, EventArgs e)
- {
- Utils.Utils.Open($"https://github.com/{UpdateChecker.Owner}/{UpdateChecker.Repo}/releases");
- }
-
- private void AboutToolStripButton_Click(object sender, EventArgs e)
- {
- Hide();
- new AboutForm().ShowDialog();
- Show();
- }
-
- private void fAQToolStripMenuItem_Click(object sender, EventArgs e)
- {
- Utils.Utils.Open("https://netch.org/#/docs/zh-CN/faq");
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/Netch/Forms/MainForm.Misc.cs b/Netch/Forms/MainForm.Misc.cs
deleted file mode 100644
index 346841cf..00000000
--- a/Netch/Forms/MainForm.Misc.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.Linq;
-using System.Net;
-using System.Windows.Forms;
-using Netch.Controllers;
-using Netch.Utils;
-
-namespace Netch.Forms
-{
- partial class MainForm
- {
- private void CheckUpdate()
- {
- UpdateChecker.NewVersionFound += (_, _) =>
- {
- NotifyTip($"{i18N.Translate(@"New version available", ": ")}{UpdateChecker.LatestVersionNumber}");
- NewVersionLabel.Visible = true;
- };
- UpdateChecker.Check(Global.Settings.CheckBetaUpdate);
- }
-
- private async void NewVersionLabel_Click(object sender, EventArgs e)
- {
- if (!UpdateChecker.LatestRelease.assets.Any())
- {
- Utils.Utils.Open(UpdateChecker.LatestVersionUrl);
- return;
- }
-
- if (MessageBoxX.Show(i18N.Translate("Download and install now?"), confirm: true) != DialogResult.OK)
- return;
- NotifyTip(i18N.Translate("Start downloading new version"));
-
- NewVersionLabel.Enabled = false;
- NewVersionLabel.Text = "...";
- try
- {
- void OnDownloadProgressChanged(object o1, DownloadProgressChangedEventArgs args)
- {
- BeginInvoke(new Action(() => { NewVersionLabel.Text = $"{args.ProgressPercentage}%"; }));
- }
-
- await UpdateChecker.UpdateNetch(OnDownloadProgressChanged);
- }
- catch (Exception exception)
- {
- Logging.Error(exception.Message);
- NotifyTip(exception.Message);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Netch/Forms/MainForm.Profile.cs b/Netch/Forms/MainForm.Profile.cs
deleted file mode 100644
index 4b82baf8..00000000
--- a/Netch/Forms/MainForm.Profile.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Netch.Models;
-using Netch.Utils;
-
-namespace Netch.Forms
-{
- public partial class Dummy
- {
- }
-
- partial class MainForm
- {
- private int _configurationGroupBoxHeight;
- private int _profileConfigurationHeight;
-
- private void InitProfile()
- {
- // Clear
- foreach (var button in ProfileButtons)
- button.Dispose();
-
- ProfileButtons.Clear();
- ProfileTable.ColumnStyles.Clear();
- ProfileTable.RowStyles.Clear();
-
- var numProfile = Global.Settings.ProfileCount;
- if (numProfile == 0)
- {
- // Hide Profile GroupBox, Change window size
- configLayoutPanel.RowStyles[2].SizeType = SizeType.Percent;
- configLayoutPanel.RowStyles[2].Height = 0;
- ProfileGroupBox.Visible = false;
-
- ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight - _profileConfigurationHeight);
- }
- else
- {
- // Load Profiles
- ProfileTable.ColumnCount = numProfile;
-
- while (Global.Settings.Profiles.Count < numProfile)
- {
- Global.Settings.Profiles.Add(new Profile());
- }
-
- for (var i = 0; i < numProfile; ++i)
- {
- var b = new Button();
- b.Click += ProfileButton_Click;
- b.Dock = DockStyle.Fill;
- b.Text = !Global.Settings.Profiles[i].IsDummy ? Global.Settings.Profiles[i].ProfileName : i18N.Translate("None");
-
- ProfileTable.Controls.Add(b, i, 0);
- ProfileButtons.Add(b);
- }
-
- // equal column
- for (var i = 1; i <= ProfileTable.RowCount; i++)
- {
- ProfileTable.RowStyles.Add(new RowStyle(SizeType.Percent, 1));
- }
-
- for (var i = 1; i <= ProfileTable.ColumnCount; i++)
- {
- ProfileTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1));
- }
-
- configLayoutPanel.RowStyles[2].SizeType = SizeType.AutoSize;
- ProfileGroupBox.Visible = true;
- ConfigurationGroupBox.Size = new Size(ConfigurationGroupBox.Size.Width, _configurationGroupBoxHeight);
- }
- }
-
- private void LoadProfile(int index)
- {
- var p = Global.Settings.Profiles[index];
- ProfileNameText.Text = p.ProfileName;
- ModeComboBox.ResetCompletionList();
-
- if (p.IsDummy)
- throw new Exception("Profile not found.");
-
- var server = ServerComboBox.Items.Cast().FirstOrDefault(s => s.Remark.Equals(p.ServerRemark));
- var mode = ModeComboBox.Items.Cast().FirstOrDefault(m => m.Remark.Equals(p.ModeRemark));
-
- if (server == null)
- {
- throw new Exception("Server not found.");
- }
-
- if (mode == null)
- {
- throw new Exception("Mode not found.");
- }
-
- ServerComboBox.SelectedItem = server;
- ModeComboBox.SelectedItem = mode;
- }
-
- private void SaveProfile(int index)
- {
- var selectedServer = (Server) ServerComboBox.SelectedItem;
- var selectedMode = (Models.Mode) ModeComboBox.SelectedItem;
- var name = ProfileNameText.Text;
-
- Global.Settings.Profiles[index] = new Profile(selectedServer, selectedMode, name);
- }
-
- private void RemoveProfile(int index)
- {
- Global.Settings.Profiles[index] = new Profile();
- }
-
-
- private List