namespace ServiceLib.ViewModels; public partial class OptionSettingViewModel : MyReactiveObject, ICloseable { public event EventHandler? RequestClose; #region Core [Reactive] public partial int LocalPort { get; set; } [Reactive] public partial bool SecondLocalPortEnabled { get; set; } [Reactive] public partial bool UdpEnabled { get; set; } [Reactive] public partial bool SniffingEnabled { get; set; } public IList DestOverride { get; set; } [Reactive] public partial bool RouteOnly { get; set; } [Reactive] public partial bool AllowLANConn { get; set; } [Reactive] public partial bool NewPort4LAN { get; set; } [Reactive] public partial string User { get; set; } [Reactive] public partial string Pass { get; set; } [Reactive] public partial bool LogEnabled { get; set; } [Reactive] public partial string Loglevel { get; set; } [Reactive] public partial string DefFingerprint { get; set; } [Reactive] public partial string DefUserAgent { get; set; } [Reactive] public partial string SendThrough { get; set; } [Reactive] public partial string BindInterface { get; set; } [Reactive] public partial int? Mux4RayConcurrency { get; set; } [Reactive] public partial int? Mux4RayXudpConcurrency { get; set; } [Reactive] public partial string Mux4RayXudpProxyUDP443 { get; set; } [Reactive] public partial string Mux4SboxProtocol { get; set; } [Reactive] public partial bool EnableCacheFile4Sbox { get; set; } [Reactive] public partial int? HyUpMbps { get; set; } [Reactive] public partial int? HyDownMbps { get; set; } [Reactive] public partial bool EnableFragment { get; set; } [Reactive] public partial bool EnableFinalFragment { get; set; } [Reactive] public partial string FragmentPackets { get; set; } [Reactive] public partial string FragmentLengths { get; set; } [Reactive] public partial string FragmentDelays { get; set; } [Reactive] public partial string FragmentMaxSplit { get; set; } #endregion Core #region UI [Reactive] public partial bool AutoRun { get; set; } [Reactive] public partial bool EnableStatistics { get; set; } [Reactive] public partial bool KeepOlderDedupl { get; set; } [Reactive] public partial bool DisplayRealTimeSpeed { get; set; } [Reactive] public partial bool EnableAutoAdjustMainLvColWidth { get; set; } [Reactive] public partial bool AutoHideStartup { get; set; } [Reactive] public partial bool Hide2TrayWhenClose { get; set; } [Reactive] public partial bool MacOSShowInDock { get; set; } [Reactive] public partial bool EnableDragDropSort { get; set; } [Reactive] public partial bool DoubleClick2Activate { get; set; } [Reactive] public partial int AutoUpdateInterval { get; set; } [Reactive] public partial int TrayMenuServersLimit { get; set; } [Reactive] public partial string CurrentFontFamily { get; set; } [Reactive] public partial int SpeedTestTimeout { get; set; } [Reactive] public partial string SpeedTestUrl { get; set; } [Reactive] public partial string SpeedPingTestUrl { get; set; } [Reactive] public partial string UdpTestTarget { get; set; } [Reactive] public partial int MixedConcurrencyCount { get; set; } [Reactive] public partial bool EnableHWA { get; set; } [Reactive] public partial string SubConvertUrl { get; set; } [Reactive] public partial int MainGirdOrientation { get; set; } [Reactive] public partial string GeoFileSourceUrl { get; set; } [Reactive] public partial string SrsFileSourceUrl { get; set; } [Reactive] public partial string RoutingRulesSourceUrl { get; set; } [Reactive] public partial string IPAPIUrl { get; set; } [Reactive] public partial string RootCertProvider { get; set; } #endregion UI #region UI visibility [Reactive] public partial bool BlIsWindows { get; set; } [Reactive] public partial bool BlIsLinux { get; set; } [Reactive] public partial bool BlIsIsMacOS { get; set; } [Reactive] public partial bool BlIsNonWindows { get; set; } #endregion UI visibility #region System proxy [Reactive] public partial bool NotProxyLocalAddress { get; set; } [Reactive] public partial string SystemProxyAdvancedProtocol { get; set; } [Reactive] public partial string SystemProxyExceptions { get; set; } [Reactive] public partial string CustomSystemProxyPacPath { get; set; } [Reactive] public partial string CustomSystemProxyScriptPath { get; set; } #endregion System proxy #region Tun mode [Reactive] public partial bool TunAutoRoute { get; set; } [Reactive] public partial bool TunStrictRoute { get; set; } [Reactive] public partial string TunStack { get; set; } [Reactive] public partial int TunMtu { get; set; } [Reactive] public partial bool TunEnableIPv6Address { get; set; } [Reactive] public partial string TunIcmpRouting { get; set; } [Reactive] public partial bool TunEnableLegacyProtect { get; set; } [Reactive] public partial string TunRouteExcludeAddress { get; set; } [Reactive] public partial string TunIPv4Address { get; set; } [Reactive] public partial string TunIPv6Address { get; set; } #endregion Tun mode #region CoreType [Reactive] public partial string CoreType1 { get; set; } [Reactive] public partial string CoreType2 { get; set; } [Reactive] public partial string CoreType3 { get; set; } [Reactive] public partial string CoreType4 { get; set; } [Reactive] public partial string CoreType5 { get; set; } [Reactive] public partial string CoreType6 { get; set; } [Reactive] public partial string CoreType7 { get; set; } [Reactive] public partial string CoreType9 { get; set; } #endregion CoreType public ReactiveCommand SaveCmd { get; } public OptionSettingViewModel() { _config = AppManager.Instance.Config; BlIsWindows = Utils.IsWindows(); BlIsLinux = Utils.IsLinux(); BlIsIsMacOS = Utils.IsMacOS(); BlIsNonWindows = Utils.IsNonWindows(); SaveCmd = ReactiveCommand.CreateFromTask(async () => { await SaveSettingAsync(); }); _ = Init(); } private async Task Init() { #region Core var inbound = _config.Inbound.First(); LocalPort = inbound.LocalPort; SecondLocalPortEnabled = inbound.SecondLocalPortEnabled; UdpEnabled = inbound.UdpEnabled; SniffingEnabled = inbound.SniffingEnabled; DestOverride = inbound.DestOverride ?? []; RouteOnly = inbound.RouteOnly; AllowLANConn = inbound.AllowLANConn; NewPort4LAN = inbound.NewPort4LAN; User = inbound.User; Pass = inbound.Pass; LogEnabled = _config.CoreBasicItem.LogEnabled; Loglevel = _config.CoreBasicItem.Loglevel; DefFingerprint = _config.CoreBasicItem.DefFingerprint; DefUserAgent = _config.CoreBasicItem.DefUserAgent; SendThrough = _config.CoreBasicItem.SendThrough ?? string.Empty; BindInterface = _config.CoreBasicItem.BindInterface ?? string.Empty; Mux4RayConcurrency = _config.Mux4RayItem.Concurrency; Mux4RayXudpConcurrency = _config.Mux4RayItem.XudpConcurrency; Mux4RayXudpProxyUDP443 = _config.Mux4RayItem.XudpProxyUDP443 ?? string.Empty; Mux4SboxProtocol = _config.Mux4SboxItem.Protocol; EnableCacheFile4Sbox = _config.CoreBasicItem.EnableCacheFile4Sbox; HyUpMbps = _config.HysteriaItem.UpMbps; HyDownMbps = _config.HysteriaItem.DownMbps; EnableFragment = _config.CoreBasicItem.EnableFragment; EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment; FragmentPackets = _config.Fragment4RayItem?.Packets; FragmentLengths = Utils.List2String(_config.Fragment4RayItem?.Lengths); FragmentDelays = Utils.List2String(_config.Fragment4RayItem?.Delays); FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit; #endregion Core #region UI AutoRun = _config.GuiItem.AutoRun; EnableStatistics = _config.GuiItem.EnableStatistics; DisplayRealTimeSpeed = _config.GuiItem.DisplayRealTimeSpeed; KeepOlderDedupl = _config.GuiItem.KeepOlderDedupl; EnableAutoAdjustMainLvColWidth = _config.UiItem.EnableAutoAdjustMainLvColWidth; AutoHideStartup = _config.UiItem.AutoHideStartup; Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose; MacOSShowInDock = _config.UiItem.MacOSShowInDock; EnableDragDropSort = _config.UiItem.EnableDragDropSort; DoubleClick2Activate = _config.UiItem.DoubleClick2Activate; AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval; TrayMenuServersLimit = _config.GuiItem.TrayMenuServersLimit; CurrentFontFamily = _config.UiItem.CurrentFontFamily; SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout; SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl; MixedConcurrencyCount = _config.SpeedTestItem.MixedConcurrencyCount; SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl; UdpTestTarget = _config.SpeedTestItem.UdpTestTarget; EnableHWA = _config.GuiItem.EnableHWA; SubConvertUrl = _config.ConstItem.SubConvertUrl; MainGirdOrientation = (int)_config.UiItem.MainGirdOrientation; GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl; SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl; RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl; IPAPIUrl = _config.SpeedTestItem.IPAPIUrl; RootCertProvider = _config.GuiItem.RootCertProvider; #endregion UI #region System proxy NotProxyLocalAddress = _config.SystemProxyItem.NotProxyLocalAddress; SystemProxyAdvancedProtocol = _config.SystemProxyItem.SystemProxyAdvancedProtocol; SystemProxyExceptions = _config.SystemProxyItem.SystemProxyExceptions; CustomSystemProxyPacPath = _config.SystemProxyItem.CustomSystemProxyPacPath; CustomSystemProxyScriptPath = _config.SystemProxyItem.CustomSystemProxyScriptPath; #endregion System proxy #region Tun mode TunAutoRoute = _config.TunModeItem.AutoRoute; TunStrictRoute = _config.TunModeItem.StrictRoute; TunStack = _config.TunModeItem.Stack; TunMtu = _config.TunModeItem.Mtu; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunIcmpRouting = _config.TunModeItem.IcmpRouting; TunEnableLegacyProtect = _config.TunModeItem.EnableLegacyProtect; TunRouteExcludeAddress = Utils.List2String(_config.TunModeItem.RouteExcludeAddress, true); TunIPv4Address = _config.TunModeItem.IPv4Address; TunIPv6Address = _config.TunModeItem.IPv6Address; #endregion Tun mode await InitCoreType(); } private async Task InitCoreType() { _config.CoreTypeItem ??= []; foreach (var it in Enum.GetValues()) { if (_config.CoreTypeItem.FindIndex(t => t.ConfigType == it) >= 0) { continue; } _config.CoreTypeItem.Add(new CoreTypeItem() { ConfigType = it, CoreType = ECoreType.Xray }); } _config.CoreTypeItem.ForEach(it => { var type = it.CoreType.ToString(); switch ((int)it.ConfigType) { case 1: CoreType1 = type; break; case 2: CoreType2 = type; break; case 3: CoreType3 = type; break; case 4: CoreType4 = type; break; case 5: CoreType5 = type; break; case 6: CoreType6 = type; break; case 7: CoreType7 = type; break; case 9: CoreType9 = type; break; } }); await Task.CompletedTask; } private async Task SaveSettingAsync() { if (LocalPort.ToString().IsNullOrEmpty() || !Utils.IsNumeric(LocalPort.ToString()) || LocalPort <= 0 || LocalPort >= Global.MaxPort) { NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort); return; } var fragmentLengths = Utils.String2List(FragmentLengths) ?? []; var fragmentDelays = Utils.String2List(FragmentDelays) ?? []; if (fragmentLengths.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _)) || fragmentDelays.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _)) || (FragmentMaxSplit.IsNotEmpty() && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _))) { NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError); return; } var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics || DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed || EnableDragDropSort != _config.UiItem.EnableDragDropSort || EnableHWA != _config.GuiItem.EnableHWA || CurrentFontFamily != _config.UiItem.CurrentFontFamily; //Core var inbound = _config.Inbound.First(); inbound.LocalPort = LocalPort; inbound.SecondLocalPortEnabled = SecondLocalPortEnabled; inbound.UdpEnabled = UdpEnabled; inbound.SniffingEnabled = SniffingEnabled; inbound.DestOverride = DestOverride?.ToList(); inbound.RouteOnly = RouteOnly; inbound.AllowLANConn = AllowLANConn; inbound.NewPort4LAN = NewPort4LAN; inbound.User = User; inbound.Pass = Pass; if (_config.Inbound.Count > 1) { _config.Inbound.RemoveAt(1); } _config.CoreBasicItem.LogEnabled = LogEnabled; _config.CoreBasicItem.Loglevel = Loglevel; _config.CoreBasicItem.DefFingerprint = DefFingerprint; _config.CoreBasicItem.DefUserAgent = DefUserAgent; _config.CoreBasicItem.SendThrough = SendThrough.TrimEx(); _config.CoreBasicItem.BindInterface = BindInterface.TrimEx(); _config.Mux4RayItem.Concurrency = Mux4RayConcurrency > 0 ? Mux4RayConcurrency : null; _config.Mux4RayItem.XudpConcurrency = Mux4RayXudpConcurrency > 0 ? Mux4RayXudpConcurrency : null; _config.Mux4RayItem.XudpProxyUDP443 = Mux4RayXudpProxyUDP443.NullIfEmpty(); _config.Mux4SboxItem.Protocol = Mux4SboxProtocol; _config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox; _config.HysteriaItem.UpMbps = HyUpMbps ?? 0; _config.HysteriaItem.DownMbps = HyDownMbps ?? 0; _config.CoreBasicItem.EnableFragment = EnableFragment; _config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment; _config.Fragment4RayItem ??= new(); _config.Fragment4RayItem.Packets = FragmentPackets; _config.Fragment4RayItem.Lengths = fragmentLengths; _config.Fragment4RayItem.Delays = fragmentDelays; _config.Fragment4RayItem.MaxSplit = FragmentMaxSplit; _config.GuiItem.AutoRun = AutoRun; _config.GuiItem.EnableStatistics = EnableStatistics; _config.GuiItem.DisplayRealTimeSpeed = DisplayRealTimeSpeed; _config.GuiItem.KeepOlderDedupl = KeepOlderDedupl; _config.UiItem.EnableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; _config.UiItem.AutoHideStartup = AutoHideStartup; _config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose; _config.UiItem.MacOSShowInDock = MacOSShowInDock; _config.GuiItem.AutoUpdateInterval = AutoUpdateInterval; _config.UiItem.EnableDragDropSort = EnableDragDropSort; _config.UiItem.DoubleClick2Activate = DoubleClick2Activate; _config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit; _config.UiItem.CurrentFontFamily = CurrentFontFamily; _config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout; _config.SpeedTestItem.MixedConcurrencyCount = MixedConcurrencyCount; _config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl; _config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl; _config.SpeedTestItem.UdpTestTarget = UdpTestTarget; _config.GuiItem.EnableHWA = EnableHWA; _config.ConstItem.SubConvertUrl = SubConvertUrl; _config.UiItem.MainGirdOrientation = (EGirdOrientation)MainGirdOrientation; _config.ConstItem.GeoSourceUrl = GeoFileSourceUrl; _config.ConstItem.SrsSourceUrl = SrsFileSourceUrl; _config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl; _config.SpeedTestItem.IPAPIUrl = IPAPIUrl; _config.GuiItem.RootCertProvider = RootCertProvider; //systemProxy _config.SystemProxyItem.SystemProxyExceptions = SystemProxyExceptions; _config.SystemProxyItem.NotProxyLocalAddress = NotProxyLocalAddress; _config.SystemProxyItem.SystemProxyAdvancedProtocol = SystemProxyAdvancedProtocol; _config.SystemProxyItem.CustomSystemProxyPacPath = CustomSystemProxyPacPath; _config.SystemProxyItem.CustomSystemProxyScriptPath = CustomSystemProxyScriptPath; //tun mode _config.TunModeItem.AutoRoute = TunAutoRoute; _config.TunModeItem.StrictRoute = TunStrictRoute; _config.TunModeItem.Stack = TunStack; _config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.IcmpRouting = TunIcmpRouting; _config.TunModeItem.EnableLegacyProtect = TunEnableLegacyProtect; _config.TunModeItem.RouteExcludeAddress = Utils.String2List(TunRouteExcludeAddress); _config.TunModeItem.IPv4Address = TunIPv4Address; _config.TunModeItem.IPv6Address = TunIPv6Address; //coreType await SaveCoreType(); if (await ConfigHandler.SaveConfig(_config) == 0) { await AutoStartupHandler.UpdateTask(_config); AppManager.Instance.Reset(); NoticeManager.Instance.Enqueue(needReboot ? ResUI.NeedRebootTips : ResUI.OperationSuccess); RequestClose?.Invoke(this, EventArgs.Empty); } else { NoticeManager.Instance.Enqueue(ResUI.OperationFailed); } } private async Task SaveCoreType() { for (var k = 1; k <= _config.CoreTypeItem.Count; k++) { var item = _config.CoreTypeItem[k - 1]; var type = string.Empty; switch ((int)item.ConfigType) { case 1: type = CoreType1; break; case 2: type = CoreType2; break; case 3: type = CoreType3; break; case 4: type = CoreType4; break; case 5: type = CoreType5; break; case 6: type = CoreType6; break; case 7: type = CoreType7; break; case 9: type = CoreType9; break; default: continue; } item.CoreType = Enum.Parse(type); } await Task.CompletedTask; } }