Config Handler

This commit is contained in:
DHR60 2025-07-24 12:48:52 +08:00
parent c899d534af
commit b8dbe61db3
2 changed files with 149 additions and 78 deletions

View file

@ -1197,43 +1197,6 @@ public class ConfigHandler
return result;
}
/// <summary>
/// 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
/// </summary>
/// <param name="config">Current configuration</param>
/// <param name="node">Server node that might need pre-SOCKS</param>
/// <param name="coreType">Core type being used</param>
/// <returns>A SOCKS profile item or null if not needed</returns>
public static async Task<ProfileItem?> 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;
}
/// <summary>
/// Remove servers with invalid test results (timeout)
/// Useful for cleaning up subscription lists

View file

@ -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)
/// <summary>
/// Core launch context that encapsulates all parameters required for launching
/// </summary>
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;
public CoreLaunchContext(ProfileItem node, Config config)
{
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;
}
/// <summary>
/// Adjust context parameters based on configuration type
/// </summary>
public void AdjustForConfigType()
{
if (Node.ConfigType == EConfigType.Custom)
{
SplitCore = false;
CoreType = Node.CoreType ?? ECoreType.Xray;
if (Node.PreSocksPort > 0)
{
PreCoreType = EnableTun ? ECoreType.sing_box : AppHandler.Instance.GetCoreType(Node, Node.ConfigType);
PreSocksPort = Node.PreSocksPort.Value;
}
else
{
EnableTun = false;
PreCoreType = null;
}
}
}
/// <summary>
/// Adjust split core configuration
/// </summary>
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<bool> 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)
{
return;
}
_process = proc;
UpdateFunc(true, ResUI.FailedToRunCore);
return false;
}
private async Task CoreStartPreService(ProfileItem node)
_process = proc;
_config.RunningCoreType = AppHandler.Instance.GetCoreType(context.Node, context.Node.ConfigType);
return true;
}
private async Task<bool> CoreStartPreService(CoreLaunchContext context)
{
if (_process != null && !_process.HasExited)
if (context.PreCoreType == null)
{
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (itemSocks != null)
{
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
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)
if (!result.Success)
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
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)
if (proc is null || (_process?.HasExited == true))
{
return;
UpdateFunc(true, ResUI.FailedToRunCore);
return false;
}
_processPre = proc;
}
}
}
return true;
}
private void UpdateFunc(bool notify, string msg)