mirror of
https://github.com/netchx/netch.git
synced 2026-03-30 19:09:48 +08:00
控制器日志写入线程安全,主控制器启动停止等改为异步执行,修复主控制器停止提前释放
This commit is contained in:
@@ -105,7 +105,7 @@ namespace Netch.Controllers
|
||||
/// <param name="argument">主程序启动参数</param>
|
||||
/// <param name="priority">进程优先级</param>
|
||||
/// <returns>是否成功启动</returns>
|
||||
protected bool StartInstanceAuto(string argument, ProcessPriorityClass priority = ProcessPriorityClass.Normal)
|
||||
protected bool StartInstanceAuto(string argument, ProcessPriorityClass priority = ProcessPriorityClass.RealTime)
|
||||
{
|
||||
State = State.Starting;
|
||||
try
|
||||
@@ -183,14 +183,14 @@ namespace Netch.Controllers
|
||||
/// </summary>
|
||||
/// <param name="sender">发送者</param>
|
||||
/// <param name="e">数据</param>
|
||||
protected async void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
protected void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
// 程序结束, 接收到 null
|
||||
if (e.Data == null)
|
||||
return;
|
||||
|
||||
var info = Encoding.GetEncoding(InstanceOutputEncoding).GetBytes(e.Data + Global.EOF);
|
||||
await Write(info);
|
||||
Task.Run(() => Write(info));
|
||||
var str = Encoding.UTF8.GetString(info);
|
||||
// 检查启动
|
||||
if (State == State.Starting)
|
||||
@@ -220,19 +220,24 @@ namespace Netch.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object _fileLocker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志文件流
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <returns>转码后的字符串</returns>
|
||||
private async Task Write(byte[] info)
|
||||
private void Write(byte[] info)
|
||||
{
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
await _logFileStream.WriteAsync(info, 0, info.Length);
|
||||
lock (_fileLocker)
|
||||
{
|
||||
_logFileStream.Write(info, 0, info.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Netch.Controllers
|
||||
/// <param name="server">服务器</param>
|
||||
/// <param name="mode">模式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public bool Start(Server server, Mode mode)
|
||||
public async Task<bool> Start(Server server, Mode mode)
|
||||
{
|
||||
Logging.Info($"启动主控制器: {server.Type} [{mode.Type}]{mode.Remark}");
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Netch.Controllers
|
||||
#endregion
|
||||
|
||||
FlushDNSResolverCache();
|
||||
_ = Task.Run(Firewall.AddNetchFwRules);
|
||||
|
||||
bool result;
|
||||
if (server.Type == "Socks5")
|
||||
@@ -111,17 +112,17 @@ namespace Netch.Controllers
|
||||
var isPortNotAvailable = false;
|
||||
if (_savedServer.Type != "Socks5")
|
||||
{
|
||||
isPortNotAvailable = PortCheckAndShowMessageBox(_socks5Port, "Socks5");
|
||||
isPortNotAvailable |= PortCheckAndShowMessageBox(_socks5Port, "Socks5");
|
||||
}
|
||||
|
||||
switch (_savedMode.Type)
|
||||
{
|
||||
case 0:
|
||||
isPortNotAvailable = isPortNotAvailable || PortCheckAndShowMessageBox(_redirectorTCPPort, "Redirector TCP");
|
||||
isPortNotAvailable |= PortCheckAndShowMessageBox(_redirectorTCPPort, "Redirector TCP");
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
isPortNotAvailable = isPortNotAvailable || PortCheckAndShowMessageBox(_httpPort, "HTTP");
|
||||
isPortNotAvailable |= PortCheckAndShowMessageBox(_httpPort, "HTTP");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", pEncryptedProxyController.Name));
|
||||
result = pEncryptedProxyController.Start(server, mode);
|
||||
result = await Task.Run(() => pEncryptedProxyController.Start(server, mode));
|
||||
}
|
||||
|
||||
if (result)
|
||||
@@ -161,7 +162,7 @@ namespace Netch.Controllers
|
||||
if (pModeController != null)
|
||||
{
|
||||
Global.MainForm.StatusText(i18N.Translate("Starting ", pModeController.Name));
|
||||
result = pModeController.Start(server, mode);
|
||||
result = await Task.Run(() => pModeController.Start(server, mode));
|
||||
}
|
||||
|
||||
if (result)
|
||||
@@ -179,13 +180,12 @@ namespace Netch.Controllers
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (mode.Type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
Task.Run(() =>
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
Global.MainForm.NatTypeStatusText(i18N.Translate("Starting NatTester"));
|
||||
// Thread.Sleep(1000);
|
||||
@@ -202,7 +202,7 @@ namespace Netch.Controllers
|
||||
if (!result)
|
||||
{
|
||||
Logging.Error("主控制器启动失败");
|
||||
Stop();
|
||||
await Stop();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -211,15 +211,16 @@ namespace Netch.Controllers
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public async void Stop()
|
||||
public async Task Stop()
|
||||
{
|
||||
await Task.WhenAll(new[]
|
||||
var tasks = new Task[]
|
||||
{
|
||||
Task.Run(() => pEncryptedProxyController?.Stop()),
|
||||
Task.Run(() => UsingPorts.Clear()),
|
||||
Task.Run(() => pModeController?.Stop()),
|
||||
Task.Run(() => pNTTController.Stop())
|
||||
});
|
||||
};
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public static void KillProcessByName(string name)
|
||||
|
||||
@@ -175,18 +175,9 @@ namespace Netch.Controllers
|
||||
}
|
||||
|
||||
if (!File.Exists(SystemDriver)) return true;
|
||||
|
||||
try
|
||||
{
|
||||
NFAPI.nf_unRegisterDriver("netfilter2");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
NFAPI.nf_unRegisterDriver("netfilter2");
|
||||
File.Delete(SystemDriver);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,26 +40,22 @@ namespace Netch.Forms
|
||||
|
||||
State = State.Starting;
|
||||
|
||||
await Task.Run(Firewall.AddNetchFwRules);
|
||||
|
||||
var server = ServerComboBox.SelectedItem as Models.Server;
|
||||
var mode = ModeComboBox.SelectedItem as Models.Mode;
|
||||
var result = false;
|
||||
|
||||
await Task.Run(() =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO 完善控制器异常处理
|
||||
result = _mainController.Start(server, mode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is DllNotFoundException || e is FileNotFoundException)
|
||||
MessageBoxX.Show(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"), owner: this);
|
||||
Netch.Application_OnException(null, new ThreadExceptionEventArgs(e));
|
||||
}
|
||||
});
|
||||
// TODO 完善控制器异常处理
|
||||
result = await _mainController.Start(server, mode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is DllNotFoundException || e is FileNotFoundException)
|
||||
MessageBoxX.Show(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"), owner: this);
|
||||
Netch.Application_OnException(null, new ThreadExceptionEventArgs(e));
|
||||
}
|
||||
|
||||
|
||||
if (result)
|
||||
{
|
||||
@@ -106,7 +102,7 @@ namespace Netch.Forms
|
||||
{
|
||||
// 停止
|
||||
State = State.Stopping;
|
||||
_mainController.Stop();
|
||||
await _mainController.Stop();
|
||||
State = State.Stopped;
|
||||
_ = Task.Run(TestServer);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace Netch.Forms
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
await _mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
}
|
||||
|
||||
var serverLock = new object();
|
||||
@@ -157,16 +157,14 @@ namespace Netch.Forms
|
||||
lock (serverLock)
|
||||
{
|
||||
Global.Settings.Server = Global.Settings.Server.Where(server => server.Group != item.Remark).ToList();
|
||||
}
|
||||
var result = ShareLink.Parse(str);
|
||||
if (result != null)
|
||||
{
|
||||
foreach (var x in result) x.Group = item.Remark;
|
||||
|
||||
var result = ShareLink.Parse(str);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
foreach (var x in result) x.Group = item.Remark;
|
||||
|
||||
Global.Settings.Server.AddRange(result);
|
||||
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, result.Count));
|
||||
Global.Settings.Server.AddRange(result);
|
||||
NotifyTip(i18N.TranslateFormat("Update {1} server(s) from {0}", item.Remark, result.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
@@ -186,7 +184,7 @@ namespace Netch.Forms
|
||||
|
||||
if (Global.Settings.UseProxyToUpdateSubscription)
|
||||
{
|
||||
_mainController.Stop();
|
||||
await _mainController.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,13 +197,10 @@ namespace Netch.Forms
|
||||
Utils.Utils.Open(".\\");
|
||||
}
|
||||
|
||||
private void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void CleanDNSCacheToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
DNS.Cache.Clear();
|
||||
NotifyTip(i18N.Translate("DNS cache cleanup succeeded"));
|
||||
});
|
||||
await Task.Run(() => DNS.Cache.Clear());
|
||||
StatusText(i18N.Translate("DNS cache cleanup succeeded"));
|
||||
}
|
||||
|
||||
private void ReloadModesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
@@ -246,95 +241,83 @@ namespace Netch.Forms
|
||||
|
||||
DisableItems(false);
|
||||
|
||||
await Task.Run(async () =>
|
||||
if (useProxy)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
State = State.Starting;
|
||||
await _mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
}
|
||||
|
||||
NotifyTip(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);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
{
|
||||
var mode = new Models.Mode
|
||||
{
|
||||
Remark = "ProxyUpdate",
|
||||
Type = 5
|
||||
};
|
||||
State = State.Starting;
|
||||
_mainController.Start(ServerComboBox.SelectedItem as Models.Server, mode);
|
||||
await _mainController.Stop();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
NotifyTip(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);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (useProxy)
|
||||
{
|
||||
_mainController.Stop();
|
||||
State = State.Stopped;
|
||||
}
|
||||
|
||||
DisableItems(true);
|
||||
}
|
||||
});
|
||||
DisableItems(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void UninstallServiceToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Enabled = false;
|
||||
StatusText(i18N.Translate("Uninstalling NF Service"));
|
||||
|
||||
Task.Run(() =>
|
||||
var result = false;
|
||||
try
|
||||
{
|
||||
try
|
||||
await Task.Run(() => result = NFController.UninstallDriver());
|
||||
if (result)
|
||||
{
|
||||
if (NFController.UninstallDriver())
|
||||
{
|
||||
StatusText(i18N.Translate("Service has been uninstalled"));
|
||||
}
|
||||
StatusText(i18N.Translate("Service has been uninstalled"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBoxX.Show(e.ToString(), LogLevel.ERROR);
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabled = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void reinstallTapDriverToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Task.Run(() =>
|
||||
StatusText(i18N.Translate("Reinstalling TUN/TAP driver"));
|
||||
Enabled = false;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
StatusText(i18N.Translate("Reinstalling TUN/TAP driver"));
|
||||
Enabled = false;
|
||||
try
|
||||
{
|
||||
Configuration.deltapall();
|
||||
Configuration.addtap();
|
||||
NotifyTip(i18N.Translate("Reinstall TUN/TAP driver successfully"));
|
||||
StatusText(i18N.Translate("Reinstall TUN/TAP driver successfully"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
NotifyTip(i18N.Translate("Reinstall TUN/TAP driver failed"), info: false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
State = State.Waiting;
|
||||
Enabled = true;
|
||||
}
|
||||
});
|
||||
State = State.Waiting;
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -9,7 +9,10 @@ using Netch.Utils;
|
||||
|
||||
namespace Netch.Forms
|
||||
{
|
||||
public partial class Dummy { }
|
||||
public partial class Dummy
|
||||
{
|
||||
}
|
||||
|
||||
partial class MainForm
|
||||
{
|
||||
/// init at <see cref="MainForm_Load"/>
|
||||
@@ -136,7 +139,7 @@ namespace Netch.Forms
|
||||
|
||||
private List<Button> ProfileButtons = new List<Button>();
|
||||
|
||||
private void ProfileButton_Click(object sender, EventArgs e)
|
||||
private async void ProfileButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var index = ProfileButtons.IndexOf((Button) sender);
|
||||
|
||||
@@ -159,6 +162,7 @@ namespace Netch.Forms
|
||||
SaveProfile(index);
|
||||
ProfileButtons[index].Text = ProfileNameText.Text;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -185,26 +189,20 @@ namespace Netch.Forms
|
||||
ControlFun();
|
||||
if (State == State.Stopping || State == State.Stopped)
|
||||
{
|
||||
Task.Run(() =>
|
||||
while (State != State.Stopped)
|
||||
{
|
||||
while (State != State.Stopped)
|
||||
{
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
await Task.Delay(250);
|
||||
}
|
||||
|
||||
ControlFun();
|
||||
});
|
||||
ControlFun();
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
Logging.Info(ee.ToString());
|
||||
ProfileButtons[index].Text = i18N.Translate("Error");
|
||||
Thread.Sleep(1200);
|
||||
ProfileButtons[index].Text = i18N.Translate("None");
|
||||
});
|
||||
Logging.Info(ee.ToString());
|
||||
ProfileButtons[index].Text = i18N.Translate("Error");
|
||||
await Task.Delay(1200);
|
||||
ProfileButtons[index].Text = i18N.Translate("None");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Netch.Forms
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
// TODO:使所有 State 赋值不在线程中执行然后移除此代码块
|
||||
BeginInvoke(new Action(() => { State = value; }));
|
||||
return;
|
||||
}
|
||||
@@ -33,9 +34,9 @@ namespace Netch.Forms
|
||||
ServerComboBox.Enabled =
|
||||
ModeComboBox.Enabled =
|
||||
EditModePictureBox.Enabled =
|
||||
EditServerPictureBox.Enabled =
|
||||
DeleteModePictureBox.Enabled =
|
||||
DeleteServerPictureBox.Enabled = enabled;
|
||||
EditServerPictureBox.Enabled =
|
||||
DeleteModePictureBox.Enabled =
|
||||
DeleteServerPictureBox.Enabled = enabled;
|
||||
|
||||
// 启动需要禁用的控件
|
||||
UninstallServiceToolStripMenuItem.Enabled =
|
||||
|
||||
@@ -250,18 +250,15 @@ namespace Netch.Forms
|
||||
ControlFun();
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
if (State == State.Waiting || State == State.Stopped)
|
||||
break;
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
if (State == State.Waiting || State == State.Stopped)
|
||||
break;
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
|
||||
SaveConfigs();
|
||||
State = State.Terminating;
|
||||
});
|
||||
SaveConfigs();
|
||||
State = State.Terminating;
|
||||
}
|
||||
|
||||
#region MISC
|
||||
@@ -467,6 +464,7 @@ namespace Netch.Forms
|
||||
|
||||
private void NotifyTip(string text, int timeout = 0, bool info = true)
|
||||
{
|
||||
// 会阻塞线程 timeout 秒
|
||||
NotifyIcon.ShowBalloonTip(timeout,
|
||||
UpdateChecker.Name,
|
||||
text,
|
||||
|
||||
@@ -35,9 +35,14 @@ namespace Netch.Utils
|
||||
Write(text, LogLevel.ERROR);
|
||||
}
|
||||
|
||||
private static readonly object FileLock = new object();
|
||||
|
||||
private static void Write(string text, LogLevel logLevel)
|
||||
{
|
||||
File.AppendAllText(LogFile, $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}");
|
||||
lock (FileLock)
|
||||
{
|
||||
File.AppendAllText(LogFile, $@"[{DateTime.Now}][{logLevel.ToString()}] {text}{Global.EOF}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user