mirror of https://github.com/2dust/v2rayN
Add functionality multi-server set as active
Implemented using sing-box Selector, which can be switched using the clash apipull/5377/head
parent
7c33c1c322
commit
c79e2e3ad4
|
@ -30,6 +30,7 @@ namespace v2rayN
|
|||
public const string CoreConfigFileName = "config.json";
|
||||
public const string CorePreConfigFileName = "configPre.json";
|
||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
||||
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||
public const string V2raySampleClient = "v2rayN.Sample.SampleClientConfig";
|
||||
public const string SingboxSampleClient = "v2rayN.Sample.SingboxSampleClientConfig";
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.IO;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using v2rayN.Enums;
|
||||
using v2rayN.Handler.CoreConfig;
|
||||
using v2rayN.Handler.Fmt;
|
||||
using v2rayN.Models;
|
||||
|
||||
|
@ -1065,6 +1066,33 @@ namespace v2rayN.Handler
|
|||
return 0;
|
||||
}
|
||||
|
||||
public static int AddCustomServer4Multiple(Config config, List<ProfileItem> selecteds, out string indexId)
|
||||
{
|
||||
indexId = Utils.GetMD5(Global.CoreMultipleLoadConfigFileName);
|
||||
string configPath = Utils.GetConfigPath(Global.CoreMultipleLoadConfigFileName);
|
||||
if (CoreConfigHandler.GenerateClientMultipleLoadConfig(config, configPath, selecteds, out string msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var fileName = configPath;
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var profileItem = LazyConfig.Instance.GetProfileItem(config.indexId) ?? new();
|
||||
profileItem.indexId = indexId;
|
||||
profileItem.remarks = "Multi-server Config";
|
||||
profileItem.address = Global.CoreMultipleLoadConfigFileName;
|
||||
profileItem.configType = EConfigType.Custom;
|
||||
profileItem.coreType = ECoreType.sing_box;
|
||||
|
||||
AddServerCommon(config, profileItem, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endregion Server
|
||||
|
||||
#region Batch add servers
|
||||
|
|
|
@ -144,5 +144,16 @@ namespace v2rayN.Handler.CoreConfig
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, out string msg)
|
||||
{
|
||||
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
JsonUtils.ToFile(singboxConfig, fileName, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -804,7 +804,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||
return true;
|
||||
}
|
||||
|
||||
private int GenDns(ProfileItem node, SingboxConfig singboxConfig)
|
||||
private int GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -853,6 +853,7 @@ namespace v2rayN.Handler.CoreConfig
|
|||
var lstDomain = singboxConfig.outbounds
|
||||
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
|
||||
.Select(t => t.server)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
if (lstDomain != null && lstDomain.Count > 0)
|
||||
{
|
||||
|
@ -1169,5 +1170,123 @@ namespace v2rayN.Handler.CoreConfig
|
|||
}
|
||||
|
||||
#endregion Gen speedtest config
|
||||
|
||||
#region Gen Multiple Load config
|
||||
|
||||
public int GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds, out SingboxConfig? singboxConfig, out string msg)
|
||||
{
|
||||
singboxConfig = null;
|
||||
try
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
msg = ResUI.CheckServerSettings;
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = ResUI.InitialConfiguration;
|
||||
|
||||
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
|
||||
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
|
||||
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
|
||||
{
|
||||
msg = ResUI.FailedGetDefaultConfiguration;
|
||||
return -1;
|
||||
}
|
||||
|
||||
singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
|
||||
if (singboxConfig == null)
|
||||
{
|
||||
msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return -1;
|
||||
}
|
||||
|
||||
GenLog(singboxConfig);
|
||||
GenInbounds(singboxConfig);
|
||||
GenRouting(singboxConfig);
|
||||
GenExperimental(singboxConfig);
|
||||
singboxConfig.outbounds.RemoveAt(0);
|
||||
|
||||
var tagProxy = new List<string>();
|
||||
foreach (var it in selecteds)
|
||||
{
|
||||
if (it.configType == EConfigType.Custom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.port <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
||||
if (item is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (it.configType is EConfigType.VMess or EConfigType.VLESS)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(item.id) || !Utils.IsGuidByParse(item.id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (item.configType == EConfigType.Shadowsocks
|
||||
&& !Global.SsSecuritiesInSingbox.Contains(item.security))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.configType == EConfigType.VLESS && !Global.Flows.Contains(item.flow))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//outbound
|
||||
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||
GenOutbound(item, outbound);
|
||||
outbound.tag = $"{Global.ProxyTag}-{tagProxy.Count + 1}";
|
||||
singboxConfig.outbounds.Add(outbound);
|
||||
tagProxy.Add(outbound.tag);
|
||||
}
|
||||
if (tagProxy.Count <= 0)
|
||||
{
|
||||
msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return -1;
|
||||
}
|
||||
|
||||
GenDns(null, singboxConfig);
|
||||
ConvertGeo2Ruleset(singboxConfig);
|
||||
|
||||
//add urltest outbound
|
||||
var outUrltest = new Outbound4Sbox
|
||||
{
|
||||
type = "urltest",
|
||||
tag = $"{Global.ProxyTag}-auto",
|
||||
outbounds = tagProxy,
|
||||
interrupt_exist_connections = false,
|
||||
};
|
||||
singboxConfig.outbounds.Add(outUrltest);
|
||||
|
||||
//add selector outbound
|
||||
var outSelector = new Outbound4Sbox
|
||||
{
|
||||
type = "selector",
|
||||
tag = Global.ProxyTag,
|
||||
outbounds = JsonUtils.DeepCopy(tagProxy),
|
||||
interrupt_exist_connections = false,
|
||||
};
|
||||
outSelector.outbounds.Insert(0, outUrltest.tag);
|
||||
singboxConfig.outbounds.Add(outSelector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Gen Multiple config
|
||||
}
|
||||
}
|
|
@ -27,9 +27,8 @@ namespace v2rayN.Handler
|
|||
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
}
|
||||
|
||||
public void LoadCore()
|
||||
{
|
||||
var node = ConfigHandler.GetDefaultServer(_config);
|
||||
public void LoadCore(ProfileItem? node) {
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
ShowMsg(false, ResUI.CheckServerSettings);
|
||||
|
|
|
@ -130,6 +130,8 @@
|
|||
public Multiplex4Sbox? multiplex { get; set; }
|
||||
public Transport4Sbox? transport { get; set; }
|
||||
public HyObfs4Sbox? obfs { get; set; }
|
||||
public List<string>? outbounds { get; set; }
|
||||
public bool? interrupt_exist_connections { get; set; }
|
||||
}
|
||||
|
||||
public class Tls4Sbox
|
||||
|
|
|
@ -1078,7 +1078,7 @@ namespace v2rayN.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Refresh Proxies (F5) 的本地化字符串。
|
||||
/// 查找类似 Refresh Proxies 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuProxiesReload {
|
||||
get {
|
||||
|
@ -1302,6 +1302,15 @@ namespace v2rayN.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Multi-server set to active 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuSetDefaultMultipleServer {
|
||||
get {
|
||||
return ResourceManager.GetString("menuSetDefaultMultipleServer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Set as active server (Enter) 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
@ -1066,9 +1066,6 @@
|
|||
<data name="menuProxiesDelaytestPart" xml:space="preserve">
|
||||
<value>Part Node Latency Test</value>
|
||||
</data>
|
||||
<data name="menuProxiesReload" xml:space="preserve">
|
||||
<value>Refresh Proxies (F5)</value>
|
||||
</data>
|
||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||
<value>Select active node (Enter)</value>
|
||||
</data>
|
||||
|
|
|
@ -1292,7 +1292,7 @@
|
|||
<value>Part Node Latency Test</value>
|
||||
</data>
|
||||
<data name="menuProxiesReload" xml:space="preserve">
|
||||
<value>Refresh Proxies (F5)</value>
|
||||
<value>Refresh Proxies</value>
|
||||
</data>
|
||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||
<value>Select active node (Enter)</value>
|
||||
|
@ -1300,4 +1300,7 @@
|
|||
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||
<value>Default domain strategy for outbound</value>
|
||||
</data>
|
||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||
<value>Multi-server set to active</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1289,7 +1289,7 @@
|
|||
<value>当前部分节点延迟测试</value>
|
||||
</data>
|
||||
<data name="menuProxiesReload" xml:space="preserve">
|
||||
<value>刷新 (F5)</value>
|
||||
<value>刷新</value>
|
||||
</data>
|
||||
<data name="menuProxiesSelectActivity" xml:space="preserve">
|
||||
<value>设为活动节点 (Enter)</value>
|
||||
|
@ -1297,4 +1297,7 @@
|
|||
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
|
||||
<value>Outbound默认解析策略</value>
|
||||
</data>
|
||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||
<value>多服务器设为活动(多选)</value>
|
||||
</data>
|
||||
</root>
|
|
@ -106,6 +106,7 @@ namespace v2rayN.ViewModels
|
|||
public ReactiveCommand<Unit, Unit> CopyServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SetDefaultServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> ShareServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SetDefaultMultipleServerCmd { get; }
|
||||
|
||||
//servers move
|
||||
public ReactiveCommand<Unit, Unit> MoveTopCmd { get; }
|
||||
|
@ -398,6 +399,10 @@ namespace v2rayN.ViewModels
|
|||
{
|
||||
ShareServer();
|
||||
}, canEditRemove);
|
||||
SetDefaultMultipleServerCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
SetDefaultMultipleServer();
|
||||
}, canEditRemove);
|
||||
//servers move
|
||||
MoveTopCmd = ReactiveCommand.Create(() =>
|
||||
{
|
||||
|
@ -1166,6 +1171,28 @@ namespace v2rayN.ViewModels
|
|||
await DialogHost.Show(dialog, "RootDialog");
|
||||
}
|
||||
|
||||
private void SetDefaultMultipleServer()
|
||||
{
|
||||
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConfigHandler.AddCustomServer4Multiple(_config, lstSelecteds, out string indexId) != 0)
|
||||
{
|
||||
_noticeHandler?.Enqueue(ResUI.OperationFailed);
|
||||
return;
|
||||
}
|
||||
if (indexId == _config.indexId)
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDefaultServer(indexId);
|
||||
}
|
||||
}
|
||||
|
||||
public void SortServer(string colName)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(colName))
|
||||
|
@ -1519,7 +1546,7 @@ namespace v2rayN.ViewModels
|
|||
Application.Current?.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
BlReloadEnabled = true;
|
||||
ShowCalshUI = (_config.runningCoreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo);
|
||||
ShowCalshUI = (_config.runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo);
|
||||
if (ShowCalshUI)
|
||||
{
|
||||
Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload();
|
||||
|
@ -1532,7 +1559,8 @@ namespace v2rayN.ViewModels
|
|||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_coreHandler.LoadCore();
|
||||
var node = ConfigHandler.GetDefaultServer(_config);
|
||||
_coreHandler.LoadCore(node);
|
||||
|
||||
//ConfigHandler.SaveConfig(_config, false);
|
||||
|
||||
|
|
|
@ -581,6 +581,10 @@
|
|||
x:Name="menuShareServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||
<MenuItem
|
||||
x:Name="menuSetDefaultMultipleServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuSetDefaultMultipleServer}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuMixedTestServer"
|
||||
|
|
|
@ -104,7 +104,8 @@ namespace v2rayN.Views
|
|||
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.SetDefaultMultipleServerCmd, v => v.menuSetDefaultMultipleServer).DisposeWith(disposables);
|
||||
|
||||
//servers move
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
|
||||
|
|
Loading…
Reference in New Issue