diff --git a/v2rayN/v2rayN/Handler/LazyConfig.cs b/v2rayN/v2rayN/Handler/LazyConfig.cs index 52b0a1af..88f02d38 100644 --- a/v2rayN/v2rayN/Handler/LazyConfig.cs +++ b/v2rayN/v2rayN/Handler/LazyConfig.cs @@ -1,4 +1,4 @@ -using v2rayN.Base; +using System.Runtime.Intrinsics.X86; using v2rayN.Mode; namespace v2rayN.Handler @@ -176,6 +176,15 @@ namespace v2rayN.Handler return SqliteHelper.Instance.Table().FirstOrDefault(it => it.indexId == indexId); } + public ProfileItem? GetProfileItemRemarks(string Remarks) + { + if (Utils.IsNullOrEmpty(Remarks)) + { + return null; + } + return SqliteHelper.Instance.Table().FirstOrDefault(it => it.remarks == Remarks); + } + public ProfileItem? GetProfileItemViaRemarks(string remarks) { if (Utils.IsNullOrEmpty(remarks)) diff --git a/v2rayN/v2rayN/Handler/ServerAutoSwitch.cs b/v2rayN/v2rayN/Handler/ServerAutoSwitch.cs index 06faf233..5f526b84 100644 --- a/v2rayN/v2rayN/Handler/ServerAutoSwitch.cs +++ b/v2rayN/v2rayN/Handler/ServerAutoSwitch.cs @@ -1,16 +1,21 @@ using DynamicData; +using Splat; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; +using System.Windows; using System.Windows.Interop; using v2rayN.Mode; +using v2rayN.Resx; +using v2rayN.ViewModels; namespace v2rayN.Handler { public delegate void SetDefaultServerDelegate(string s); + public delegate void SetTestResultDelegate(string i, string d, string s); public class TestResultItem { public string indexId { get; set; } @@ -24,6 +29,8 @@ namespace v2rayN.Handler private NoticeHandler? _noticeHandler; private Task taskmain = null; private SetDefaultServerDelegate setDefaultServerDelegates; + private SetTestResultDelegate setTestResultDelegates; + private SetAutoSwitchTogDelegate _setAutoSwitchTog; public ServerAutoSwitch() { @@ -36,12 +43,20 @@ namespace v2rayN.Handler { bStop = true; if(taskmain!=null) - taskmain.Wait(); + taskmain.Wait(); taskmain = null; } public void SetDelegate(SetDefaultServerDelegate s = null) { this.setDefaultServerDelegates = s; } + public void SetDelegate(SetTestResultDelegate s = null) + { + this.setTestResultDelegates = s; + } + public void SetDelegate(SetAutoSwitchTogDelegate s = null) + { + this._setAutoSwitchTog = s; + } private void UpdateHandler(bool notify, string msg) { } @@ -62,6 +77,7 @@ namespace v2rayN.Handler indexId = id, latency = i }); + setTestResultDelegates(id, dl, speed); } } @@ -77,56 +93,114 @@ namespace v2rayN.Handler taskmain = Task.Run(() => { - int iFailTimeMax = 30; - int iTestInterval = iFailTimeMax / 3; + _noticeHandler = Locator.Current.GetService(); DownloadHandle downloadHandle = new(); long failtimestart = 0; + int LastServerSelectMode = -1; List listprofile = new List(); while (!bStop) { + var _config = LazyConfig.Instance.GetConfig(); + int iFailTimeMax = LazyConfig.Instance.GetConfig().autoSwitchItem.FailTimeMax; + int iTestInterval = iFailTimeMax / 3; + int ServerSelectMode = LazyConfig.Instance.GetConfig().autoSwitchItem.ServerSelectMode; + int AutoSwitchMode = LazyConfig.Instance.GetConfig().autoSwitchItem.mode; + Thread.Sleep(iTestInterval * 1000); int res = downloadHandle.RunAvailabilityCheck(null).Result; + if (!bStop) + Task.Run(() => setTestResultDelegates(_config.indexId, res.ToString(), "")); + else + break; if (res <= 0) { - _noticeHandler?.SendMessage("Current server test failed!", true); + _noticeHandler?.SendMessage("Current server test failed!",true); if (failtimestart == 0) failtimestart = GetTimestamp(DateTime.Now); if (GetTimestamp(DateTime.Now) - failtimestart >= iFailTimeMax) { - if (testResultItems.Count == 0 || listprofile.Count == 0) - listprofile = LazyConfig.Instance.ProfileItemsAutoSwitch(); - if (listprofile.Count > 0) + if (testResultItems.Count == 0 || listprofile.Count == 0 || ServerSelectMode!= LastServerSelectMode) { - var _config = LazyConfig.Instance.GetConfig(); + testResultItems.Clear(); + listprofile = LazyConfig.Instance.ProfileItemsAutoSwitch(); + } + + if (listprofile.Count >= 2) + { + if (testResultItems.Count == 0) { var _coreHandler = new CoreHandler(_config, (bool x, string y) => { }); - new SpeedtestHandler(_config, _coreHandler, listprofile, Mode.ESpeedActionType.Tcping, UpdateSpeedtestHandler); - while (testResultItems.Count < listprofile.Count) + + if (ServerSelectMode == 0 || ServerSelectMode == 1) + new SpeedtestHandler(_config, _coreHandler, listprofile, Mode.ESpeedActionType.Tcping, UpdateSpeedtestHandler); + else if (ServerSelectMode == 2) + new SpeedtestHandler(_config, _coreHandler, listprofile, Mode.ESpeedActionType.Realping, UpdateSpeedtestHandler); + if (bStop) break; + while (!bStop && testResultItems.Count < listprofile.Count) { Thread.Sleep(20); } - } + if (bStop) break; + if (ServerSelectMode == 0) + { + List templist = new List(); - for(int i=testResultItems.Count-1; i>=0; i--) { - if (testResultItems[i].latency <= 0 || testResultItems[i].indexId == _config.indexId) - testResultItems.RemoveAt(i); + foreach (var item in listprofile) + { + var item2 = testResultItems.Find(x => x.indexId == item.indexId); + if (item2 != null) + templist.Add(item2); + } + testResultItems = templist; + } } - - if (testResultItems.Count > 0) + if (ServerSelectMode == 0) { - testResultItems.Sort((x, y) => x.latency.CompareTo(y.latency)); - setDefaultServerDelegates(testResultItems[0].indexId); - //if (ConfigHandler.SetDefaultServerIndex(ref _config, testResultItems[0].indexId) == 0) - //{ - // RefreshServers(); - // Reload(); - //} - - testResultItems.RemoveAt(0); + for (int i = testResultItems.Count - 1; i >= 0; i--) + { + if (testResultItems[i].latency <= 0 && testResultItems[i].indexId != _config.indexId) + testResultItems.RemoveAt(i); + } + if (testResultItems.Count > 1) + { + int j = testResultItems.FindIndex(x => x.indexId == _config.indexId); + int k = j + 1; + if (k > testResultItems.Count - 1) + k = 0; + setDefaultServerDelegates(testResultItems[k].indexId); + testResultItems.RemoveAt(j); + if (testResultItems.Count <= 1) + testResultItems.Clear(); + } + else + testResultItems.Clear(); } + else if (ServerSelectMode == 1 || ServerSelectMode == 2) + { + for (int i = testResultItems.Count - 1; i >= 0; i--) + { + if (testResultItems[i].latency <= 0 || testResultItems[i].indexId == _config.indexId) + testResultItems.RemoveAt(i); + } + + if (testResultItems.Count > 0) + { + testResultItems.Sort((x, y) => x.latency.CompareTo(y.latency)); + setDefaultServerDelegates(testResultItems[0].indexId); + testResultItems.RemoveAt(0); + } + } + } + else + { + _setAutoSwitchTog(false); + _config.autoSwitchItem.EnableAutoSwitch = false; + MessageBox.Show(ResUI.stopSwtichWarn); + } + } } else @@ -135,7 +209,7 @@ namespace v2rayN.Handler testResultItems.Clear(); listprofile.Clear(); } - + LastServerSelectMode = ServerSelectMode; } }); } diff --git a/v2rayN/v2rayN/Handler/UpdateHandle.cs b/v2rayN/v2rayN/Handler/UpdateHandle.cs index 6236c58f..6f41b45c 100644 --- a/v2rayN/v2rayN/Handler/UpdateHandle.cs +++ b/v2rayN/v2rayN/Handler/UpdateHandle.cs @@ -167,6 +167,7 @@ namespace v2rayN.Handler Task.Run(async () => { + var listprofile = LazyConfig.Instance.ProfileItemsAutoSwitch(); foreach (var item in subItem) { string id = item.id.TrimEx(); @@ -275,6 +276,16 @@ namespace v2rayN.Handler Logging.SaveLog("FailedImportSubscription"); Logging.SaveLog(result); } + else + { + foreach (var item3 in listprofile) + { + var item2 = LazyConfig.Instance.GetProfileItemRemarks(item3.remarks); + item2.autoSwitch = true; + SqliteHelper.Instance.Update(item2); + } + ConfigHandler.SaveConfig(_config); + } _updateFunc(false, ret > 0 ? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}" @@ -284,6 +295,8 @@ namespace v2rayN.Handler } _updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); + + }); } diff --git a/v2rayN/v2rayN/Resx/ResUI.Designer.cs b/v2rayN/v2rayN/Resx/ResUI.Designer.cs index 34e4dce0..8f25248c 100644 --- a/v2rayN/v2rayN/Resx/ResUI.Designer.cs +++ b/v2rayN/v2rayN/Resx/ResUI.Designer.cs @@ -1815,6 +1815,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Because the number of selected switching servers is less than the minimum value of 2, stop automatic switching! 的本地化字符串。 + /// + public static string stopSwtichWarn { + get { + return ResourceManager.GetString("stopSwtichWarn", resourceCulture); + } + } + /// /// 查找类似 Group please leave blank here 的本地化字符串。 /// @@ -2770,6 +2779,24 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Lowest RealPing Latency Server 的本地化字符串。 + /// + public static string TbSettingsLowestRealPingServer { + get { + return ResourceManager.GetString("TbSettingsLowestRealPingServer", resourceCulture); + } + } + + /// + /// 查找类似 Lowest TCPing Latency Server 的本地化字符串。 + /// + public static string TbSettingsLowestTCPingServer { + get { + return ResourceManager.GetString("TbSettingsLowestTCPingServer", resourceCulture); + } + } + /// /// 查找类似 sing-box Mux Protocol 的本地化字符串。 /// @@ -2806,6 +2833,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Next Server 的本地化字符串。 + /// + public static string TbSettingsNextServer { + get { + return ResourceManager.GetString("TbSettingsNextServer", resourceCulture); + } + } + /// /// 查找类似 Auth pass 的本地化字符串。 /// @@ -2833,6 +2869,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 Switch when server cannot connect 的本地化字符串。 + /// + public static string TbSettingsServerFail { + get { + return ResourceManager.GetString("TbSettingsServerFail", resourceCulture); + } + } + /// /// 查找类似 Switch to server 的本地化字符串。 /// @@ -3292,6 +3337,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 The number of selected switching servers must be greater than or equal to 2 to start switching! 的本地化字符串。 + /// + public static string turnOnSwitchWarn { + get { + return ResourceManager.GetString("turnOnSwitchWarn", resourceCulture); + } + } + /// /// 查找类似 Ungrouped 的本地化字符串。 /// diff --git a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx index afb7cac6..d10d4560 100644 --- a/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/v2rayN/Resx/ResUI.fa-Ir.resx @@ -1162,4 +1162,22 @@ از هاست های سیستم استفاده کنید + + سرور بعدی + + + سرور با کمترین تاخیر TCPing + + + کمترین سرور RealPing Latency + + + هنگامی که سرور نمی تواند متصل شود، تغییر دهید + + + از آنجایی که تعداد سرورهای سوئیچینگ انتخابی کمتر از مقدار حداقل 2 است، تعویض خودکار را متوقف کنید! + + + برای شروع سوئیچینگ، تعداد سرورهای سوئیچینگ انتخابی باید بیشتر یا مساوی 2 باشد! + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index bce95c49..6be9c4ed 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -205,7 +205,7 @@ Type - AutoSwitch + AutoSwitch Subs group @@ -1198,4 +1198,22 @@ Address(Ip,Ipv6) + + Next Server + + + Lowest TCPing Latency Server + + + Lowest RealPing Latency Server + + + Switch when server cannot connect + + + Because the number of selected switching servers is less than the minimum value of 2, stop automatic switching! + + + The number of selected switching servers must be greater than or equal to 2 to start switching! + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.ru.resx b/v2rayN/v2rayN/Resx/ResUI.ru.resx index 448b6a48..7f57cd53 100644 --- a/v2rayN/v2rayN/Resx/ResUI.ru.resx +++ b/v2rayN/v2rayN/Resx/ResUI.ru.resx @@ -1162,4 +1162,22 @@ Используйте системные хосты + + Следующий сервер + + + Сервер с наименьшей задержкой TCPing + + + Сервер с самой низкой задержкой RealPing + + + Переключиться, когда сервер не может подключиться + + + Поскольку количество выбранных коммутационных серверов меньше минимального значения 2, остановите автоматическое переключение! + + + Для начала переключения количество выбранных коммутационных серверов должно быть больше или равно 2! + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index 9b034116..54af3b51 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -1195,4 +1195,22 @@ Address(Ip,Ipv6) + + 下一个服务器 + + + 最低TCPing延迟服务器 + + + 最低真连接延迟服务器 + + + 服务器无法连接时切换 + + + 因为选择的切换服务器数量小于最低值2,停止自动切换! + + + 选择的切换服务器数量必须大于等于2才能启动切换! + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx index 7dd4ba10..38be51bd 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hant.resx @@ -1136,7 +1136,7 @@ IP 或 IP CIDR - 自動切換 + 切換 自動切換設定 @@ -1180,4 +1180,22 @@ 啟用IPv6 + + 下一个服务器 + + + TCPing 延遲最低的伺服器 + + + 最低 RealPing 延遲伺服器 + + + 伺服器無法連接時切換 + + + 由於選擇的切換伺服器數量小於最小值2,因此停止自動切換! + + + 選定的切換伺服器數量必須大於或等於2才能開始切換! + \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index 9a998a5d..99a4de24 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -13,6 +13,7 @@ using System.Reactive; using System.Reactive.Linq; using System.Text; using System.Windows; +using System.Windows.Controls; using System.Windows.Media; using v2rayN.Handler; using v2rayN.Mode; @@ -22,6 +23,7 @@ using v2rayN.Views; namespace v2rayN.ViewModels { public delegate void SetAutoSwitchTogDelegate(bool b); + public delegate void SetAutoSwitchAllDelegate(bool b); public class MainWindowViewModel : ReactiveObject { #region private prop @@ -37,10 +39,15 @@ namespace v2rayN.ViewModels private Dictionary _dicHeaderSort = new(); private Action _updateView; private SetAutoSwitchTogDelegate _setAutoSwitchTog; + private SetAutoSwitchAllDelegate _setAutoSwitchAll; public void SetDelegate(SetAutoSwitchTogDelegate s = null) { this._setAutoSwitchTog = s; } + public void SetDelegate2(SetAutoSwitchAllDelegate s = null) + { + this._setAutoSwitchAll = s; + } #endregion private prop #region ObservableCollection @@ -254,9 +261,12 @@ namespace v2rayN.ViewModels [Reactive] public string CurrentLanguage { get; set; } + [Reactive] + public bool autoSwitchCheckAll { get; set; } + #endregion UI - + public ServerAutoSwitch ServerAutoSwitchs= new ServerAutoSwitch(); @@ -605,7 +615,9 @@ namespace v2rayN.ViewModels Reload(); ChangeSystemProxyStatus(_config.sysProxyType, true); ServerAutoSwitchs.SetDelegate(SetDefaultServer); - if(_config.autoSwitchItem.EnableAutoSwitch) + ServerAutoSwitchs.SetDelegate(UpdateSpeedtestHandler); + ServerAutoSwitchs.SetDelegate(_setAutoSwitchTog); + if (_config.autoSwitchItem.EnableAutoSwitch) ServerAutoSwitchs.Start(); } @@ -614,7 +626,7 @@ namespace v2rayN.ViewModels Application.Current.Dispatcher.Invoke((Action)(() => { ShowHideWindow(true); - })); + })); } #endregion Init @@ -757,9 +769,9 @@ namespace v2rayN.ViewModels { Logging.SaveLog("MyAppExit Begin"); - StorageUI(); + StorageUI(); ConfigHandler.SaveConfig(_config); - + ServerAutoSwitchs.Stop(); //HttpProxyHandle.CloseHttpAgent(config); if (blWindowsShutDown) { @@ -891,6 +903,16 @@ namespace v2rayN.ViewModels RunningServerDisplay = ResUI.CheckServerSettings; RunningServerToolTipText = ResUI.CheckServerSettings; } + + int autoswitchservercount = 0; + foreach (var item in lstModel) + { + if(item.autoSwitch) + autoswitchservercount++; + } + + if(_setAutoSwitchAll!=null) + _setAutoSwitchAll( lstModel.Count>0 && autoswitchservercount == lstModel.Count); })); } @@ -1668,11 +1690,11 @@ namespace v2rayN.ViewModels var profiles = LazyConfig.Instance.ProfileItemsAutoSwitch(); if (profiles.Count < 2) { - MessageBox.Show("ѡлڵ2л!"); + MessageBox.Show(ResUI.turnOnSwitchWarn); _setAutoSwitchTog(false); _config.autoSwitchItem.EnableAutoSwitch = false; EnableAutoSwitch = false; - ConfigHandler.SaveConfig(ref _config); + ConfigHandler.SaveConfig(_config); return; } ServerAutoSwitchs.Start(); @@ -1684,7 +1706,7 @@ namespace v2rayN.ViewModels ServerAutoSwitchs.Stop(); }); } - ConfigHandler.SaveConfig(ref _config); + ConfigHandler.SaveConfig(_config); } } @@ -1899,18 +1921,18 @@ namespace v2rayN.ViewModels private void AutoHideStartup() { - if (_config.uiItem.autoHideStartup) - { + Observable.Range(1, 1) .Delay(TimeSpan.FromSeconds(0.5)) .Subscribe(x => { Application.Current.Dispatcher.Invoke(() => { - ShowHideWindow(false); + ShowHideWindow(!_config.uiItem.autoHideStartup); + RefreshServers(); }); }); - } + } #endregion UI diff --git a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs index da871a2f..3ad9a3ff 100644 --- a/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/OptionSettingViewModel.cs @@ -99,6 +99,10 @@ namespace v2rayN.ViewModels #endregion CoreType + [Reactive] public int ServerSelectMode { get; set; } + [Reactive] public int AutoSwitchMode { get; set; } + [Reactive] public int FailTimeMax { get; set; } + public ReactiveCommand SaveCmd { get; } public OptionSettingViewModel(Window view) @@ -181,6 +185,10 @@ namespace v2rayN.ViewModels #endregion Tun mode + FailTimeMax = _config.autoSwitchItem.FailTimeMax; + AutoSwitchMode = _config.autoSwitchItem.mode; + ServerSelectMode = _config.autoSwitchItem.ServerSelectMode; + InitCoreType(); SaveCmd = ReactiveCommand.Create(() => @@ -326,6 +334,10 @@ namespace v2rayN.ViewModels _config.tunModeItem.enableExInbound = TunEnableExInbound; _config.tunModeItem.enableIPv6Address = TunEnableIPv6Address; + _config.autoSwitchItem.mode = AutoSwitchMode; + _config.autoSwitchItem.ServerSelectMode=ServerSelectMode; + _config.autoSwitchItem.FailTimeMax = FailTimeMax; + //coreType SaveCoreType(); diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 8a801dc2..44e80095 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -674,10 +674,16 @@ + + + + +