mirror of
https://github.com/2dust/v2rayN.git
synced 2026-04-16 12:35:46 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
fa9709da07
43 changed files with 617 additions and 648 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.19.0</Version>
|
||||
<Version>7.19.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.3" />
|
||||
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.3" />
|
||||
<PackageVersion Include="NLog" Version="6.1.0" />
|
||||
<PackageVersion Include="NLog" Version="6.1.1" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||
|
|
|
|||
|
|
@ -497,6 +497,13 @@ public class Utils
|
|||
return false;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(domain);
|
||||
if (ext.IsNotEmpty()
|
||||
&& ext[1..].ToLowerInvariant() is "json" or "txt" or "xml" or "cfg" or "ini" or "log" or "yaml" or "yml" or "toml")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Uri.CheckHostName(domain) == UriHostNameType.Dns;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public class Global
|
|||
public const string DirectTag = "direct";
|
||||
public const string BlockTag = "block";
|
||||
public const string DnsTag = "dns-module";
|
||||
public const string DirectDnsTag = "direct-dns";
|
||||
public const string BalancerTagSuffix = "-round";
|
||||
public const string StreamSecurity = "tls";
|
||||
public const string StreamSecurityReality = "reality";
|
||||
|
|
@ -90,6 +91,22 @@ public class Global
|
|||
|
||||
public const int Hysteria2DefaultHopInt = 10;
|
||||
|
||||
public const string PolicyGroupExcludeKeywords = @"剩余|过期|到期|重置|[Rr]emaining|[Ee]xpir|[Rr]eset";
|
||||
|
||||
public const string PolicyGroupDefaultAllFilter = $"^(?!.*(?:{PolicyGroupExcludeKeywords})).*$";
|
||||
|
||||
public static readonly List<string> PolicyGroupDefaultFilterList =
|
||||
[
|
||||
// All nodes (exclude traffic/expiry info)
|
||||
PolicyGroupDefaultAllFilter,
|
||||
// Low multiplier nodes, e.g. ×0.1, 0.5x, 0.1倍
|
||||
@"^.*(?:[×xX✕*]\s*0\.[0-9]+|0\.[0-9]+\s*[×xX✕*倍]).*$",
|
||||
// Dedicated line nodes, e.g. IPLC, IEPL
|
||||
$@"^(?!.*(?:{PolicyGroupExcludeKeywords})).*(?:专线|IPLC|IEPL|中转).*$",
|
||||
// Japan nodes
|
||||
$@"^(?!.*(?:{PolicyGroupExcludeKeywords})).*(?:日本|\\b[Jj][Pp]\\b|🇯🇵|[Jj]apan).*$",
|
||||
];
|
||||
|
||||
public static readonly List<string> IEProxyProtocols =
|
||||
[
|
||||
"{ip}:{http_port}",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,39 @@ public record CoreConfigContextBuilderResult(CoreConfigContext Context, NodeVali
|
|||
public bool Success => ValidatorResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the results of a full context build, including the main context and an optional
|
||||
/// pre-socks context (e.g. for TUN protection or pre-socks chaining).
|
||||
/// </summary>
|
||||
public record CoreConfigContextBuilderAllResult(
|
||||
CoreConfigContextBuilderResult MainResult,
|
||||
CoreConfigContextBuilderResult? PreSocksResult)
|
||||
{
|
||||
/// <summary>True only when both the main result and (if present) the pre-socks result succeeded.</summary>
|
||||
public bool Success => MainResult.Success && (PreSocksResult?.Success ?? true);
|
||||
|
||||
/// <summary>
|
||||
/// Merges all errors and warnings from the main result and the optional pre-socks result
|
||||
/// into a single <see cref="NodeValidatorResult"/> for unified notification.
|
||||
/// </summary>
|
||||
public NodeValidatorResult CombinedValidatorResult => new(
|
||||
[.. MainResult.ValidatorResult.Errors, .. PreSocksResult?.ValidatorResult.Errors ?? []],
|
||||
[.. MainResult.ValidatorResult.Warnings, .. PreSocksResult?.ValidatorResult.Warnings ?? []]);
|
||||
|
||||
/// <summary>
|
||||
/// The main context with TunProtectSsPort/ProxyRelaySsPort and ProtectDomainList merged in
|
||||
/// from the pre-socks result (if any). Pass this to the core runner.
|
||||
/// </summary>
|
||||
public CoreConfigContext ResolvedMainContext => PreSocksResult is not null
|
||||
? MainResult.Context with
|
||||
{
|
||||
TunProtectSsPort = PreSocksResult.Context.TunProtectSsPort,
|
||||
ProxyRelaySsPort = PreSocksResult.Context.ProxyRelaySsPort,
|
||||
ProtectDomainList = [.. MainResult.Context.ProtectDomainList ?? [], .. PreSocksResult.Context.ProtectDomainList ?? []],
|
||||
}
|
||||
: MainResult.Context;
|
||||
}
|
||||
|
||||
public class CoreConfigContextBuilder
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -75,6 +108,79 @@ public class CoreConfigContextBuilder
|
|||
return new CoreConfigContextBuilderResult(context, validatorResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the main <see cref="CoreConfigContext"/> for <paramref name="node"/> and, when
|
||||
/// the main build succeeds, also builds the optional pre-socks context required for TUN
|
||||
/// protection or pre-socks proxy chaining.
|
||||
/// </summary>
|
||||
public static async Task<CoreConfigContextBuilderAllResult> BuildAll(Config config, ProfileItem node)
|
||||
{
|
||||
var mainResult = await Build(config, node);
|
||||
if (!mainResult.Success)
|
||||
{
|
||||
return new CoreConfigContextBuilderAllResult(mainResult, null);
|
||||
}
|
||||
|
||||
var preResult = await BuildPreSocksIfNeeded(mainResult.Context);
|
||||
return new CoreConfigContextBuilderAllResult(mainResult, preResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a pre-socks context is required for <paramref name="nodeContext"/>
|
||||
/// and, if so, builds and returns it. Returns <c>null</c> when no pre-socks core is needed.
|
||||
/// </summary>
|
||||
private static async Task<CoreConfigContextBuilderResult?> BuildPreSocksIfNeeded(CoreConfigContext nodeContext)
|
||||
{
|
||||
var config = nodeContext.AppConfig;
|
||||
var node = nodeContext.Node;
|
||||
var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
|
||||
|
||||
var preSocksItem = ConfigHandler.GetPreSocksItem(config, node, coreType);
|
||||
if (preSocksItem != null)
|
||||
{
|
||||
var preSocksResult = await Build(nodeContext.AppConfig, preSocksItem);
|
||||
return preSocksResult with
|
||||
{
|
||||
Context = preSocksResult.Context with
|
||||
{
|
||||
ProtectDomainList = [.. nodeContext.ProtectDomainList ?? [], .. preSocksResult.Context.ProtectDomainList ?? []],
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (!nodeContext.IsTunEnabled
|
||||
|| coreType != ECoreType.Xray
|
||||
|| node.ConfigType == EConfigType.Custom)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var tunProtectSsPort = Utils.GetFreePort();
|
||||
var proxyRelaySsPort = Utils.GetFreePort();
|
||||
var preItem = new ProfileItem()
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.Shadowsocks,
|
||||
Address = Global.Loopback,
|
||||
Port = proxyRelaySsPort,
|
||||
Password = Global.None,
|
||||
};
|
||||
preItem.SetProtocolExtra(preItem.GetProtocolExtra() with
|
||||
{
|
||||
SsMethod = Global.None,
|
||||
});
|
||||
var preResult2 = await Build(nodeContext.AppConfig, preItem);
|
||||
return preResult2 with
|
||||
{
|
||||
Context = preResult2.Context with
|
||||
{
|
||||
ProtectDomainList = [.. nodeContext.ProtectDomainList ?? [], .. preResult2.Context.ProtectDomainList ?? []],
|
||||
TunProtectSsPort = tunProtectSsPort,
|
||||
ProxyRelaySsPort = proxyRelaySsPort,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a node into the context, optionally wrapping it in a subscription-level proxy chain.
|
||||
/// Returns the effective (possibly replaced) node and the validation result.
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ public static class ConfigHandler
|
|||
item.Address = profileItem.Address;
|
||||
item.Port = profileItem.Port;
|
||||
|
||||
item.Username = profileItem.Username;
|
||||
item.Password = profileItem.Password;
|
||||
|
||||
item.Network = profileItem.Network;
|
||||
|
|
@ -1165,46 +1166,28 @@ public static class ConfigHandler
|
|||
|
||||
/// <summary>
|
||||
/// Create a group server that combines multiple servers for load balancing
|
||||
/// Generates a configuration file that references multiple servers
|
||||
/// Generates a PolicyGroup profile with references to the sub-items
|
||||
/// </summary>
|
||||
/// <param name="config">Current configuration</param>
|
||||
/// <param name="selecteds">Selected servers to combine</param>
|
||||
/// <param name="coreType">Core type to use (Xray or sing_box)</param>
|
||||
/// <param name="multipleLoad">Load balancing algorithm</param>
|
||||
/// <param name="subItem">Sub-item for grouping</param>
|
||||
/// <returns>Result object with success state and data</returns>
|
||||
public static async Task<RetResult> AddGroupServer4Multiple(Config config, List<ProfileItem> selecteds, ECoreType coreType, EMultipleLoad multipleLoad, string? subId)
|
||||
public static async Task<RetResult> AddGroupAllServer(Config config, SubItem? subItem)
|
||||
{
|
||||
var result = new RetResult();
|
||||
|
||||
var indexId = Utils.GetGuid(false);
|
||||
var childProfileIndexId = Utils.List2String(selecteds.Select(p => p.IndexId).ToList());
|
||||
var subId = subItem?.Id;
|
||||
if (subId.IsNullOrEmpty())
|
||||
{
|
||||
result.Success = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
var remark = subId.IsNullOrEmpty() ? string.Empty : $"{(await AppManager.Instance.GetSubItem(subId))?.Remarks} ";
|
||||
if (coreType == ECoreType.Xray)
|
||||
{
|
||||
remark += multipleLoad switch
|
||||
{
|
||||
EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerXrayLeastPing,
|
||||
EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerXrayFallback,
|
||||
EMultipleLoad.Random => ResUI.menuGenGroupMultipleServerXrayRandom,
|
||||
EMultipleLoad.RoundRobin => ResUI.menuGenGroupMultipleServerXrayRoundRobin,
|
||||
EMultipleLoad.LeastLoad => ResUI.menuGenGroupMultipleServerXrayLeastLoad,
|
||||
_ => ResUI.menuGenGroupMultipleServerXrayRoundRobin,
|
||||
};
|
||||
}
|
||||
else if (coreType == ECoreType.sing_box)
|
||||
{
|
||||
remark += multipleLoad switch
|
||||
{
|
||||
EMultipleLoad.LeastPing => ResUI.menuGenGroupMultipleServerSingBoxLeastPing,
|
||||
EMultipleLoad.Fallback => ResUI.menuGenGroupMultipleServerSingBoxFallback,
|
||||
_ => ResUI.menuGenGroupMultipleServerSingBoxLeastPing,
|
||||
};
|
||||
}
|
||||
var indexId = Utils.GetGuid(false);
|
||||
var remark = $"{subItem.Remarks} - {ResUI.TbConfigTypePolicyGroup}";
|
||||
var profile = new ProfileItem
|
||||
{
|
||||
IndexId = indexId,
|
||||
CoreType = coreType,
|
||||
CoreType = ECoreType.Xray,
|
||||
ConfigType = EConfigType.PolicyGroup,
|
||||
Remarks = remark,
|
||||
IsSub = false
|
||||
|
|
@ -1215,8 +1198,10 @@ public static class ConfigHandler
|
|||
}
|
||||
var extraItem = new ProtocolExtraItem
|
||||
{
|
||||
ChildItems = childProfileIndexId,
|
||||
MultipleLoad = multipleLoad,
|
||||
MultipleLoad = EMultipleLoad.LeastPing,
|
||||
GroupType = profile.ConfigType.ToString(),
|
||||
SubChildItems = subId,
|
||||
Filter = Global.PolicyGroupDefaultAllFilter,
|
||||
};
|
||||
profile.SetProtocolExtra(extraItem);
|
||||
var ret = await AddServerCommon(config, profile, true);
|
||||
|
|
@ -1225,6 +1210,92 @@ public static class ConfigHandler
|
|||
return result;
|
||||
}
|
||||
|
||||
private static string CombineWithDefaultAllFilter(string regionPattern)
|
||||
{
|
||||
return $"^(?!.*(?:{Global.PolicyGroupExcludeKeywords})).*(?:{regionPattern}).*$";
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> PolicyGroupRegionFilters = new()
|
||||
{
|
||||
{ "JP", "日本|\\b[Jj][Pp]\\b|🇯🇵|[Jj]apan" },
|
||||
{ "US", "美国|\\b[Uu][Ss]\\b|🇺🇸|[Uu]nited [Ss]tates|\\b[Uu][Ss][Aa]\\b" },
|
||||
{ "HK", "香港|\\b[Hh][Kk]\\b|🇭🇰|[Hh]ong ?[Kk]ong" },
|
||||
{ "TW", "台湾|台灣|\\b[Tt][Ww]\\b|🇹🇼|[Tt]aiwan" },
|
||||
{ "KR", "韩国|\\b[Kk][Rr]\\b|🇰🇷|[Kk]orea" },
|
||||
{ "SG", "新加坡|\\b[Ss][Gg]\\b|🇸🇬|[Ss]ingapore" },
|
||||
{ "DE", "德国|\\b[Dd][Ee]\\b|🇩🇪|[Gg]ermany" },
|
||||
{ "FR", "法国|\\b[Ff][Rr]\\b|🇫🇷|[Ff]rance" },
|
||||
{ "GB", "英国|\\b[Gg][Bb]\\b|🇬🇧|[Uu]nited [Kk]ingdom|[Bb]ritain" },
|
||||
{ "CA", "加拿大|🇨🇦|[Cc]anada" },
|
||||
{ "AU", "澳大利亚|\\b[Aa][Uu]\\b|🇦🇺|[Aa]ustralia" },
|
||||
{ "RU", "俄罗斯|\\b[Rr][Uu]\\b|🇷🇺|[Rr]ussia" },
|
||||
{ "BR", "巴西|\\b[Bb][Rr]\\b|🇧🇷|[Bb]razil" },
|
||||
{ "IN", "印度|🇮🇳|[Ii]ndia" },
|
||||
{ "VN", "越南|\\b[Vv][Nn]\\b|🇻🇳|[Vv]ietnam" },
|
||||
{ "ID", "印度尼西亚|\\b[Ii][Dd]\\b|🇮🇩|[Ii]ndonesia" },
|
||||
{ "MX", "墨西哥|\\b[Mm][Xx]\\b|🇲🇽|[Mm]exico" }
|
||||
};
|
||||
|
||||
public static async Task<RetResult> AddGroupRegionServer(Config config, SubItem? subItem)
|
||||
{
|
||||
var result = new RetResult();
|
||||
var subId = subItem?.Id;
|
||||
if (subId.IsNullOrEmpty())
|
||||
{
|
||||
result.Success = false;
|
||||
return result;
|
||||
}
|
||||
var childProfiles = await AppManager.Instance.ProfileItems(subId);
|
||||
List<string> indexIdList = [];
|
||||
|
||||
foreach (var regionFilter in PolicyGroupRegionFilters)
|
||||
{
|
||||
var indexId = Utils.GetGuid(false);
|
||||
var remark = $"{subItem.Remarks} - {ResUI.TbConfigTypePolicyGroup} - {regionFilter.Key}";
|
||||
var profile = new ProfileItem
|
||||
{
|
||||
IndexId = indexId,
|
||||
CoreType = ECoreType.Xray,
|
||||
ConfigType = EConfigType.PolicyGroup,
|
||||
Remarks = remark,
|
||||
IsSub = false
|
||||
};
|
||||
if (!subId.IsNullOrEmpty())
|
||||
{
|
||||
profile.Subid = subId;
|
||||
}
|
||||
var extraItem = new ProtocolExtraItem
|
||||
{
|
||||
MultipleLoad = EMultipleLoad.LeastPing,
|
||||
GroupType = profile.ConfigType.ToString(),
|
||||
SubChildItems = subId,
|
||||
Filter = CombineWithDefaultAllFilter(regionFilter.Value),
|
||||
};
|
||||
profile.SetProtocolExtra(extraItem);
|
||||
|
||||
var matchedChildProfiles = childProfiles?.Where(p =>
|
||||
p != null &&
|
||||
p.IsValid() &&
|
||||
!p.ConfigType.IsComplexType() &&
|
||||
(extraItem.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extraItem.Filter))
|
||||
)
|
||||
.ToList() ?? [];
|
||||
if (matchedChildProfiles.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ret = await AddServerCommon(config, profile, true);
|
||||
if (ret == 0)
|
||||
{
|
||||
indexIdList.Add(indexId);
|
||||
}
|
||||
}
|
||||
result.Success = indexIdList.Count > 0;
|
||||
result.Data = indexIdList;
|
||||
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
|
||||
|
|
@ -1251,47 +1322,6 @@ public static class ConfigHandler
|
|||
return itemSocks;
|
||||
}
|
||||
|
||||
public static CoreConfigContext? GetPreSocksCoreConfigContext(CoreConfigContext nodeContext)
|
||||
{
|
||||
var config = nodeContext.AppConfig;
|
||||
var node = nodeContext.Node;
|
||||
var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
|
||||
|
||||
var preSocksItem = GetPreSocksItem(config, node, coreType);
|
||||
if (preSocksItem != null)
|
||||
{
|
||||
return nodeContext with { Node = preSocksItem, };
|
||||
}
|
||||
|
||||
if ((!nodeContext.IsTunEnabled)
|
||||
|| coreType != ECoreType.Xray
|
||||
|| node.ConfigType == EConfigType.Custom)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var tunProtectSsPort = Utils.GetFreePort();
|
||||
var proxyRelaySsPort = Utils.GetFreePort();
|
||||
var preItem = new ProfileItem()
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.Shadowsocks,
|
||||
Address = Global.Loopback,
|
||||
Port = proxyRelaySsPort,
|
||||
Password = Global.None,
|
||||
};
|
||||
preItem.SetProtocolExtra(preItem.GetProtocolExtra() with
|
||||
{
|
||||
SsMethod = Global.None,
|
||||
});
|
||||
var preContext = nodeContext with
|
||||
{
|
||||
Node = preItem,
|
||||
TunProtectSsPort = tunProtectSsPort,
|
||||
ProxyRelaySsPort = proxyRelaySsPort,
|
||||
};
|
||||
return preContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove servers with invalid test results (timeout)
|
||||
/// Useful for cleaning up subscription lists
|
||||
|
|
|
|||
|
|
@ -99,11 +99,9 @@ public static class CoreConfigHandler
|
|||
};
|
||||
var builderResult = await CoreConfigContextBuilder.Build(config, dummyNode);
|
||||
var context = builderResult.Context;
|
||||
var ids = selecteds.Where(serverTestItem => !serverTestItem.IndexId.IsNullOrEmpty())
|
||||
.Select(serverTestItem => serverTestItem.IndexId);
|
||||
var nodes = await AppManager.Instance.GetProfileItemsByIndexIds(ids);
|
||||
foreach (var node in nodes)
|
||||
foreach (var testItem in selecteds)
|
||||
{
|
||||
var node = testItem.Profile;
|
||||
var (actNode, _) = await CoreConfigContextBuilder.ResolveNodeAsync(context, node, true);
|
||||
if (node.IndexId == actNode.IndexId)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -242,6 +242,30 @@ public sealed class AppManager
|
|||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ProfileItem>> GetProfileItemsByIndexIdsAsMap(IEnumerable<string> indexIds)
|
||||
{
|
||||
var items = await GetProfileItemsByIndexIds(indexIds);
|
||||
return items.ToDictionary(it => it.IndexId);
|
||||
}
|
||||
|
||||
public async Task<List<ProfileItem>> GetProfileItemsOrderedByIndexIds(IEnumerable<string> indexIds)
|
||||
{
|
||||
var idList = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList();
|
||||
if (idList.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var items = await SQLiteHelper.Instance.TableAsync<ProfileItem>()
|
||||
.Where(it => idList.Contains(it.IndexId))
|
||||
.ToListAsync();
|
||||
var itemMap = items.ToDictionary(it => it.IndexId);
|
||||
|
||||
return idList.Select(id => itemMap.GetValueOrDefault(id))
|
||||
.Where(item => item != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
|
||||
{
|
||||
if (remarks.IsNullOrEmpty())
|
||||
|
|
|
|||
|
|
@ -57,27 +57,19 @@ public class CoreManager
|
|||
}
|
||||
}
|
||||
|
||||
public async Task LoadCore(CoreConfigContext? context)
|
||||
/// <param name="mainContext">Resolved main context (with pre-socks ports already merged if applicable).</param>
|
||||
/// <param name="preContext">Optional pre-socks context passed to <see cref="CoreStartPreService"/>.</param>
|
||||
public async Task LoadCore(CoreConfigContext? mainContext, CoreConfigContext? preContext)
|
||||
{
|
||||
if (context == null)
|
||||
if (mainContext == null)
|
||||
{
|
||||
await UpdateFunc(false, ResUI.CheckServerSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
var contextMod = context;
|
||||
var node = contextMod.Node;
|
||||
var node = mainContext.Node;
|
||||
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
|
||||
var preContext = ConfigHandler.GetPreSocksCoreConfigContext(contextMod);
|
||||
if (preContext is not null)
|
||||
{
|
||||
contextMod = contextMod with
|
||||
{
|
||||
TunProtectSsPort = preContext.TunProtectSsPort,
|
||||
ProxyRelaySsPort = preContext.ProxyRelaySsPort,
|
||||
};
|
||||
}
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(contextMod, fileName);
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(mainContext, fileName);
|
||||
if (result.Success != true)
|
||||
{
|
||||
await UpdateFunc(true, result.Msg);
|
||||
|
|
@ -96,7 +88,7 @@ public class CoreManager
|
|||
await WindowsUtils.RemoveTunDevice();
|
||||
}
|
||||
|
||||
await CoreStart(contextMod);
|
||||
await CoreStart(mainContext);
|
||||
await CoreStartPreService(preContext);
|
||||
if (_processService != null)
|
||||
{
|
||||
|
|
@ -106,7 +98,7 @@ public class CoreManager
|
|||
|
||||
public async Task<ProcessService?> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||
{
|
||||
var coreType = selecteds.Any(t => Global.SingboxOnlyConfigType.Contains(t.ConfigType)) ? ECoreType.sing_box : ECoreType.Xray;
|
||||
var coreType = selecteds.FirstOrDefault()?.CoreType == ECoreType.sing_box ? ECoreType.sing_box : ECoreType.Xray;
|
||||
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||
var configPath = Utils.GetBinConfigPath(fileName);
|
||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ public class GroupProfileManager
|
|||
return false;
|
||||
}
|
||||
|
||||
foreach (var child in childIds)
|
||||
var childItems = await AppManager.Instance.GetProfileItemsByIndexIds(childIds);
|
||||
foreach (var childItem in childItems)
|
||||
{
|
||||
var childItem = await AppManager.Instance.GetProfileItem(child);
|
||||
if (await HasCycle(child, childItem?.GetProtocolExtra(), visited, stack))
|
||||
if (await HasCycle(childItem.IndexId, childItem?.GetProtocolExtra(), visited, stack))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -103,26 +103,7 @@ public class GroupProfileManager
|
|||
return [];
|
||||
}
|
||||
|
||||
var childProfiles = await AppManager.Instance.GetProfileItemsByIndexIds(childProfileIds);
|
||||
if (childProfiles == null || childProfiles.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var profileMap = childProfiles
|
||||
.Where(p => p != null && !p.IndexId.IsNullOrEmpty())
|
||||
.GroupBy(p => p!.IndexId!)
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
|
||||
var ordered = new List<ProfileItem>(childProfileIds.Count);
|
||||
foreach (var id in childProfileIds)
|
||||
{
|
||||
if (id != null && profileMap.TryGetValue(id, out var item) && item != null)
|
||||
{
|
||||
ordered.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
var ordered = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childProfileIds);
|
||||
return ordered;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,4 +38,25 @@ public class NoticeManager
|
|||
Enqueue(msg);
|
||||
SendMessage(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends each error and warning in <paramref name="validatorResult"/> to the message panel
|
||||
/// and enqueues a summary snack notification (capped at 10 messages).
|
||||
/// Returns <c>true</c> when there were any messages so the caller can decide on early-return
|
||||
/// based on <see cref="NodeValidatorResult.Success"/>.
|
||||
/// </summary>
|
||||
public bool NotifyValidatorResult(NodeValidatorResult validatorResult)
|
||||
{
|
||||
var msgs = new List<string>([.. validatorResult.Errors, .. validatorResult.Warnings]);
|
||||
if (msgs.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
SendMessage(msg);
|
||||
}
|
||||
Enqueue(Utils.List2String(msgs.Take(10).ToList(), true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ public class ServerTestItem
|
|||
public bool AllowTest { get; set; }
|
||||
public bool NeedAutoFillRemarks { get; set; }
|
||||
public int QueueNum { get; set; }
|
||||
public required ProfileItem Profile { get; set; }
|
||||
public ECoreType CoreType { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,12 +220,6 @@ public class DnsServer4Ray
|
|||
public List<string>? domains { get; set; }
|
||||
public bool? skipFallback { get; set; }
|
||||
public List<string>? expectedIPs { get; set; }
|
||||
public List<string>? unexpectedIPs { get; set; }
|
||||
public string? clientIp { get; set; }
|
||||
public string? queryStrategy { get; set; }
|
||||
public int? timeoutMs { get; set; }
|
||||
public bool? disableCache { get; set; }
|
||||
public bool? finalQuery { get; set; }
|
||||
public string? tag { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
75
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
75
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -834,6 +834,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 All configurations 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAllServers {
|
||||
get {
|
||||
return ResourceManager.GetString("menuAllServers", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Backup and Restore 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -1006,74 +1015,20 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Generate Policy Group from Multiple Profiles 的本地化字符串。
|
||||
/// 查找类似 Generate Policy Group 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServer {
|
||||
public static string menuGenGroupServer {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServer", resourceCulture);
|
||||
return ResourceManager.GetString("menuGenGroupServer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Fallback by sing-box 的本地化字符串。
|
||||
/// 查找类似 Group by Region 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerSingBoxFallback {
|
||||
public static string menuGenRegionGroup {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerSingBoxFallback", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 LeastPing by sing-box 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerSingBoxLeastPing {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerSingBoxLeastPing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Fallback by Xray 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerXrayFallback {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerXrayFallback", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 LeastLoad by Xray 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerXrayLeastLoad {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerXrayLeastLoad", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 LeastPing by Xray 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerXrayLeastPing {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerXrayLeastPing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Random by Xray 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerXrayRandom {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerXrayRandom", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 RoundRobin by Xray 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuGenGroupMultipleServerXrayRoundRobin {
|
||||
get {
|
||||
return ResourceManager.GetString("menuGenGroupMultipleServerXrayRoundRobin", resourceCulture);
|
||||
return ResourceManager.GetString("menuGenRegionGroup", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1371,24 +1371,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>مخفی و پورت می شود، با کاما (،) جدا می شود</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>Generate Policy Group from Multiple Profiles</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>چند سرور تصادفی توسط Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>چند سرور RoundRobin توسط Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>چند سرور LeastPing توسط Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>چند سرور LeastLoad توسط Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>LeastPing چند سرور توسط sing-box</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>صادر کردن سرور</value>
|
||||
</data>
|
||||
|
|
@ -1533,12 +1515,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>Fallback</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>Core '{0}' does not support network type '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>Generate Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>All configurations</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>Group by Region</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1368,24 +1368,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Écrase le port ; pour plusieurs groupes, séparer par virgules (,)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>Générer un groupe de stratégie depuis plusieurs profils</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>Xray aléatoire (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>Xray équilibrage (tourniquet) multi-sélection</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>Xray latence minimale (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>Xray le plus stable (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>sing-box latence minimale (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>Exporter</value>
|
||||
</data>
|
||||
|
|
@ -1530,12 +1512,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>Basculement (failover)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>sing-box basculement (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>Xray basculement (multi-sélection)</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>Le cœur « {0} » ne prend pas en charge le type de réseau « {1} »</value>
|
||||
</data>
|
||||
|
|
@ -1683,4 +1659,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>Generate Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>All configurations</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>Group by Region</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
|||
|
|
@ -1371,24 +1371,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>A portot lefedi, vesszővel (,) elválasztva</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>Generate Policy Group from Multiple Profiles</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>Több konfiguráció véletlenszerűen Xray szerint</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>Több konfiguráció RoundRobin Xray szerint</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>Több konfiguráció legkisebb pinggel Xray szerint</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>Több konfiguráció legkisebb terheléssel Xray szerint</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>Több konfiguráció legkisebb pinggel sing-box szerint</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>Konfiguráció exportálása</value>
|
||||
</data>
|
||||
|
|
@ -1533,12 +1515,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>Fallback</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>Core '{0}' does not support network type '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>Generate Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>All configurations</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>Group by Region</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1371,24 +1371,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Will cover the port, separate with commas (,)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>Generate Policy Group from Multiple Profiles</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>Random by Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>RoundRobin by Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>LeastPing by Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>LeastLoad by Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>LeastPing by sing-box</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>Export</value>
|
||||
</data>
|
||||
|
|
@ -1533,12 +1515,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>Fallback</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>Fallback by sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>Fallback by Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>Core '{0}' does not support network type '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>Generate Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>All configurations</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>Group by Region</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1371,24 +1371,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Заменит указанный порт, перечисляйте через запятую (,)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>Generate Policy Group from Multiple Profiles</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>Случайный (Xray)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>Круговой (Xray)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>Минимальное RTT (минимальное время туда-обратно) (Xray)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>Минимальная нагрузка (Xray)</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>Минимальное RTT (минимальное время туда-обратно) (sing-box)</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>Экспортировать конфигурацию</value>
|
||||
</data>
|
||||
|
|
@ -1533,12 +1515,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>Fallback</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>Multi-Configuration Fallback by Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>Core '{0}' does not support network type '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1686,4 +1662,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>Generate Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>All configurations</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>Group by Region</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1368,24 +1368,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>会覆盖端口,多组时用逗号 (,) 隔开</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>多选生成策略组</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>多选随机 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>多选负载均衡 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>多选最低延迟 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>多选最稳定 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>多选最低延迟 sing-box</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>导出</value>
|
||||
</data>
|
||||
|
|
@ -1530,12 +1512,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>故障转移</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>多选故障转移 sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>多选故障转移 Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>核心 '{0}' 不支持网络类型 '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1683,4 +1659,13 @@
|
|||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>订阅后置节点 {0} 未找到,已跳过。</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>一键生成策略组</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>全部配置项</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>按地区分组</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -127,7 +127,7 @@
|
|||
<value>設定格式不正確</value>
|
||||
</data>
|
||||
<data name="CustomServerTips" xml:space="preserve">
|
||||
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改偵聽埠。</value>
|
||||
<value>注意,自訂設定完全依賴您自行輸入的內容,部分功能可能無法使用。如需啟用系統代理,請手動調整監聽埠。</value>
|
||||
</data>
|
||||
<data name="Downloading" xml:space="preserve">
|
||||
<value>下載開始...</value>
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
<value>生成預設設定檔失敗</value>
|
||||
</data>
|
||||
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
|
||||
<value>獲取預設設定失敗</value>
|
||||
<value>取得預設設定失敗</value>
|
||||
</data>
|
||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||
<value>匯入自訂設定失敗</value>
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<value>讀取設定失敗</value>
|
||||
</data>
|
||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||
<value>請填寫正確格式的埠</value>
|
||||
<value>請填寫有效的埠號</value>
|
||||
</data>
|
||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||
<value>請填寫本機偵聽埠</value>
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
<value>非 VMess 或 SS 協定</value>
|
||||
</data>
|
||||
<data name="NotFoundCore" xml:space="preserve">
|
||||
<value>在資料夾 ({0}) 下未找到 Core 檔案 (檔案名: {1}),請下載後放入資料夾,下載網址: {2}</value>
|
||||
<value>在資料夾 ({0}) 中找不到 Core 檔案(檔名:{1})。請下載後放入該資料夾。下載網址:{2}</value>
|
||||
</data>
|
||||
<data name="NoValidQRcodeFound" xml:space="preserve">
|
||||
<value>掃描完成,未發現有效二維碼</value>
|
||||
|
|
@ -304,7 +304,7 @@
|
|||
<value>是否確定移除規則?</value>
|
||||
</data>
|
||||
<data name="RoutingRuleDetailRequiredTips" xml:space="preserve">
|
||||
<value>{0},必填其中一項.</value>
|
||||
<value>{0},至少需填寫其中一項。</value>
|
||||
</data>
|
||||
<data name="LvRemarks" xml:space="preserve">
|
||||
<value>別名</value>
|
||||
|
|
@ -385,7 +385,7 @@
|
|||
<value>所有</value>
|
||||
</data>
|
||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||
<value>請瀏覽匯入設定</value>
|
||||
<value>請選擇要匯入的設定檔</value>
|
||||
</data>
|
||||
<data name="Speedtesting" xml:space="preserve">
|
||||
<value>測試中...</value>
|
||||
|
|
@ -472,7 +472,7 @@
|
|||
<value>語言 (需重啟)</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaClipboard" xml:space="preserve">
|
||||
<value>從剪貼簿導入分享連結</value>
|
||||
<value>從剪貼簿匯入分享連結</value>
|
||||
</data>
|
||||
<data name="menuAddServerViaScan" xml:space="preserve">
|
||||
<value>掃描螢幕上的二維碼</value>
|
||||
|
|
@ -616,10 +616,10 @@
|
|||
<value>SNI</value>
|
||||
</data>
|
||||
<data name="TbStreamSecurity" xml:space="preserve">
|
||||
<value>傳輸層安全 (TLS)</value>
|
||||
<value>傳輸層安全性 (TLS)</value>
|
||||
</data>
|
||||
<data name="TipNetwork" xml:space="preserve">
|
||||
<value>*預設 TCP,選錯會無法連接</value>
|
||||
<value>*預設 TCP,選錯會無法連線</value>
|
||||
</data>
|
||||
<data name="TbCoreType" xml:space="preserve">
|
||||
<value>Core 類型</value>
|
||||
|
|
@ -652,7 +652,7 @@
|
|||
<value>SOCKS 埠</value>
|
||||
</data>
|
||||
<data name="TipPreSocksPort" xml:space="preserve">
|
||||
<value>*自訂設定的 Socks 埠值,可不設定;當設定此值後,將使用 Xray/sing-box (Tun) 額外啟動一個前置 Socks 服務,提供分流和速度顯示等功能</value>
|
||||
<value>*自訂設定的 Socks 埠值,可留空;當設定此值後,將使用 Xray/sing-box (Tun) 額外啟動一個前置 Socks 服務,提供分流和速度顯示等功能</value>
|
||||
</data>
|
||||
<data name="TbBrowse" xml:space="preserve">
|
||||
<value>瀏覽</value>
|
||||
|
|
@ -1309,7 +1309,7 @@
|
|||
<value>安裝字體到系統中,選擇或填入字體名稱,重新啟動後生效</value>
|
||||
</data>
|
||||
<data name="menuExitTips" xml:space="preserve">
|
||||
<value>是否確定退出?</value>
|
||||
<value>確定要退出嗎?</value>
|
||||
</data>
|
||||
<data name="LvMemo" xml:space="preserve">
|
||||
<value>備註備忘</value>
|
||||
|
|
@ -1368,24 +1368,6 @@
|
|||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>會覆蓋埠,多組時用逗號 (,) 隔開</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServer" xml:space="preserve">
|
||||
<value>多選生成策略組</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRandom" xml:space="preserve">
|
||||
<value>多選隨機 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||
<value>多選負載平衡 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastPing" xml:space="preserve">
|
||||
<value>多選最低延遲 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||
<value>多選最穩定 Xray</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||
<value>多選最低延遲 sing-box</value>
|
||||
</data>
|
||||
<data name="menuExportConfig" xml:space="preserve">
|
||||
<value>匯出</value>
|
||||
</data>
|
||||
|
|
@ -1513,13 +1495,13 @@
|
|||
<value>策略組類型</value>
|
||||
</data>
|
||||
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||
<value>添加策略組</value>
|
||||
<value>新增策略組</value>
|
||||
</data>
|
||||
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||
<value>添加鏈式代理</value>
|
||||
<value>新增鏈式代理</value>
|
||||
</data>
|
||||
<data name="menuAddChildServer" xml:space="preserve">
|
||||
<value>添加子配置</value>
|
||||
<value>新增子配置</value>
|
||||
</data>
|
||||
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||
<value>刪除子配置</value>
|
||||
|
|
@ -1530,12 +1512,6 @@
|
|||
<data name="TbFallback" xml:space="preserve">
|
||||
<value>容錯移轉</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerSingBoxFallback" xml:space="preserve">
|
||||
<value>多選容錯移轉 sing-box</value>
|
||||
</data>
|
||||
<data name="menuGenGroupMultipleServerXrayFallback" xml:space="preserve">
|
||||
<value>多選容錯移轉 Xray</value>
|
||||
</data>
|
||||
<data name="MsgCoreNotSupportNetwork" xml:space="preserve">
|
||||
<value>核心 '{0}' 不支援網路類型 '{1}'</value>
|
||||
</data>
|
||||
|
|
@ -1615,72 +1591,81 @@
|
|||
<value>EchForceQuery</value>
|
||||
</data>
|
||||
<data name="TbFullCertTips" xml:space="preserve">
|
||||
<value>Full certificate (chain), PEM format</value>
|
||||
<value>完整憑證(鏈),PEM 格式</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Certificate fingerprint (SHA-256)</value>
|
||||
<value>憑證指紋(SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbServeStale" xml:space="preserve">
|
||||
<value>Serve Stale</value>
|
||||
<value>提供過期快取(Serve Stale)</value>
|
||||
</data>
|
||||
<data name="TbParallelQuery" xml:space="preserve">
|
||||
<value>Parallel Query</value>
|
||||
<value>并行查詢</value>
|
||||
</data>
|
||||
<data name="TbDomesticDNSTips" xml:space="preserve">
|
||||
<value>By default, invoked only during routing for resolution</value>
|
||||
<value>預設僅在路由期間進行解析時調用</value>
|
||||
</data>
|
||||
<data name="TbRemoteDNSTips" xml:space="preserve">
|
||||
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
|
||||
<value>預設僅在路由期間進行解析時調用;請確保遠端伺服器能連線至此 DNS</value>
|
||||
</data>
|
||||
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
|
||||
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
|
||||
<value>若未設定或為 "AsIs",使用系統 DNS 解析;否則將使用內建 DNS 模組。</value>
|
||||
</data>
|
||||
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
|
||||
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
|
||||
<value>若未設定或為 "AsIs",由遠端伺服器的 DNS 解析;否則將使用內建 DNS 模組。</value>
|
||||
</data>
|
||||
<data name="TbHopInt7" xml:space="preserve">
|
||||
<value>Port hopping interval</value>
|
||||
<value>連接埠跳轉間隔</value>
|
||||
</data>
|
||||
<data name="menuServerListPreview" xml:space="preserve">
|
||||
<value>Configuration item preview</value>
|
||||
<value>子配置項預覽</value>
|
||||
</data>
|
||||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="MsgRoutingRuleOutboundNodeWarning" xml:space="preserve">
|
||||
<value>Routing rule {0} outbound node {1} warning: {2}</value>
|
||||
<value>路由規則 {0} 的出站節點 {1} 發出警告:{2}</value>
|
||||
</data>
|
||||
<data name="MsgRoutingRuleOutboundNodeError" xml:space="preserve">
|
||||
<value>Routing rule {0} outbound node {1} error: {2}. Fallback to proxy node only.</value>
|
||||
<value>路由規則 {0} 的出站節點 {1} 發生錯誤:{2}。已回退為僅使用代理節點。</value>
|
||||
</data>
|
||||
<data name="MsgGroupCycleDependency" xml:space="preserve">
|
||||
<value>Group {0} has a cycle dependency on child node {1}. Skipping this node.</value>
|
||||
<value>節點組 {0} 與子節點 {1} 存在循環依賴。已跳過此節點。</value>
|
||||
</data>
|
||||
<data name="MsgGroupChildNodeWarning" xml:space="preserve">
|
||||
<value>Group {0} child node {1} warning: {2}</value>
|
||||
<value>節點組 {0} 的子節點 {1} 發出警告:{2}</value>
|
||||
</data>
|
||||
<data name="MsgGroupChildNodeError" xml:space="preserve">
|
||||
<value>Group {0} child node {1} error: {2}. Skipping this node.</value>
|
||||
<value>節點組 {0} 的子節點 {1} 發生錯誤:{2}。已跳過此節點。</value>
|
||||
</data>
|
||||
<data name="MsgGroupChildGroupNodeWarning" xml:space="preserve">
|
||||
<value>Group {0} child group node {1} warning: {2}</value>
|
||||
<value>節點組 {0} 的子節點組 {1} 發出警告:{2}</value>
|
||||
</data>
|
||||
<data name="MsgGroupChildGroupNodeError" xml:space="preserve">
|
||||
<value>Group {0} child group node {1} error: {2}. Skipping this node.</value>
|
||||
<value>節點組 {0} 的子節點組 {1} 發生錯誤:{2}。已跳過此節點。</value>
|
||||
</data>
|
||||
<data name="MsgGroupNoValidChildNode" xml:space="preserve">
|
||||
<value>Group {0} has no valid child node.</value>
|
||||
<value>節點組 {0} 沒有可用的有效子節點。</value>
|
||||
</data>
|
||||
<data name="MsgRoutingRuleEmptyOutboundTag" xml:space="preserve">
|
||||
<value>Routing rule {0} has an empty outbound tag. Fallback to proxy node only.</value>
|
||||
<value>路由規則 {0} 的出站標籤為空。已回退為僅使用代理節點。</value>
|
||||
</data>
|
||||
<data name="MsgRoutingRuleOutboundNodeNotFound" xml:space="preserve">
|
||||
<value>Routing rule {0} outbound node {1} not found. Fallback to proxy node only.</value>
|
||||
<value>找不到路由規則 {0} 的出站節點 {1}。已回退為僅使用代理節點。</value>
|
||||
</data>
|
||||
<data name="MsgSubscriptionPrevProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription previous proxy {0} not found. Skipping.</value>
|
||||
<value>找不到訂閱的前一個代理 {0}。已跳過。</value>
|
||||
</data>
|
||||
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
|
||||
<value>Subscription next proxy {0} not found. Skipping.</value>
|
||||
<value>找不到訂閱的下一個代理 {0}。已跳過。</value>
|
||||
</data>
|
||||
<data name="menuGenGroupServer" xml:space="preserve">
|
||||
<value>生成策略組</value>
|
||||
</data>
|
||||
<data name="menuAllServers" xml:space="preserve">
|
||||
<value>所有配置項</value>
|
||||
</data>
|
||||
<data name="menuGenRegionGroup" xml:space="preserve">
|
||||
<value>按區域分組</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -149,11 +149,11 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
|
|||
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (!Global.SingboxSupportConfigType.Contains(it.ConfigType))
|
||||
if (!(Global.SingboxSupportConfigType.Contains(it.ConfigType) || it.ConfigType.IsGroupType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.Port <= 0)
|
||||
if (!it.ConfigType.IsComplexType() && it.Port <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,15 +148,20 @@ public partial class CoreConfigSingboxService
|
|||
_coreConfig.dns ??= new Dns4Sbox();
|
||||
_coreConfig.dns.rules ??= [];
|
||||
|
||||
_coreConfig.dns.rules.AddRange(new[]
|
||||
_coreConfig.dns.rules.Add(new() { ip_accept_any = true, server = Global.SingboxHostsDNSTag });
|
||||
|
||||
if (context.ProtectDomainList.Count > 0)
|
||||
{
|
||||
new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag },
|
||||
new Rule4Sbox
|
||||
_coreConfig.dns.rules.Add(new()
|
||||
{
|
||||
server = Global.SingboxDirectDNSTag,
|
||||
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
|
||||
domain = context.ProtectDomainList.ToList(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_coreConfig.dns.rules.AddRange(new[]
|
||||
{
|
||||
new Rule4Sbox
|
||||
{
|
||||
server = Global.SingboxRemoteDNSTag,
|
||||
|
|
@ -428,7 +433,11 @@ public partial class CoreConfigSingboxService
|
|||
localDnsServer.tag = tag;
|
||||
|
||||
dns4Sbox.servers.Add(localDnsServer);
|
||||
dns4Sbox.rules.Insert(0, BuildProtectDomainRule());
|
||||
var protectDomainRule = BuildProtectDomainRule();
|
||||
if (protectDomainRule != null)
|
||||
{
|
||||
dns4Sbox.rules.Insert(0, protectDomainRule);
|
||||
}
|
||||
|
||||
_coreConfig.dns = dns4Sbox;
|
||||
}
|
||||
|
|
@ -450,8 +459,12 @@ public partial class CoreConfigSingboxService
|
|||
_coreConfig.dns?.servers?.Add(localDnsServer);
|
||||
}
|
||||
|
||||
private Rule4Sbox BuildProtectDomainRule()
|
||||
private Rule4Sbox? BuildProtectDomainRule()
|
||||
{
|
||||
if (context.ProtectDomainList.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new()
|
||||
{
|
||||
server = Global.SingboxLocalDNSTag,
|
||||
|
|
|
|||
|
|
@ -112,11 +112,11 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (!Global.XraySupportConfigType.Contains(it.ConfigType))
|
||||
if (!(Global.XraySupportConfigType.Contains(it.ConfigType) || it.ConfigType.IsGroupType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.Port <= 0)
|
||||
if (!it.ConfigType.IsComplexType() && it.Port <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -180,13 +180,13 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
//rule
|
||||
RulesItem4Ray rule = new()
|
||||
{
|
||||
inboundTag = new List<string> { inbound.tag },
|
||||
inboundTag = [inbound.tag],
|
||||
outboundTag = tag,
|
||||
type = "field"
|
||||
};
|
||||
if (isBalancer)
|
||||
{
|
||||
rule.balancerTag = tag;
|
||||
rule.balancerTag = tag + Global.BalancerTagSuffix;
|
||||
rule.outboundTag = null;
|
||||
}
|
||||
_coreConfig.routing.rules.Add(rule);
|
||||
|
|
@ -301,6 +301,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
GenLog();
|
||||
_coreConfig.outbounds.Clear();
|
||||
GenOutbounds();
|
||||
GenStatistic();
|
||||
|
||||
var protectNode = new ProfileItem()
|
||||
{
|
||||
|
|
@ -326,18 +327,17 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
Node = protectNode,
|
||||
}).BuildProxyOutbound("tun-project-ss"));
|
||||
|
||||
_coreConfig.routing.rules ??= [];
|
||||
var hasBalancer = _coreConfig.routing.balancers is { Count: > 0 };
|
||||
_coreConfig.routing.rules =
|
||||
[
|
||||
new()
|
||||
{
|
||||
inboundTag = new List<string> { "proxy-relay-ss" },
|
||||
outboundTag = hasBalancer ? null : Global.ProxyTag,
|
||||
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix: null,
|
||||
type = "field"
|
||||
}
|
||||
];
|
||||
_coreConfig.inbounds.Clear();
|
||||
_coreConfig.routing.rules.Add(new()
|
||||
{
|
||||
inboundTag = ["proxy-relay-ss"],
|
||||
outboundTag = hasBalancer ? null : Global.ProxyTag,
|
||||
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix : null,
|
||||
type = "field"
|
||||
});
|
||||
|
||||
//_coreConfig.inbounds.Clear();
|
||||
|
||||
var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!;
|
||||
configNode["inbounds"]!.AsArray().Add(new
|
||||
|
|
|
|||
|
|
@ -71,6 +71,25 @@ public partial class CoreConfigV2rayService
|
|||
dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null;
|
||||
|
||||
// DNS routing
|
||||
var directDnsTags = dnsItem.servers
|
||||
.Select(server =>
|
||||
{
|
||||
var tagNode = (server as JsonObject)?["tag"];
|
||||
return tagNode is JsonValue value && value.TryGetValue<string>(out var tag) ? tag : null;
|
||||
})
|
||||
.Where(tag => tag is not null && tag.StartsWith(Global.DirectDnsTag, StringComparison.Ordinal))
|
||||
.Select(tag => tag!)
|
||||
.ToList();
|
||||
if (directDnsTags.Count > 0)
|
||||
{
|
||||
_coreConfig.routing.rules.Add(new()
|
||||
{
|
||||
type = "field",
|
||||
inboundTag = directDnsTags,
|
||||
outboundTag = Global.DirectTag,
|
||||
});
|
||||
}
|
||||
|
||||
var finalRule = BuildFinalRule();
|
||||
dnsItem.tag = Global.DnsTag;
|
||||
_coreConfig.routing.rules.Add(new()
|
||||
|
|
@ -78,7 +97,7 @@ public partial class CoreConfigV2rayService
|
|||
type = "field",
|
||||
inboundTag = [Global.DnsTag],
|
||||
outboundTag = finalRule.outboundTag,
|
||||
balancerTag = finalRule.balancerTag
|
||||
balancerTag = finalRule.balancerTag,
|
||||
});
|
||||
|
||||
_coreConfig.dns = dnsItem;
|
||||
|
|
@ -212,11 +231,13 @@ public partial class CoreConfigV2rayService
|
|||
|
||||
dnsItem.servers ??= [];
|
||||
|
||||
var directDnsTagIndex = 1;
|
||||
|
||||
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||
AddDnsServers(directDNSAddress, directDomainList);
|
||||
AddDnsServers(directDNSAddress, directDomainList, true);
|
||||
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||
AddDnsServers(directDNSAddress, directGeositeList);
|
||||
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
|
||||
AddDnsServers(directDNSAddress, directGeositeList, true);
|
||||
AddDnsServers(directDNSAddress, expectedDomainList, true, expectedIPs);
|
||||
if (dnsServerDomains.Count > 0)
|
||||
{
|
||||
AddDnsServers(bootstrapDNSAddress, dnsServerDomains);
|
||||
|
|
@ -234,8 +255,21 @@ public partial class CoreConfigV2rayService
|
|||
useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork;
|
||||
}
|
||||
|
||||
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
|
||||
dnsItem.servers.AddRange(defaultDnsServers);
|
||||
if (!useDirectDns)
|
||||
{
|
||||
dnsItem.servers.AddRange(remoteDNSAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var dns in directDNSAddress)
|
||||
{
|
||||
var dnsServer = CreateDnsServer(dns, []);
|
||||
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
||||
dnsServer.skipFallback = false;
|
||||
dnsItem.servers.Add(JsonUtils.SerializeToNode(dnsServer,
|
||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
|
||||
|
|
@ -249,7 +283,7 @@ public partial class CoreConfigV2rayService
|
|||
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
|
||||
}
|
||||
|
||||
static object? CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||
static DnsServer4Ray CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||
{
|
||||
var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress);
|
||||
var domainFinal = dnsAddress;
|
||||
|
|
@ -272,13 +306,10 @@ public partial class CoreConfigV2rayService
|
|||
domains = domains.Count > 0 ? domains : null,
|
||||
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
||||
};
|
||||
return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
});
|
||||
return dnsServer;
|
||||
}
|
||||
|
||||
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
|
||||
void AddDnsServers(List<string> dnsAddresses, List<string> domains, bool isDirectDns = false, List<string>? expectedIPs = null)
|
||||
{
|
||||
if (domains.Count <= 0)
|
||||
{
|
||||
|
|
@ -286,7 +317,14 @@ public partial class CoreConfigV2rayService
|
|||
}
|
||||
foreach (var dnsAddress in dnsAddresses)
|
||||
{
|
||||
dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
|
||||
var dnsServer = CreateDnsServer(dnsAddress, domains, expectedIPs);
|
||||
if (isDirectDns)
|
||||
{
|
||||
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
||||
}
|
||||
var dnsServerNode = JsonUtils.SerializeToNode(dnsServer,
|
||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
||||
dnsItem.servers.Add(dnsServerNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -399,7 +437,7 @@ public partial class CoreConfigV2rayService
|
|||
|
||||
FillDnsDomainsCustom(obj);
|
||||
|
||||
_coreConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(obj));
|
||||
_coreConfig.dns = obj;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,19 +67,27 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
|||
|
||||
private async Task<List<ServerTestItem>> GetClearItem(ESpeedActionType actionType, List<ProfileItem> selecteds)
|
||||
{
|
||||
var lstSelected = new List<ServerTestItem>();
|
||||
foreach (var it in selecteds)
|
||||
var lstSelected = new List<ServerTestItem>(selecteds.Count);
|
||||
var ids = selecteds.Where(it => !it.IndexId.IsNullOrEmpty()
|
||||
&& it.ConfigType != EConfigType.Custom
|
||||
&& (it.ConfigType.IsComplexType() || it.Port > 0))
|
||||
.Select(it => it.IndexId)
|
||||
.ToList();
|
||||
var profileMap = await AppManager.Instance.GetProfileItemsByIndexIdsAsMap(ids);
|
||||
for (var i = 0; i < selecteds.Count; i++)
|
||||
{
|
||||
if (it.ConfigType.IsComplexType())
|
||||
var it = selecteds[i];
|
||||
if (it.ConfigType == EConfigType.Custom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (it.Port <= 0)
|
||||
if (!it.ConfigType.IsComplexType() && it.Port <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = profileMap.GetValueOrDefault(it.IndexId, it);
|
||||
lstSelected.Add(new ServerTestItem()
|
||||
{
|
||||
IndexId = it.IndexId,
|
||||
|
|
@ -88,6 +96,9 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
|||
ConfigType = it.ConfigType,
|
||||
NeedAutoFillRemarks = it.Remarks.IsNullOrEmpty(),
|
||||
QueueNum = selecteds.IndexOf(it)
|
||||
QueueNum = i,
|
||||
Profile = profile,
|
||||
CoreType = AppManager.Instance.GetCoreType(profile, it.ConfigType),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -397,8 +408,8 @@ public class SpeedtestService(Config config, Func<SpeedTestResult, Task> updateF
|
|||
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
|
||||
{
|
||||
List<List<ServerTestItem>> lstTest = new();
|
||||
var lst1 = lstSelected.Where(t => Global.XraySupportConfigType.Contains(t.ConfigType)).ToList();
|
||||
var lst2 = lstSelected.Where(t => Global.SingboxOnlyConfigType.Contains(t.ConfigType)).ToList();
|
||||
var lst1 = lstSelected.Where(t => t.CoreType == ECoreType.Xray).ToList();
|
||||
var lst2 = lstSelected.Where(t => t.CoreType == ECoreType.sing_box).ToList();
|
||||
|
||||
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,15 +99,8 @@ public class AddGroupServerViewModel : MyReactiveObject
|
|||
Filter = protocolExtra?.Filter;
|
||||
|
||||
var childIndexIds = Utils.String2List(protocolExtra?.ChildItems) ?? [];
|
||||
foreach (var item in childIndexIds)
|
||||
{
|
||||
var child = await AppManager.Instance.GetProfileItem(item);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ChildItemsObs.Add(child);
|
||||
}
|
||||
var childItemList = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childIndexIds);
|
||||
ChildItemsObs.AddRange(childItemList);
|
||||
}
|
||||
|
||||
public async Task ChildRemoveAsync()
|
||||
|
|
|
|||
|
|
@ -546,24 +546,15 @@ public class MainWindowViewModel : MyReactiveObject
|
|||
NoticeManager.Instance.Enqueue(ResUI.CheckServerSettings);
|
||||
return;
|
||||
}
|
||||
var (context, validatorResult) = await CoreConfigContextBuilder.Build(_config, profileItem);
|
||||
var msgs = new List<string>([..validatorResult.Errors, ..validatorResult.Warnings]);
|
||||
if (msgs.Count > 0)
|
||||
var allResult = await CoreConfigContextBuilder.BuildAll(_config, profileItem);
|
||||
if (NoticeManager.Instance.NotifyValidatorResult(allResult.CombinedValidatorResult) && !allResult.Success)
|
||||
{
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
NoticeManager.Instance.SendMessage(msg);
|
||||
}
|
||||
NoticeManager.Instance.Enqueue(Utils.List2String(msgs.Take(10).ToList(), true));
|
||||
if (!validatorResult.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await LoadCore(context);
|
||||
await LoadCore(allResult.ResolvedMainContext, allResult.PreSocksResult?.Context);
|
||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||
await Task.Delay(1000);
|
||||
});
|
||||
|
|
@ -604,9 +595,9 @@ public class MainWindowViewModel : MyReactiveObject
|
|||
RxApp.MainThreadScheduler.Schedule(() => BlReloadEnabled = enabled);
|
||||
}
|
||||
|
||||
private async Task LoadCore(CoreConfigContext? context)
|
||||
private async Task LoadCore(CoreConfigContext? mainContext, CoreConfigContext? preContext)
|
||||
{
|
||||
await CoreManager.Instance.LoadCore(context);
|
||||
await CoreManager.Instance.LoadCore(mainContext, preContext);
|
||||
}
|
||||
|
||||
#endregion core job
|
||||
|
|
|
|||
|
|
@ -255,19 +255,7 @@ public class ProfilesSelectViewModel : MyReactiveObject
|
|||
{
|
||||
return null;
|
||||
}
|
||||
var lst = new List<ProfileItem>();
|
||||
foreach (var sp in SelectedProfiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sp?.IndexId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var item = await AppManager.Instance.GetProfileItem(sp.IndexId);
|
||||
if (item != null)
|
||||
{
|
||||
lst.Add(item);
|
||||
}
|
||||
}
|
||||
var lst = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(SelectedProfiles.Select(sp => sp?.IndexId));
|
||||
if (lst.Count == 0)
|
||||
{
|
||||
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
private string _serverFilter = string.Empty;
|
||||
private Dictionary<string, bool> _dicHeaderSort = new();
|
||||
private SpeedtestService? _speedtestService;
|
||||
private string? _pendingSelectIndexId;
|
||||
|
||||
#endregion private prop
|
||||
|
||||
|
|
@ -43,13 +44,8 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SetDefaultServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> ShareServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerXrayRandomCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerXrayRoundRobinCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerXrayLeastPingCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerXrayLeastLoadCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerXrayFallbackCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerSingBoxLeastPingCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupMultipleServerSingBoxFallbackCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupAllServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenGroupRegionServerCmd { get; }
|
||||
|
||||
//servers move
|
||||
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||
|
|
@ -134,33 +130,13 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
{
|
||||
await ShareServerAsync();
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerXrayRandomCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
GenGroupAllServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.Random);
|
||||
await GenGroupAllServer();
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerXrayRoundRobinCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
GenGroupRegionServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.RoundRobin);
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerXrayLeastPingCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.LeastPing);
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerXrayLeastLoadCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.LeastLoad);
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerXrayFallbackCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.Xray, EMultipleLoad.Fallback);
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerSingBoxLeastPingCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.sing_box, EMultipleLoad.LeastPing);
|
||||
}, canEditRemove);
|
||||
GenGroupMultipleServerSingBoxFallbackCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await GenGroupMultipleServer(ECoreType.sing_box, EMultipleLoad.Fallback);
|
||||
await GenGroupRegionServer();
|
||||
}, canEditRemove);
|
||||
|
||||
//servers move
|
||||
|
|
@ -392,15 +368,14 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
ProfileItems.AddRange(lstModel);
|
||||
if (lstModel.Count > 0)
|
||||
{
|
||||
var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId);
|
||||
if (selected != null)
|
||||
ProfileItemModel? selected = null;
|
||||
if (!_pendingSelectIndexId.IsNullOrEmpty())
|
||||
{
|
||||
SelectedProfile = selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedProfile = lstModel.First();
|
||||
selected = lstModel.FirstOrDefault(t => t.IndexId == _pendingSelectIndexId);
|
||||
_pendingSelectIndexId = null;
|
||||
}
|
||||
selected ??= lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId);
|
||||
SelectedProfile = selected ?? lstModel.First();
|
||||
}
|
||||
|
||||
await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null);
|
||||
|
|
@ -481,14 +456,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort);
|
||||
if (latest)
|
||||
{
|
||||
foreach (var profile in orderProfiles)
|
||||
{
|
||||
var item = await AppManager.Instance.GetProfileItem(profile.IndexId);
|
||||
if (item is not null)
|
||||
{
|
||||
lstSelected.Add(item);
|
||||
}
|
||||
}
|
||||
lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -641,29 +609,29 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
await _updateView?.Invoke(EViewAction.ShareServer, url);
|
||||
}
|
||||
|
||||
private async Task GenGroupMultipleServer(ECoreType coreType, EMultipleLoad multipleLoad)
|
||||
private async Task GenGroupAllServer()
|
||||
{
|
||||
var lstSelected = await GetProfileItems(true);
|
||||
if (lstSelected == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ret = await ConfigHandler.AddGroupServer4Multiple(_config, lstSelected, coreType, multipleLoad, SelectedSub?.Id);
|
||||
var ret = await ConfigHandler.AddGroupAllServer(_config, SelectedSub);
|
||||
if (ret.Success != true)
|
||||
{
|
||||
NoticeManager.Instance.Enqueue(ResUI.OperationFailed);
|
||||
return;
|
||||
}
|
||||
if (ret?.Data?.ToString() == _config.IndexId)
|
||||
_pendingSelectIndexId = ret.Data?.ToString();
|
||||
await RefreshServers();
|
||||
}
|
||||
|
||||
private async Task GenGroupRegionServer()
|
||||
{
|
||||
var ret = await ConfigHandler.AddGroupRegionServer(_config, SelectedSub);
|
||||
if (ret.Success != true)
|
||||
{
|
||||
await RefreshServers();
|
||||
Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
await SetDefaultServer(ret?.Data?.ToString());
|
||||
NoticeManager.Instance.Enqueue(ResUI.OperationFailed);
|
||||
return;
|
||||
}
|
||||
var indexIdList = ret.Data as List<string>;
|
||||
_pendingSelectIndexId = indexIdList?.FirstOrDefault();
|
||||
await RefreshServers();
|
||||
}
|
||||
|
||||
public async Task SortServer(string colName)
|
||||
|
|
@ -789,18 +757,9 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
}
|
||||
|
||||
var (context, validatorResult) = await CoreConfigContextBuilder.Build(_config, item);
|
||||
var msgs = new List<string>([..validatorResult.Errors, ..validatorResult.Warnings]);
|
||||
if (msgs.Count > 0)
|
||||
if (NoticeManager.Instance.NotifyValidatorResult(validatorResult) && !validatorResult.Success)
|
||||
{
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
NoticeManager.Instance.SendMessage(msg);
|
||||
}
|
||||
NoticeManager.Instance.Enqueue(Utils.List2String(msgs.Take(10).ToList(), true));
|
||||
if (!validatorResult.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (blClipboard)
|
||||
|
|
@ -829,18 +788,9 @@ public class ProfilesViewModel : MyReactiveObject
|
|||
return;
|
||||
}
|
||||
var (context, validatorResult) = await CoreConfigContextBuilder.Build(_config, item);
|
||||
var msgs = new List<string>([..validatorResult.Errors, ..validatorResult.Warnings]);
|
||||
if (msgs.Count > 0)
|
||||
if (NoticeManager.Instance.NotifyValidatorResult(validatorResult) && !validatorResult.Success)
|
||||
{
|
||||
foreach (var msg in msgs)
|
||||
{
|
||||
NoticeManager.Instance.SendMessage(msg);
|
||||
}
|
||||
NoticeManager.Instance.Enqueue(Utils.List2String(msgs.Take(10).ToList(), true));
|
||||
if (!validatorResult.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(context, fileName);
|
||||
if (result.Success != true)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuServerList}">
|
||||
<Grid
|
||||
Margin="{StaticResource Margin8}"
|
||||
ColumnDefinitions="300,Auto,Auto"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
RowDefinitions="Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
x:Name="cmbSubChildItems"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DisplayMemberBinding="{Binding Remarks}"
|
||||
ItemsSource="{Binding SubItems}" />
|
||||
|
|
@ -117,7 +117,8 @@
|
|||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" />
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
|
|
@ -125,12 +126,14 @@
|
|||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
<ComboBox
|
||||
x:Name="cmbFilter"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center" />
|
||||
VerticalAlignment="Center"
|
||||
IsEditable="True" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
|
|
@ -184,11 +187,11 @@
|
|||
Binding="{Binding ConfigType}"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<DataGridTextColumn
|
||||
|
|
@ -226,11 +229,11 @@
|
|||
Binding="{Binding ConfigType}"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<DataGridTextColumn
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||
ResUI.TbRoundRobin,
|
||||
ResUI.TbLeastLoad,
|
||||
};
|
||||
cmbFilter.ItemsSource = Global.PolicyGroupDefaultFilterList;
|
||||
|
||||
switch (profileItem.ConfigType)
|
||||
{
|
||||
|
|
@ -53,7 +54,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables);
|
||||
//this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbSubChildItems.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSubItem, v => v.cmbSubChildItems.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Filter, v => v.txtFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Filter, v => v.cmbFilter.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
|
|
@ -147,14 +148,7 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||
private async void MenuAddChild_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
if (ViewModel?.SelectedSource?.ConfigType == EConfigType.PolicyGroup)
|
||||
{
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
}
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
selectWindow.AllowMultiSelect(true);
|
||||
var result = await selectWindow.ShowDialog<bool?>(this);
|
||||
if (result == true)
|
||||
|
|
|
|||
|
|
@ -90,17 +90,17 @@
|
|||
Header="{x:Static resx:ResUI.LvServiceType}"
|
||||
Tag="ConfigType" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}"
|
||||
Tag="Remarks" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}"
|
||||
Tag="Address" />
|
||||
<DataGridTextColumn
|
||||
Width="60"
|
||||
Width="100"
|
||||
Binding="{Binding Port}"
|
||||
Header="{x:Static resx:ResUI.LvPort}"
|
||||
Tag="Port" />
|
||||
|
|
|
|||
|
|
@ -193,14 +193,9 @@
|
|||
<MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupMultipleServer}">
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayRandom" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRandom}" />
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayRoundRobin" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRoundRobin}" />
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayLeastPing" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastPing}" />
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerXrayLeastLoad" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastLoad}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerSingBoxLeastPing" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxLeastPing}" />
|
||||
<MenuItem x:Name="menuGenGroupMultipleServerSingBoxFallback" Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxFallback}" />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupServer}">
|
||||
<MenuItem x:Name="menuGenGroupAllServer" Header="{x:Static resx:ResUI.menuAllServers}" />
|
||||
<MenuItem x:Name="menuGenGroupRegionServer" Header="{x:Static resx:ResUI.menuGenRegionGroup}" />
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
|
|
|
|||
|
|
@ -60,12 +60,8 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRandomCmd, v => v.menuGenGroupMultipleServerXrayRandom).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRoundRobinCmd, v => v.menuGenGroupMultipleServerXrayRoundRobin).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastPingCmd, v => v.menuGenGroupMultipleServerXrayLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastLoadCmd, v => v.menuGenGroupMultipleServerXrayLeastLoad).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxLeastPingCmd, v => v.menuGenGroupMultipleServerSingBoxLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxFallbackCmd, v => v.menuGenGroupMultipleServerSingBoxFallback).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupAllServerCmd, v => v.menuGenGroupAllServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupRegionServerCmd, v => v.menuGenGroupRegionServer).DisposeWith(disposables);
|
||||
|
||||
//servers move
|
||||
//this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
|||
private async void BtnSelectPrevProfile_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
var result = await selectWindow.ShowDialog<bool?>(this);
|
||||
if (result == true)
|
||||
{
|
||||
|
|
@ -74,7 +74,7 @@ public partial class SubEditWindow : WindowBase<SubEditViewModel>
|
|||
private async void BtnSelectNextProfile_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
var result = await selectWindow.ShowDialog<bool?>(this);
|
||||
if (result == true)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
|
@ -163,7 +163,7 @@
|
|||
x:Name="cmbSubChildItems"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DisplayMemberPath="Remarks"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
|
@ -173,7 +173,8 @@
|
|||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}" />
|
||||
Text="{x:Static resx:ResUI.TbPolicyGroupSubChildTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
|
|
@ -182,14 +183,15 @@
|
|||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
<ComboBox
|
||||
x:Name="cmbFilter"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
IsEditable="True"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
|
|
@ -251,11 +253,11 @@
|
|||
Binding="{Binding ConfigType}"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<DataGridTextColumn
|
||||
|
|
@ -292,11 +294,11 @@
|
|||
Binding="{Binding ConfigType}"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<DataGridTextColumn
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public partial class AddGroupServerWindow
|
|||
ResUI.TbRoundRobin,
|
||||
ResUI.TbLeastLoad,
|
||||
};
|
||||
cmbFilter.ItemsSource = Global.PolicyGroupDefaultFilterList;
|
||||
|
||||
switch (profileItem.ConfigType)
|
||||
{
|
||||
|
|
@ -48,7 +49,7 @@ public partial class AddGroupServerWindow
|
|||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbSubChildItems.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSubItem, v => v.cmbSubChildItems.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Filter, v => v.txtFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Filter, v => v.cmbFilter.Text).DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, vm => vm.ChildItemsObs, v => v.lstChild.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables);
|
||||
|
|
@ -127,14 +128,7 @@ public partial class AddGroupServerWindow
|
|||
private async void MenuAddChild_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
if (ViewModel?.SelectedSource?.ConfigType == EConfigType.PolicyGroup)
|
||||
{
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
}
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
selectWindow.AllowMultiSelect(true);
|
||||
if (selectWindow.ShowDialog() == true)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ public partial class DNSSettingWindow
|
|||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||
|
||||
|
|
|
|||
|
|
@ -119,17 +119,17 @@
|
|||
ExName="ConfigType"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<base:MyDGTextColumn
|
||||
Width="150"
|
||||
Width="200"
|
||||
Binding="{Binding Remarks}"
|
||||
ExName="Remarks"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<base:MyDGTextColumn
|
||||
Width="120"
|
||||
Width="200"
|
||||
Binding="{Binding Address}"
|
||||
ExName="Address"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<base:MyDGTextColumn
|
||||
Width="60"
|
||||
Width="100"
|
||||
Binding="{Binding Port}"
|
||||
ExName="Port"
|
||||
Header="{x:Static resx:ResUI.LvPort}" />
|
||||
|
|
|
|||
|
|
@ -240,32 +240,15 @@
|
|||
Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupMultipleServer}">
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupServer}">
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerXrayRandom"
|
||||
x:Name="menuGenGroupAllServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRandom}" />
|
||||
Header="{x:Static resx:ResUI.menuAllServers}" />
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerXrayRoundRobin"
|
||||
x:Name="menuGenGroupRegionServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRoundRobin}" />
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerXrayLeastPing"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastPing}" />
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerXrayLeastLoad"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastLoad}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerSingBoxLeastPing"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxLeastPing}" />
|
||||
<MenuItem
|
||||
x:Name="menuGenGroupMultipleServerSingBoxFallback"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxFallback}" />
|
||||
Header="{x:Static resx:ResUI.menuGenRegionGroup}" />
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
|
|
|
|||
|
|
@ -54,12 +54,8 @@ public partial class ProfilesView
|
|||
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRandomCmd, v => v.menuGenGroupMultipleServerXrayRandom).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayRoundRobinCmd, v => v.menuGenGroupMultipleServerXrayRoundRobin).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastPingCmd, v => v.menuGenGroupMultipleServerXrayLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerXrayLeastLoadCmd, v => v.menuGenGroupMultipleServerXrayLeastLoad).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxLeastPingCmd, v => v.menuGenGroupMultipleServerSingBoxLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupMultipleServerSingBoxFallbackCmd, v => v.menuGenGroupMultipleServerSingBoxFallback).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupAllServerCmd, v => v.menuGenGroupAllServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GenGroupRegionServerCmd, v => v.menuGenGroupRegionServer).DisposeWith(disposables);
|
||||
|
||||
//servers move
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public partial class SubEditWindow
|
|||
private async void BtnSelectPrevProfile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
if (selectWindow.ShowDialog() == true)
|
||||
{
|
||||
var profile = await selectWindow.ProfileItem;
|
||||
|
|
@ -67,7 +67,7 @@ public partial class SubEditWindow
|
|||
private async void BtnSelectNextProfile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectWindow = new ProfilesSelectWindow();
|
||||
selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true);
|
||||
selectWindow.SetConfigTypeFilter([EConfigType.Custom], exclude: true);
|
||||
if (selectWindow.ShowDialog() == true)
|
||||
{
|
||||
var profile = await selectWindow.ProfileItem;
|
||||
|
|
|
|||
Loading…
Reference in a new issue