mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-14 16:35:00 +03:00
5292568150
Introduce a synchronized ConfigState and make ConfigTextManager static. Update configuration access across desktop and WebAPI, and add an AddServer overload using the current configuration.
307 lines
9.6 KiB
C#
307 lines
9.6 KiB
C#
namespace ServiceLib.Manager.Data;
|
|
|
|
public static class ConfigTextManager
|
|
{
|
|
private static readonly string _configRes = Global.ConfigFileName;
|
|
private static readonly string _tag = "ConfigTextManager";
|
|
|
|
public static Config Config
|
|
{
|
|
get => ConfigState.Instance.Current;
|
|
private set => ConfigState.Instance.SetCurrent(value);
|
|
}
|
|
|
|
#region Init
|
|
|
|
public static Config? Init()
|
|
{
|
|
var config = LoadConfig();
|
|
if (config == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
Config = config;
|
|
return Config;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load the application configuration file
|
|
/// If the file exists, deserialize it from JSON
|
|
/// If not found, create a new Config object with default settings
|
|
/// Initialize default values for missing configuration sections
|
|
/// </summary>
|
|
/// <returns>Config object containing application settings or null if there's an error</returns>
|
|
private static Config? LoadConfig()
|
|
{
|
|
Config? config = null;
|
|
var result = EmbedUtils.LoadResource(Utils.GetConfigPath(_configRes));
|
|
if (result.IsNotEmpty())
|
|
{
|
|
config = JsonUtils.Deserialize<Config>(result);
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(Utils.GetConfigPath(_configRes)))
|
|
{
|
|
Logging.SaveLog("LoadConfig Exception");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
config ??= new Config();
|
|
|
|
config.CoreBasicItem ??= new()
|
|
{
|
|
LogEnabled = false,
|
|
Loglevel = "warning",
|
|
};
|
|
|
|
if (config.Inbound == null)
|
|
{
|
|
config.Inbound = [];
|
|
InItem inItem = new()
|
|
{
|
|
Protocol = nameof(EInboundProtocol.socks),
|
|
LocalPort = 10808,
|
|
UdpEnabled = true,
|
|
SniffingEnabled = true,
|
|
RouteOnly = false,
|
|
};
|
|
|
|
config.Inbound.Add(inItem);
|
|
}
|
|
else
|
|
{
|
|
if (config.Inbound.Count > 0)
|
|
{
|
|
config.Inbound.First().Protocol = nameof(EInboundProtocol.socks);
|
|
}
|
|
}
|
|
|
|
config.RoutingBasicItem ??= new();
|
|
if (config.RoutingBasicItem.DomainStrategy.IsNullOrEmpty())
|
|
{
|
|
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
|
|
}
|
|
|
|
config.KcpItem ??= new KcpItem
|
|
{
|
|
Mtu = 1350,
|
|
Tti = 50,
|
|
UplinkCapacity = 12,
|
|
DownlinkCapacity = 100,
|
|
CwndMultiplier = 1,
|
|
MaxSendingWindow = 2 * 1024 * 1024,
|
|
};
|
|
config.KcpItem.CwndMultiplier = config.KcpItem.CwndMultiplier <= 0 ? 1 : config.KcpItem.CwndMultiplier;
|
|
config.KcpItem.MaxSendingWindow = config.KcpItem.MaxSendingWindow <= 0 ? (2 * 1024 * 1024) : config.KcpItem.MaxSendingWindow;
|
|
config.GrpcItem ??= new GrpcItem
|
|
{
|
|
IdleTimeout = 60,
|
|
HealthCheckTimeout = 20,
|
|
PermitWithoutStream = false,
|
|
InitialWindowsSize = 0,
|
|
};
|
|
config.TunModeItem ??= new TunModeItem
|
|
{
|
|
EnableTun = false,
|
|
Mtu = 9000,
|
|
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
|
|
EnableLegacyProtect = true,
|
|
};
|
|
config.GuiItem ??= new();
|
|
if (!Global.RootCertProviders.Contains(config.GuiItem.RootCertProvider))
|
|
{
|
|
config.GuiItem.RootCertProvider = Global.RootCertProviders.First();
|
|
}
|
|
config.MsgUIItem ??= new();
|
|
|
|
config.UiItem ??= new();
|
|
config.UiItem.MainColumnItem ??= [];
|
|
config.UiItem.WindowSizeItem ??= [];
|
|
if (config.UiItem.FrozenColumnCount == null)
|
|
{
|
|
var lvColumnItem = config.UiItem.MainColumnItem.OrderBy(t => t.Index).ToList();
|
|
if (lvColumnItem.Count == 0
|
|
|| (lvColumnItem.Count >= 2
|
|
&& lvColumnItem[0].Name.Equals("ConfigType")
|
|
&& lvColumnItem[1].Name.Equals("Remarks")))
|
|
{
|
|
config.UiItem.FrozenColumnCount = 2;
|
|
}
|
|
else
|
|
{
|
|
config.UiItem.FrozenColumnCount = 0;
|
|
}
|
|
}
|
|
|
|
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
|
{
|
|
config.UiItem.CurrentLanguage = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals("zh", StringComparison.CurrentCultureIgnoreCase)
|
|
? Global.Languages.First()
|
|
: Global.Languages[2];
|
|
}
|
|
|
|
config.ConstItem ??= new ConstItem();
|
|
|
|
config.SimpleDNSItem ??= ConfigDbManager.InitBuiltinSimpleDNS();
|
|
config.SimpleDNSItem.BlockAAAAQuery ??= false;
|
|
config.SimpleDNSItem.FakeIPRange ??= Global.FakeIPRanges.FirstOrDefault();
|
|
config.SimpleDNSItem.FakeIPv6 ??= false;
|
|
config.SimpleDNSItem.FakeIPv6Range ??= Global.FakeIPv6Ranges.First();
|
|
config.SimpleDNSItem.GlobalFakeIp ??= true;
|
|
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
|
config.SimpleDNSItem.ServeStale ??= false;
|
|
config.SimpleDNSItem.ParallelQuery ??= false;
|
|
config.SimpleDNSItem.EnableHappyEyeballs ??= false;
|
|
|
|
config.SpeedTestItem ??= new();
|
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
|
{
|
|
config.SpeedTestItem.SpeedTestTimeout = 10;
|
|
}
|
|
if (config.SpeedTestItem.SpeedTestUrl.IsNullOrEmpty())
|
|
{
|
|
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
|
|
}
|
|
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
|
{
|
|
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrls.First();
|
|
}
|
|
config.SpeedTestItem.MixedConcurrencyCount = Math.Max(config.SpeedTestItem.MixedConcurrencyCount, Global.SpeedTestConcurrencyCountMin);
|
|
if (config.SpeedTestItem.UdpTestTarget.IsNullOrEmpty())
|
|
{
|
|
config.SpeedTestItem.UdpTestTarget = Global.UdpTestTargets.First();
|
|
}
|
|
|
|
config.Mux4RayItem ??= new()
|
|
{
|
|
Concurrency = 8,
|
|
XudpConcurrency = 16,
|
|
XudpProxyUDP443 = "reject"
|
|
};
|
|
|
|
config.Mux4SboxItem ??= new()
|
|
{
|
|
Protocol = Global.SingboxMuxs.First(),
|
|
MaxConnections = 8
|
|
};
|
|
|
|
config.HysteriaItem ??= new()
|
|
{
|
|
UpMbps = 100,
|
|
DownMbps = 100
|
|
};
|
|
config.ClashUIItem ??= new();
|
|
config.ClashUIItem.ConnectionsColumnItem ??= [];
|
|
config.SystemProxyItem ??= new();
|
|
config.WebDavItem ??= new();
|
|
config.CheckUpdateItem ??= new();
|
|
config.Fragment4RayItem ??= new()
|
|
{
|
|
Packets = "tlshello",
|
|
};
|
|
config.Fragment4RayItem.MaxSplit ??= "0";
|
|
|
|
config.HappyEyeballs4RayItem ??= new()
|
|
{
|
|
TryDelayMs = 250,
|
|
PrioritizeIPv6 = false,
|
|
Interleave = 1,
|
|
MaxConcurrentTry = 4,
|
|
};
|
|
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
|
|
{
|
|
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
|
|
}
|
|
if ((config.Fragment4RayItem.Delays ?? []).Count == 0)
|
|
{
|
|
config.Fragment4RayItem.Delays = [config.Fragment4RayItem.Interval ?? "10-20"];
|
|
}
|
|
config.GlobalHotkeys ??= [];
|
|
|
|
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
|
{
|
|
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save the configuration to a file
|
|
/// First writes to a temporary file, then replaces the original file
|
|
/// </summary>
|
|
/// <param name="_config">Configuration object to be saved</param>
|
|
/// <returns>0 if successful, -1 if failed</returns>
|
|
public static async Task<int> SaveConfig()
|
|
{
|
|
try
|
|
{
|
|
//save temp file
|
|
var resPath = Utils.GetConfigPath(_configRes);
|
|
var tempPath = $"{resPath}_temp";
|
|
|
|
var content = JsonUtils.Serialize(Config, true, true);
|
|
if (content.IsNullOrEmpty())
|
|
{
|
|
return -1;
|
|
}
|
|
await File.WriteAllTextAsync(tempPath, content);
|
|
|
|
//rename
|
|
File.Move(tempPath, resPath, true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logging.SaveLog(_tag, ex);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endregion Init
|
|
|
|
#region UIItem
|
|
|
|
public static WindowSizeItem? GetWindowSizeItem(string typeName)
|
|
{
|
|
var sizeItem = Config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
|
if (sizeItem == null || sizeItem.Width <= 0 || sizeItem.Height <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return sizeItem;
|
|
}
|
|
|
|
public static int SaveWindowSizeItem(string typeName, double width, double height)
|
|
{
|
|
var sizeItem = Config?.UiItem?.WindowSizeItem?.FirstOrDefault(t => t.TypeName == typeName);
|
|
if (sizeItem == null)
|
|
{
|
|
sizeItem = new WindowSizeItem { TypeName = typeName };
|
|
Config.UiItem.WindowSizeItem.Add(sizeItem);
|
|
}
|
|
|
|
sizeItem.Width = (int)width;
|
|
sizeItem.Height = (int)height;
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int SaveMainGirdHeight(double height1, double height2)
|
|
{
|
|
var uiItem = Config.UiItem ?? new();
|
|
|
|
uiItem.MainGirdHeight1 = (int)(height1 + 0.1);
|
|
uiItem.MainGirdHeight2 = (int)(height2 + 0.1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endregion UIItem
|
|
}
|