mirror of
https://github.com/netchx/netch.git
synced 2026-05-07 22:44:03 +08:00
Fix repository
This commit is contained in:
@@ -1,92 +1,196 @@
|
||||
namespace Netch.Controllers
|
||||
{
|
||||
public class MainController : Interface.IController
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点控制器
|
||||
/// </summary>
|
||||
private Interface.IController NodeController;
|
||||
|
||||
/// <summary>
|
||||
/// 模式控制器
|
||||
/// </summary>
|
||||
private Interface.IController ModeController;
|
||||
|
||||
public bool Create(Models.Server.Server s, Models.Mode.Mode m)
|
||||
{
|
||||
switch (s.Type)
|
||||
{
|
||||
case Models.Server.ServerType.Socks:
|
||||
break;
|
||||
case Models.Server.ServerType.Shadowsocks:
|
||||
this.NodeController = new Server.ShadowsocksController();
|
||||
break;
|
||||
case Models.Server.ServerType.ShadowsocksR:
|
||||
this.NodeController = new Server.ShadowsocksRController();
|
||||
break;
|
||||
case Models.Server.ServerType.WireGuard:
|
||||
this.NodeController = new Server.WireGuardController();
|
||||
break;
|
||||
case Models.Server.ServerType.Trojan:
|
||||
this.NodeController = new Server.TrojanController();
|
||||
break;
|
||||
case Models.Server.ServerType.VMess:
|
||||
this.NodeController = new Server.VMessController();
|
||||
break;
|
||||
case Models.Server.ServerType.VLess:
|
||||
this.NodeController = new Server.VLessController();
|
||||
break;
|
||||
default:
|
||||
Global.Logger.Error($"未知的节点类型:{s.Type}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
var status = this.NodeController?.Create(s, m);
|
||||
if (status.HasValue && !status.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m.Type)
|
||||
{
|
||||
case Models.Mode.ModeType.ProcessMode:
|
||||
this.ModeController = new Mode.ProcessController();
|
||||
break;
|
||||
case Models.Mode.ModeType.ShareMode:
|
||||
this.ModeController = new Mode.ShareController();
|
||||
break;
|
||||
case Models.Mode.ModeType.TunMode:
|
||||
this.ModeController = new Mode.TunController();
|
||||
break;
|
||||
case Models.Mode.ModeType.WebMode:
|
||||
this.ModeController = new Mode.WebController();
|
||||
break;
|
||||
default:
|
||||
Global.Logger.Error($"未知的模式类型:{s.Type}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
var status = this.ModeController?.Create(s, m);
|
||||
if (status.HasValue && !status.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
{
|
||||
this.NodeController?.Delete();
|
||||
this.ModeController?.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Diagnostics;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Netch.Interfaces;
|
||||
using Netch.Models;
|
||||
using Netch.Models.Modes;
|
||||
using Netch.Servers;
|
||||
using Netch.Services;
|
||||
using Netch.Utils;
|
||||
|
||||
namespace Netch.Controllers;
|
||||
|
||||
public static class MainController
|
||||
{
|
||||
public static Socks5Server? Socks5Server { get; private set; }
|
||||
|
||||
public static Server? Server { get; private set; }
|
||||
|
||||
public static Mode? Mode { get; private set; }
|
||||
|
||||
public static IServerController? ServerController { get; private set; }
|
||||
|
||||
public static IModeController? ModeController { get; private set; }
|
||||
|
||||
private static readonly AsyncSemaphore Lock = new(1);
|
||||
|
||||
public static async Task StartAsync(Server server, Mode mode)
|
||||
{
|
||||
using var releaser = await Lock.EnterAsync();
|
||||
|
||||
Log.Information("Start MainController: {Server} {Mode}", $"{server.Type}", $"[{(int)mode.Type}]{mode.i18NRemark}");
|
||||
|
||||
if (await DnsUtils.LookupAsync(server.Hostname) == null)
|
||||
throw new MessageException(i18N.Translate("Lookup Server hostname failed"));
|
||||
|
||||
// TODO Disable NAT Type Test setting
|
||||
// cache STUN Server ip to prevent "Wrong STUN Server"
|
||||
DnsUtils.LookupAsync(Global.Settings.STUN_Server).Forget();
|
||||
|
||||
Server = server;
|
||||
Mode = mode;
|
||||
|
||||
await Task.WhenAll(Task.Run(NativeMethods.RefreshDNSCache), Task.Run(Firewall.AddNetchFwRules));
|
||||
|
||||
try
|
||||
{
|
||||
ModeController = ModeService.GetModeControllerByType(mode.Type, out var modePort, out var portName);
|
||||
|
||||
if (modePort != null)
|
||||
TryReleaseTcpPort((ushort)modePort, portName);
|
||||
|
||||
if (Server is Socks5Server socks5 && (!socks5.Auth() || ModeController.Features.HasFlag(ModeFeature.SupportSocks5Auth)))
|
||||
{
|
||||
Socks5Server = socks5;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start Server Controller to get a local socks5 server
|
||||
Log.Debug("Server Information: {Data}", $"{server.Type} {server.MaskedData()}");
|
||||
|
||||
ServerController = ServerHelper.GetUtilByTypeName(server.Type).GetController();
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ServerController.Name));
|
||||
|
||||
TryReleaseTcpPort(ServerController.Socks5LocalPort(), "Socks5");
|
||||
Socks5Server = await ServerController.StartAsync(server);
|
||||
|
||||
StatusPortInfoText.Socks5Port = Socks5Server.Port;
|
||||
StatusPortInfoText.UpdateShareLan();
|
||||
}
|
||||
|
||||
// Start Mode Controller
|
||||
Global.MainForm.StatusText(i18N.TranslateFormat("Starting {0}", ModeController.Name));
|
||||
|
||||
await ModeController.StartAsync(Socks5Server, mode);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
releaser.Dispose();
|
||||
await StopAsync();
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case DllNotFoundException:
|
||||
case FileNotFoundException:
|
||||
throw new Exception(e.Message + "\n\n" + i18N.Translate("Missing File or runtime components"));
|
||||
case MessageException:
|
||||
throw;
|
||||
default:
|
||||
Log.Error(e, "Unhandled Exception When Start MainController");
|
||||
Utils.Utils.Open(Constants.LogFile);
|
||||
throw new MessageException($"{i18N.Translate("Unhandled Exception")}\n{e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task StopAsync()
|
||||
{
|
||||
if (Lock.CurrentCount == 0)
|
||||
{
|
||||
(await Lock.EnterAsync()).Dispose();
|
||||
if (ServerController == null && ModeController == null)
|
||||
// stopped
|
||||
return;
|
||||
|
||||
// else begin stop
|
||||
}
|
||||
|
||||
using var _ = await Lock.EnterAsync();
|
||||
|
||||
if (ServerController == null && ModeController == null)
|
||||
return;
|
||||
|
||||
Log.Information("Stop Main Controller");
|
||||
StatusPortInfoText.Reset();
|
||||
|
||||
var tasks = new[]
|
||||
{
|
||||
ServerController?.StopAsync() ?? Task.CompletedTask,
|
||||
ModeController?.StopAsync() ?? Task.CompletedTask
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "MainController Stop Error");
|
||||
}
|
||||
|
||||
ServerController = null;
|
||||
ModeController = null;
|
||||
}
|
||||
|
||||
public static void PortCheck(ushort port, string portName, PortType portType = PortType.Both)
|
||||
{
|
||||
try
|
||||
{
|
||||
PortHelper.CheckPort(port, portType);
|
||||
}
|
||||
catch (PortInUseException)
|
||||
{
|
||||
throw new MessageException(i18N.TranslateFormat("The {0} port is in use.", $"{portName} ({port})"));
|
||||
}
|
||||
catch (PortReservedException)
|
||||
{
|
||||
throw new MessageException(i18N.TranslateFormat("The {0} port is reserved by system.", $"{portName} ({port})"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void TryReleaseTcpPort(ushort port, string portName)
|
||||
{
|
||||
foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
|
||||
{
|
||||
var fileName = p.MainModule?.FileName;
|
||||
if (fileName == null)
|
||||
continue;
|
||||
|
||||
if (fileName.StartsWith(Global.NetchDir))
|
||||
{
|
||||
p.Kill();
|
||||
p.WaitForExit();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageException(i18N.TranslateFormat("The {0} port is used by {1}.", $"{portName} ({port})", $"({p.Id}){fileName}"));
|
||||
}
|
||||
}
|
||||
|
||||
PortCheck(port, portName, PortType.TCP);
|
||||
}
|
||||
|
||||
public static Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
return Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
|
||||
}
|
||||
|
||||
public static Task<int?> HttpConnectAsync(CancellationToken ctx = default)
|
||||
{
|
||||
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
|
||||
try
|
||||
{
|
||||
return Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warning(e, "Unhandled Socks5ServerTestUtils.HttpConnectAsync Exception");
|
||||
}
|
||||
|
||||
return Task.FromResult<int?>(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user