From b8dbe61db394a187f4e5a47a97a077dd300bb408 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Thu, 24 Jul 2025 12:48:52 +0800 Subject: [PATCH] Config Handler --- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 37 ---- v2rayN/ServiceLib/Handler/CoreHandler.cs | 190 ++++++++++++++++----- 2 files changed, 149 insertions(+), 78 deletions(-) diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 063e185a..4e289bd4 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -1197,43 +1197,6 @@ public class ConfigHandler return result; } - /// - /// Get a SOCKS server profile for pre-SOCKS functionality - /// Used when TUN mode is enabled or when a custom config has a pre-SOCKS port - /// - /// Current configuration - /// Server node that might need pre-SOCKS - /// Core type being used - /// A SOCKS profile item or null if not needed - public static async Task GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType) - { - ProfileItem? itemSocks = null; - if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun) - { - itemSocks = new ProfileItem() - { - CoreType = ECoreType.sing_box, - ConfigType = EConfigType.SOCKS, - Address = Global.Loopback, - Sni = node.Address, //Tun2SocksAddress - Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks) - }; - } - else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0)) - { - var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray; - itemSocks = new ProfileItem() - { - CoreType = preCoreType, - ConfigType = EConfigType.SOCKS, - Address = Global.Loopback, - Port = node.PreSocksPort.Value, - }; - } - await Task.CompletedTask; - return itemSocks; - } - /// /// Remove servers with invalid test results (timeout) /// Useful for cleaning up subscription lists diff --git a/v2rayN/ServiceLib/Handler/CoreHandler.cs b/v2rayN/ServiceLib/Handler/CoreHandler.cs index f7ad2285..b7a8b4f5 100644 --- a/v2rayN/ServiceLib/Handler/CoreHandler.cs +++ b/v2rayN/ServiceLib/Handler/CoreHandler.cs @@ -1,5 +1,7 @@ using System.Diagnostics; using System.Text; +using ServiceLib.Enums; +using ServiceLib.Models; namespace ServiceLib.Handler; @@ -71,28 +73,24 @@ public class CoreHandler return; } - var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName); - var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); - if (result.Success != true) + // Create launch context and configure parameters + var context = new CoreLaunchContext(node, _config); + context.AdjustForConfigType(); + context.AdjustForSplitCore(); + + // Start main core + if (!await CoreStart(context)) { - UpdateFunc(true, result.Msg); return; } - UpdateFunc(false, $"{node.GetSummary()}"); - UpdateFunc(false, $"{Utils.GetRuntimeInfo()}"); - UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); - await CoreStop(); - await Task.Delay(100); - - if (Utils.IsWindows() && _config.TunModeItem.EnableTun) + // Start pre-core if needed + if (!await CoreStartPreService(context)) { - await Task.Delay(100); - await WindowsUtils.RemoveTunDevice(); + await CoreStop(); // Clean up main core if pre-core fails + return; } - await CoreStart(node); - await CoreStartPreService(node); if (_process != null) { UpdateFunc(true, $"{node.GetSummary()}"); @@ -181,43 +179,153 @@ public class CoreHandler #region Private - private async Task CoreStart(ProfileItem node) + /// + /// Core launch context that encapsulates all parameters required for launching + /// + private class CoreLaunchContext { - var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType); - var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); + public ProfileItem Node { get; set; } + public bool SplitCore { get; set; } + public ECoreType CoreType { get; set; } + public ECoreType? PreCoreType { get; set; } + public ECoreType PureEndpointCore { get; set; } + public ECoreType SplitRouteCore { get; set; } + public bool EnableTun { get; set; } + public int PreSocksPort { get; set; } - var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog; - var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true); - if (proc is null) + public CoreLaunchContext(ProfileItem node, Config config) { - return; + Node = node; + SplitCore = config.SplitCoreItem.EnableSplitCore; + CoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType); + PureEndpointCore = AppHandler.Instance.GetSplitCoreType(node, node.ConfigType); + SplitRouteCore = config.SplitCoreItem.RouteCoreType; + EnableTun = config.TunModeItem.EnableTun; + PreSocksPort = 0; + PreCoreType = null; } - _process = proc; - } - private async Task CoreStartPreService(ProfileItem node) - { - if (_process != null && !_process.HasExited) + /// + /// Adjust context parameters based on configuration type + /// + public void AdjustForConfigType() { - var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType); - var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType); - if (itemSocks != null) + if (Node.ConfigType == EConfigType.Custom) { - var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box; - var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName); - var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName); - if (result.Success) + SplitCore = false; + CoreType = Node.CoreType ?? ECoreType.Xray; + if (Node.PreSocksPort > 0) { - var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType); - var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true); - if (proc is null) - { - return; - } - _processPre = proc; + PreCoreType = EnableTun ? ECoreType.sing_box : AppHandler.Instance.GetCoreType(Node, Node.ConfigType); + PreSocksPort = Node.PreSocksPort.Value; + } + else + { + EnableTun = false; + PreCoreType = null; } } } + + /// + /// Adjust split core configuration + /// + public void AdjustForSplitCore() + { + if (SplitCore) + { + PreCoreType = EnableTun ? ECoreType.sing_box : SplitRouteCore; + CoreType = PureEndpointCore; + + if (PreCoreType == CoreType) + { + PreCoreType = null; + SplitCore = false; + } + else + { + PreSocksPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.split); + } + } + } + } + + private async Task CoreStart(CoreLaunchContext context) + { + var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName); + var result = context.SplitCore + ? await CoreConfigHandler.GeneratePureEndpointConfig(context.Node, fileName) + : await CoreConfigHandler.GenerateClientConfig(context.Node, fileName); + + if (result.Success != true) + { + UpdateFunc(true, result.Msg); + return false; + } + + UpdateFunc(false, $"{context.Node.GetSummary()}"); + UpdateFunc(false, $"{Utils.GetRuntimeInfo()}"); + UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); + + await CoreStop(); + await Task.Delay(100); + + if (Utils.IsWindows() && _config.TunModeItem.EnableTun) + { + await Task.Delay(100); + await WindowsUtils.RemoveTunDevice(); + } + + var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(context.CoreType); + var displayLog = context.Node.ConfigType != EConfigType.Custom || context.Node.DisplayLog; + var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true); + + if (proc is null) + { + UpdateFunc(true, ResUI.FailedToRunCore); + return false; + } + + _process = proc; + _config.RunningCoreType = AppHandler.Instance.GetCoreType(context.Node, context.Node.ConfigType); + return true; + } + + private async Task CoreStartPreService(CoreLaunchContext context) + { + if (context.PreCoreType == null) + { + return true; // No pre-core needed, consider successful + } + + var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName); + var itemSocks = new ProfileItem() + { + CoreType = context.PreCoreType, + ConfigType = EConfigType.SOCKS, + Address = Global.Loopback, + Sni = context.EnableTun && Utils.IsDomain(context.Node.Address) ? context.Node.Address : string.Empty, //Tun2SocksAddress + Port = context.PreSocksPort + }; + + var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName); + if (!result.Success) + { + UpdateFunc(true, result.Msg); + return false; + } + + var coreInfo = CoreInfoHandler.Instance.GetCoreInfo((ECoreType)context.PreCoreType); + var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true); + + if (proc is null || (_process?.HasExited == true)) + { + UpdateFunc(true, ResUI.FailedToRunCore); + return false; + } + + _processPre = proc; + return true; } private void UpdateFunc(bool notify, string msg)