diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index f9ff4494..b5fdea2b 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -258,6 +258,7 @@ public static class ConfigHandler item.CertSha = profileItem.CertSha; item.EchConfigList = profileItem.EchConfigList; item.EchForceQuery = profileItem.EchForceQuery; + item.JsonData = profileItem.JsonData; } var ret = item.ConfigType switch @@ -360,11 +361,6 @@ public static class ConfigHandler { } } - else if (profileItem.ConfigType.IsGroupType()) - { - var profileGroupItem = await AppManager.Instance.GetProfileGroupItem(it.IndexId); - await AddGroupServerCommon(config, profileItem, profileGroupItem, true); - } else { await AddServerCommon(config, profileItem, true); @@ -967,9 +963,11 @@ public static class ConfigHandler profileItem.Path = profileItem.Path.TrimEx(); profileItem.StreamSecurity = profileItem.StreamSecurity.TrimEx(); - if (!Global.Flows.Contains(profileItem.Flow)) + var extraItem = profileItem.GetExtraItem(); + + if (!Global.Flows.Contains(extraItem.Flow ?? string.Empty)) { - profileItem.Flow = Global.Flows.First(); + extraItem.Flow = Global.Flows.First(); } if (profileItem.Id.IsNullOrEmpty()) { @@ -980,6 +978,8 @@ public static class ConfigHandler profileItem.Security = Global.None; } + profileItem.SetExtraItem(extraItem); + await AddServerCommon(config, profileItem, toFile); return 0; @@ -1082,37 +1082,6 @@ public static class ConfigHandler return 0; } - public static async Task AddGroupServerCommon(Config config, ProfileItem profileItem, ProfileGroupItem profileGroupItem, bool toFile = true) - { - var maxSort = -1; - if (profileItem.IndexId.IsNullOrEmpty()) - { - profileItem.IndexId = Utils.GetGuid(false); - maxSort = ProfileExManager.Instance.GetMaxSort(); - } - var groupType = profileItem.ConfigType == EConfigType.ProxyChain ? EConfigType.ProxyChain.ToString() : profileGroupItem.MultipleLoad.ToString(); - profileItem.Address = $"{profileItem.CoreType}-{groupType}"; - if (maxSort > 0) - { - ProfileExManager.Instance.SetSort(profileItem.IndexId, maxSort + 1); - } - if (toFile) - { - await SQLiteHelper.Instance.ReplaceAsync(profileItem); - if (profileGroupItem != null) - { - profileGroupItem.IndexId = profileItem.IndexId; - await ProfileGroupItemManager.Instance.SaveItemAsync(profileGroupItem); - } - else - { - ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(profileItem.IndexId); - await ProfileGroupItemManager.Instance.SaveTo(); - } - } - return 0; - } - /// /// Compare two profile items to determine if they represent the same server /// Used for deduplication and server matching @@ -1128,6 +1097,8 @@ public static class ConfigHandler return false; } + var extraItem = o.GetExtraItem(); + return o.ConfigType == n.ConfigType && AreEqual(o.Address, n.Address) && o.Port == n.Port @@ -1138,7 +1109,7 @@ public static class ConfigHandler && AreEqual(o.RequestHost, n.RequestHost) && AreEqual(o.Path, n.Path) && (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity) - && AreEqual(o.Flow, n.Flow) + && AreEqual(extraItem.Flow, extraItem.Flow) && AreEqual(o.Sni, n.Sni) && AreEqual(o.Alpn, n.Alpn) && AreEqual(o.Fingerprint, n.Fingerprint) @@ -1199,7 +1170,7 @@ public static class ConfigHandler var indexId = Utils.GetGuid(false); var childProfileIndexId = Utils.List2String(selecteds.Select(p => p.IndexId).ToList()); - var remark = subId.IsNullOrEmpty() ? string.Empty : $"{(await AppManager.Instance.GetSubItem(subId)).Remarks} "; + var remark = subId.IsNullOrEmpty() ? string.Empty : $"{(await AppManager.Instance.GetSubItem(subId))?.Remarks} "; if (coreType == ECoreType.Xray) { remark += multipleLoad switch @@ -1233,13 +1204,12 @@ public static class ConfigHandler { profile.Subid = subId; } - var profileGroup = new ProfileGroupItem + var extraItem = new ProtocolExtraItem { - ChildItems = childProfileIndexId, - MultipleLoad = multipleLoad, - IndexId = indexId, + ChildItems = childProfileIndexId, MultipleLoad = multipleLoad, }; - var ret = await AddGroupServerCommon(config, profile, profileGroup, true); + profile.SetExtraItem(extraItem); + var ret = await AddServerCommon(config, profile, true); result.Success = ret == 0; result.Data = indexId; return result; @@ -1261,7 +1231,7 @@ public static class ConfigHandler var tun2SocksAddress = node.Address; if (node.ConfigType.IsGroupType()) { - var lstAddresses = (await ProfileGroupItemManager.GetAllChildDomainAddresses(node.IndexId)).ToList(); + var lstAddresses = (await GroupProfileManager.GetAllChildDomainAddresses(node)).ToList(); if (lstAddresses.Count > 0) { tun2SocksAddress = Utils.List2String(lstAddresses); diff --git a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs index 8bd3c3de..a2930362 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs @@ -21,9 +21,10 @@ public class BaseFmt protected static int ToUriQuery(ProfileItem item, string? securityDef, ref Dictionary dicQuery) { - if (item.Flow.IsNotEmpty()) + var extraItem = item.GetExtraItem(); + if (!extraItem.Flow.IsNullOrEmpty()) { - dicQuery.Add("flow", item.Flow); + dicQuery.Add("flow", extraItem.Flow); } if (item.StreamSecurity.IsNotEmpty()) @@ -208,7 +209,9 @@ public class BaseFmt protected static int ResolveUriQuery(NameValueCollection query, ref ProfileItem item) { - item.Flow = GetQueryValue(query, "flow"); + var extraItem = item.GetExtraItem(); + extraItem.Flow = GetQueryValue(query, "flow"); + item.SetExtraItem(extraItem); item.StreamSecurity = GetQueryValue(query, "security"); item.Sni = GetQueryValue(query, "sni"); item.Alpn = GetQueryDecoded(query, "alpn"); diff --git a/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs b/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs index d92bd0c8..fe6f9168 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/Hysteria2Fmt.cs @@ -24,11 +24,15 @@ public class Hysteria2Fmt : BaseFmt var query = Utils.ParseQueryString(url.Query); ResolveUriQuery(query, ref item); item.Path = GetQueryDecoded(query, "obfs-password"); - item.Ports = GetQueryDecoded(query, "mport"); if (item.CertSha.IsNullOrEmpty()) { item.CertSha = GetQueryDecoded(query, "pinSHA256"); } + ProtocolExtraItem extraItem = new() + { + Ports = GetQueryDecoded(query, "mport") + }; + item.SetExtraItem(extraItem); return item; } @@ -55,9 +59,10 @@ public class Hysteria2Fmt : BaseFmt dicQuery.Add("obfs", "salamander"); dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path)); } - if (item.Ports.IsNotEmpty()) + var extra = item.GetExtraItem(); + if (extra?.Ports?.IsNotEmpty() ?? false) { - dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-'))); + dicQuery.Add("mport", Utils.UrlEncode(extra.Ports.Replace(':', '-'))); } if (!item.CertSha.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs index e6535d6e..6bab8a50 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/VmessFmt.cs @@ -23,6 +23,8 @@ public class VmessFmt : BaseFmt { return null; } + + var extraItem = item?.GetExtraItem(); var vmessQRCode = new VmessQRCode { v = item.ConfigVersion, @@ -30,7 +32,7 @@ public class VmessFmt : BaseFmt add = item.Address, port = item.Port, id = item.Id, - aid = item.AlterId, + aid = int.TryParse(extraItem?.AlterId, out var result) ? result : 0, scy = item.Security, net = item.Network, type = item.HeaderType, @@ -76,7 +78,10 @@ public class VmessFmt : BaseFmt item.Address = Utils.ToString(vmessQRCode.add); item.Port = vmessQRCode.port; item.Id = Utils.ToString(vmessQRCode.id); - item.AlterId = vmessQRCode.aid; + item.SetExtraItem(new ProtocolExtraItem + { + AlterId = vmessQRCode.aid.ToString(), + }); item.Security = Utils.ToString(vmessQRCode.scy); item.Security = vmessQRCode.scy.IsNotEmpty() ? vmessQRCode.scy : Global.DefaultSecurity; diff --git a/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs b/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs index 965335cc..e101ba53 100644 --- a/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs +++ b/v2rayN/ServiceLib/Manager/ActionPrecheckManager.cs @@ -128,6 +128,8 @@ public class ActionPrecheckManager } } + var extraItem = item.GetExtraItem(); + switch (item.ConfigType) { case EConfigType.VMess: @@ -144,7 +146,7 @@ public class ActionPrecheckManager errors.Add(string.Format(ResUI.InvalidProperty, "Id")); } - if (!Global.Flows.Contains(item.Flow)) + if (!Global.Flows.Contains(extraItem.Flow ?? string.Empty)) { errors.Add(string.Format(ResUI.InvalidProperty, "Flow")); } @@ -202,37 +204,22 @@ public class ActionPrecheckManager { var errors = new List(); - ProfileGroupItemManager.Instance.TryGet(item.IndexId, out var group); - if (group is null || group.NotHasChild()) - { - errors.Add(string.Format(ResUI.GroupEmpty, item.Remarks)); - return errors; - } - - var hasCycle = ProfileGroupItemManager.HasCycle(item.IndexId); + var hasCycle = await GroupProfileManager.HasCycle(item.IndexId, item.GetExtraItem()); if (hasCycle) { errors.Add(string.Format(ResUI.GroupSelfReference, item.Remarks)); return errors; } - var childIds = new List(); - var subItems = await ProfileGroupItemManager.GetSubChildProfileItems(group); - childIds.AddRangeSafe(subItems.Select(p => p.IndexId)); - childIds.AddRangeSafe(Utils.String2List(group.ChildItems)); + var (childItems, _) = await GroupProfileManager.GetChildProfileItems(item); - foreach (var child in childIds) + foreach (var childItem in childItems) { var childErrors = new List(); - if (child.IsNullOrEmpty()) - { - continue; - } - var childItem = await AppManager.Instance.GetProfileItem(child); if (childItem is null) { - childErrors.Add(string.Format(ResUI.NodeTagNotExist, child)); + childErrors.Add(string.Format(ResUI.NodeTagNotExist, "")); continue; } diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index 6c20022a..4c978934 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -94,6 +94,8 @@ public sealed class AppManager _ = StatePort; _ = StatePort2; + _ = MigrateProfileExtra(); + return true; } @@ -225,15 +227,6 @@ public sealed class AppManager return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Remarks == remarks); } - public async Task GetProfileGroupItem(string indexId) - { - if (indexId.IsNullOrEmpty()) - { - return null; - } - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); - } - public async Task?> RoutingItems() { return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); @@ -264,6 +257,40 @@ public sealed class AppManager return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); } + public async Task MigrateProfileExtra() + { + var list = await SQLiteHelper.Instance.TableAsync().ToListAsync(); + foreach (var item in list) + { + if (!item.JsonData.IsNullOrEmpty()) + { + return; + } + ProtocolExtraItem extra = new() + { + AlterId = item.AlterId.ToString(), + Flow = item.Flow.IsNotEmpty() ? item.Flow : null, + Ports = item.Ports.IsNotEmpty() ? item.Ports : null, + }; + if (item.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) + { + extra.GroupType = nameof(item.ConfigType); + ProfileGroupItemManager.Instance.TryGet(item.IndexId, out var groupItem); + if (groupItem != null && !groupItem.NotHasChild()) + { + extra.ChildItems = groupItem.ChildItems; + extra.SubChildItems = groupItem.SubChildItems; + extra.Filter = groupItem.Filter; + extra.MultipleLoad = groupItem.MultipleLoad; + } + } + item.SetExtraItem(extra); + await SQLiteHelper.Instance.UpdateAsync(item); + } + + await ProfileGroupItemManager.Instance.ClearAll(); + } + #endregion SqliteHelper #region Core Type diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs new file mode 100644 index 00000000..af2029fa --- /dev/null +++ b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs @@ -0,0 +1,175 @@ +namespace ServiceLib.Manager; + +public class GroupProfileManager +{ + public static async Task HasCycle(ProfileItem item) + { + return await HasCycle(item.IndexId, item.GetExtraItem()); + } + + public static async Task HasCycle(string? indexId, ProtocolExtraItem? extraInfo) + { + return await HasCycle(indexId, extraInfo, new HashSet(), new HashSet()); + } + + public static async Task HasCycle(string? indexId, ProtocolExtraItem? extraInfo, HashSet visited, HashSet stack) + { + if (indexId.IsNullOrEmpty() || extraInfo == null) + { + return false; + } + + if (stack.Contains(indexId)) + { + return true; + } + + if (visited.Contains(indexId)) + { + return false; + } + + visited.Add(indexId); + stack.Add(indexId); + + try + { + if (extraInfo.GroupType.IsNullOrEmpty()) + { + return false; + } + + if (extraInfo.ChildItems.IsNullOrEmpty()) + { + return false; + } + + var childIds = Utils.String2List(extraInfo.ChildItems) + ?.Where(p => !string.IsNullOrEmpty(p)) + .ToList(); + if (childIds == null) + { + return false; + } + + foreach (var child in childIds) + { + var childItem = await AppManager.Instance.GetProfileItem(child); + if (await HasCycle(child, childItem?.GetExtraItem(), visited, stack)) + { + return true; + } + } + + return false; + } + finally + { + stack.Remove(indexId); + } + } + + public static async Task<(List Items, ProtocolExtraItem? Extra)> GetChildProfileItems(ProfileItem profileItem) + { + var profileExtra = profileItem?.GetExtraItem(); + if (profileExtra == null) + { + return ([], null); + } + var items = await GetChildProfileItems(profileExtra); + var subItems = await GetSubChildProfileItems(profileExtra); + items.AddRange(subItems); + + return (items, profileExtra); + } + + public static async Task> GetChildProfileItems(ProtocolExtraItem? extra) + { + if (extra == null || extra.ChildItems.IsNullOrEmpty()) + { + return new(); + } + var childProfiles = (await Task.WhenAll( + Utils.String2List(extra.ChildItems) + .Where(p => !p.IsNullOrEmpty()) + .Select(AppManager.Instance.GetProfileItem) + )) + .Where(p => + p != null && + p.IsValid() && + p.ConfigType != EConfigType.Custom + ) + .ToList(); + return childProfiles; + } + + public static async Task> GetSubChildProfileItems(ProtocolExtraItem? extra) + { + if (extra == null || extra.Filter.IsNullOrEmpty()) + { + return new(); + } + var childProfiles = await AppManager.Instance.ProfileItems(extra.SubChildItems ?? string.Empty); + + return childProfiles.Where(p => + p != null && + p.IsValid() && + !p.ConfigType.IsComplexType() && + (extra.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extra.Filter)) + ) + .ToList(); + } + + public static async Task> GetAllChildDomainAddresses(ProfileItem profileItem) + { + var childAddresses = new HashSet(); + var (childItems, _) = await GetChildProfileItems(profileItem); + foreach (var child in childItems) + { + if (!child.IsComplex()) + { + childAddresses.Add(child.Address); + } + else if (child.ConfigType.IsGroupType()) + { + var subAddresses = await GetAllChildDomainAddresses(child); + foreach (var addr in subAddresses) + { + childAddresses.Add(addr); + } + } + } + return childAddresses; + } + + public static async Task> GetAllChildEchQuerySni(ProfileItem profileItem) + { + var childAddresses = new HashSet(); + var (childItems, _) = await GetChildProfileItems(profileItem); + foreach (var childNode in childItems) + { + if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty()) + { + if (childNode.StreamSecurity == Global.StreamSecurity + && childNode.EchConfigList?.Contains("://") == true) + { + var idx = childNode.EchConfigList.IndexOf('+'); + childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni); + } + else + { + childAddresses.Add(childNode.Sni); + } + } + else if (childNode.ConfigType.IsGroupType()) + { + var subAddresses = await GetAllChildDomainAddresses(childNode); + foreach (var addr in subAddresses) + { + childAddresses.Add(addr); + } + } + } + return childAddresses; + } +} diff --git a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs index 041b1c78..01983440 100644 --- a/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs +++ b/v2rayN/ServiceLib/Manager/ProfileGroupItemManager.cs @@ -29,11 +29,6 @@ public class ProfileGroupItemManager return _items.TryGetValue(indexId, out item); } - public ProfileGroupItem? GetOrDefault(string indexId) - { - return string.IsNullOrWhiteSpace(indexId) ? null : (_items.TryGetValue(indexId, out var v) ? v : null); - } - private async Task InitData() { await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileGroupItem where IndexId not in ( select indexId from ProfileItem )"); @@ -42,347 +37,9 @@ public class ProfileGroupItemManager _items = new ConcurrentDictionary(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!)); } - private ProfileGroupItem AddProfileGroupItem(string indexId) - { - var profileGroupItem = new ProfileGroupItem() - { - IndexId = indexId, - ChildItems = string.Empty, - MultipleLoad = EMultipleLoad.LeastPing - }; - - _items[indexId] = profileGroupItem; - return profileGroupItem; - } - - private ProfileGroupItem GetProfileGroupItem(string indexId) - { - if (string.IsNullOrEmpty(indexId)) - { - indexId = Utils.GetGuid(false); - } - - return _items.GetOrAdd(indexId, AddProfileGroupItem); - } - public async Task ClearAll() { await SQLiteHelper.Instance.ExecuteAsync($"delete from ProfileGroupItem "); _items.Clear(); } - - public async Task SaveTo() - { - try - { - var lstExists = await SQLiteHelper.Instance.TableAsync().ToListAsync(); - var existsMap = lstExists.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!); - - var lstInserts = new List(); - var lstUpdates = new List(); - - foreach (var item in _items.Values) - { - if (string.IsNullOrEmpty(item.IndexId)) - { - continue; - } - - if (existsMap.ContainsKey(item.IndexId)) - { - lstUpdates.Add(item); - } - else - { - lstInserts.Add(item); - } - } - - try - { - if (lstInserts.Count > 0) - { - await SQLiteHelper.Instance.InsertAllAsync(lstInserts); - } - - if (lstUpdates.Count > 0) - { - await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates); - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - } - - public ProfileGroupItem GetOrCreateAndMarkDirty(string indexId) - { - return GetProfileGroupItem(indexId); - } - - public async ValueTask DisposeAsync() - { - await SaveTo(); - } - - public async Task SaveItemAsync(ProfileGroupItem item) - { - if (item is null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (string.IsNullOrWhiteSpace(item.IndexId)) - { - throw new ArgumentException("IndexId required", nameof(item)); - } - - _items[item.IndexId] = item; - - try - { - var lst = await SQLiteHelper.Instance.TableAsync().Where(t => t.IndexId == item.IndexId).ToListAsync(); - if (lst != null && lst.Count > 0) - { - await SQLiteHelper.Instance.UpdateAllAsync(new List { item }); - } - else - { - await SQLiteHelper.Instance.InsertAllAsync(new List { item }); - } - } - catch (Exception ex) - { - Logging.SaveLog(_tag, ex); - } - } - - #region Helper - - public static bool HasCycle(string? indexId) - { - return HasCycle(indexId, new HashSet(), new HashSet()); - } - - public static bool HasCycle(string? indexId, HashSet visited, HashSet stack) - { - if (indexId.IsNullOrEmpty()) - { - return false; - } - - if (stack.Contains(indexId)) - { - return true; - } - - if (visited.Contains(indexId)) - { - return false; - } - - visited.Add(indexId); - stack.Add(indexId); - - try - { - Instance.TryGet(indexId, out var groupItem); - - if (groupItem == null || groupItem.ChildItems.IsNullOrEmpty()) - { - return false; - } - - var childIds = Utils.String2List(groupItem.ChildItems) - .Where(p => !string.IsNullOrEmpty(p)) - .ToList(); - if (childIds == null) - { - return false; - } - - foreach (var child in childIds) - { - if (HasCycle(child, visited, stack)) - { - return true; - } - } - - return false; - } - finally - { - stack.Remove(indexId); - } - } - - public static async Task<(List Items, ProfileGroupItem? Group)> GetChildProfileItems(string? indexId) - { - Instance.TryGet(indexId, out var profileGroupItem); - if (profileGroupItem == null || profileGroupItem.NotHasChild()) - { - return (new List(), profileGroupItem); - } - - var items = new List(); - items.AddRange(await GetSubChildProfileItems(profileGroupItem)); - items.AddRange(await GetChildProfileItems(profileGroupItem)); - - return (items, profileGroupItem); - } - - public static async Task> GetChildProfileItems(ProfileGroupItem? group) - { - if (group == null || group.ChildItems.IsNullOrEmpty()) - { - return new(); - } - var childProfiles = (await Task.WhenAll( - Utils.String2List(group.ChildItems) - .Where(p => !p.IsNullOrEmpty()) - .Select(AppManager.Instance.GetProfileItem) - )) - .Where(p => - p != null && - p.IsValid() && - p.ConfigType != EConfigType.Custom - ) - .ToList(); - return childProfiles; - } - - public static async Task> GetSubChildProfileItems(ProfileGroupItem? group) - { - if (group == null || group.SubChildItems.IsNullOrEmpty()) - { - return new(); - } - var childProfiles = await AppManager.Instance.ProfileItems(group.SubChildItems); - - return childProfiles.Where(p => - p != null && - p.IsValid() && - !p.ConfigType.IsComplexType() && - (group.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, group.Filter)) - ) - .ToList(); - } - - public static async Task> GetAllChildDomainAddresses(string indexId) - { - // include grand children - var childAddresses = new HashSet(); - if (!Instance.TryGet(indexId, out var groupItem) || groupItem == null) - { - return childAddresses; - } - - if (groupItem.SubChildItems.IsNotEmpty()) - { - var subItems = await GetSubChildProfileItems(groupItem); - subItems.ForEach(p => childAddresses.Add(p.Address)); - } - - var childIds = Utils.String2List(groupItem.ChildItems) ?? []; - - foreach (var childId in childIds) - { - var childNode = await AppManager.Instance.GetProfileItem(childId); - if (childNode == null) - { - continue; - } - - if (!childNode.IsComplex()) - { - childAddresses.Add(childNode.Address); - } - else if (childNode.ConfigType.IsGroupType()) - { - var subAddresses = await GetAllChildDomainAddresses(childNode.IndexId); - foreach (var addr in subAddresses) - { - childAddresses.Add(addr); - } - } - } - - return childAddresses; - } - - public static async Task> GetAllChildEchQuerySni(string indexId) - { - // include grand children - var childAddresses = new HashSet(); - if (!Instance.TryGet(indexId, out var groupItem) || groupItem == null) - { - return childAddresses; - } - - if (groupItem.SubChildItems.IsNotEmpty()) - { - var subItems = await GetSubChildProfileItems(groupItem); - foreach (var childNode in subItems) - { - if (childNode.EchConfigList.IsNullOrEmpty()) - { - continue; - } - if (childNode.StreamSecurity == Global.StreamSecurity - && childNode.EchConfigList?.Contains("://") == true) - { - var idx = childNode.EchConfigList.IndexOf('+'); - childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni); - } - else - { - childAddresses.Add(childNode.Sni); - } - } - } - - var childIds = Utils.String2List(groupItem.ChildItems) ?? []; - - foreach (var childId in childIds) - { - var childNode = await AppManager.Instance.GetProfileItem(childId); - if (childNode == null) - { - continue; - } - - if (!childNode.IsComplex() && !childNode.EchConfigList.IsNullOrEmpty()) - { - if (childNode.StreamSecurity == Global.StreamSecurity - && childNode.EchConfigList?.Contains("://") == true) - { - var idx = childNode.EchConfigList.IndexOf('+'); - childAddresses.Add(idx > 0 ? childNode.EchConfigList[..idx] : childNode.Sni); - } - else - { - childAddresses.Add(childNode.Sni); - } - } - else if (childNode.ConfigType.IsGroupType()) - { - var subAddresses = await GetAllChildDomainAddresses(childNode.IndexId); - foreach (var addr in subAddresses) - { - childAddresses.Add(addr); - } - } - } - - return childAddresses; - } - - #endregion Helper } diff --git a/v2rayN/ServiceLib/Models/ProfileGroupItem.cs b/v2rayN/ServiceLib/Models/ProfileGroupItem.cs index 12c0f899..8d2f61b1 100644 --- a/v2rayN/ServiceLib/Models/ProfileGroupItem.cs +++ b/v2rayN/ServiceLib/Models/ProfileGroupItem.cs @@ -1,5 +1,6 @@ namespace ServiceLib.Models; +// deprecated [Serializable] public class ProfileGroupItem { diff --git a/v2rayN/ServiceLib/Models/ProfileItem.cs b/v2rayN/ServiceLib/Models/ProfileItem.cs index b5424265..b299ace0 100644 --- a/v2rayN/ServiceLib/Models/ProfileItem.cs +++ b/v2rayN/ServiceLib/Models/ProfileItem.cs @@ -94,7 +94,7 @@ public class ProfileItem : ReactiveObject return false; } - if (!Global.Flows.Contains(Flow)) + if (!Global.Flows.Contains(GetExtraItem().Flow ?? string.Empty)) { return false; } @@ -125,6 +125,20 @@ public class ProfileItem : ReactiveObject return true; } + public void SetExtraItem(ProtocolExtraItem extraItem) + { + JsonData = JsonUtils.Serialize(extraItem, false); + } + + public ProtocolExtraItem GetExtraItem() + { + if (JsonData.IsNullOrEmpty()) + { + return new ProtocolExtraItem(); + } + return JsonUtils.Deserialize(JsonData); + } + #endregion function [PrimaryKey] @@ -134,9 +148,7 @@ public class ProfileItem : ReactiveObject public int ConfigVersion { get; set; } public string Address { get; set; } public int Port { get; set; } - public string Ports { get; set; } public string Id { get; set; } - public int AlterId { get; set; } public string Security { get; set; } public string Network { get; set; } public string Remarks { get; set; } @@ -147,7 +159,6 @@ public class ProfileItem : ReactiveObject public string AllowInsecure { get; set; } public string Subid { get; set; } public bool IsSub { get; set; } = true; - public string Flow { get; set; } public string Sni { get; set; } public string Alpn { get; set; } = string.Empty; public ECoreType? CoreType { get; set; } @@ -164,4 +175,9 @@ public class ProfileItem : ReactiveObject public string CertSha { get; set; } public string EchConfigList { get; set; } public string EchForceQuery { get; set; } + public string JsonData { get; set; } + // deprecated + public string Ports { get; set; } + public int AlterId { get; set; } + public string Flow { get; set; } } diff --git a/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs b/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs new file mode 100644 index 00000000..41ba1c7d --- /dev/null +++ b/v2rayN/ServiceLib/Models/ProtocolExtraItem.cs @@ -0,0 +1,27 @@ +namespace ServiceLib.Models; + +public class ProtocolExtraItem +{ + // vmess + public string? AlterId { get; set; } + + // vless + public string? Flow { get; set; } + //public string? VisionSeed { get; set; } + + // shadowsocks + //public string? PluginArgs { get; set; } + + // hysteria2 + public string? UpMbps { get; set; } + public string? DownMbps { get; set; } + public string? Ports { get; set; } + public string? HopInterval { get; set; } + + // group profile + public string? GroupType { get; set; } + public string? ChildItems { get; set; } + public string? SubChildItems { get; set; } + public string? Filter { get; set; } + public EMultipleLoad? MultipleLoad { get; set; } +} diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs index 6079b2fb..ac304176 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxDnsService.cs @@ -204,7 +204,7 @@ public partial class CoreConfigSingboxService } else if (node?.ConfigType.IsGroupType() == true) { - var queryServerNames = (await ProfileGroupItemManager.GetAllChildEchQuerySni(node.IndexId)).ToList(); + var queryServerNames = (await GroupProfileManager.GetAllChildEchQuerySni(node)).ToList(); if (queryServerNames.Count > 0) { singboxConfig.dns.rules.Add(new() diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index e2c0d502..61fe2f84 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -6,6 +6,7 @@ public partial class CoreConfigSingboxService { try { + var extraItem = node.GetExtraItem(); outbound.server = node.Address; outbound.server_port = node.Port; outbound.type = Global.ProtocolTypes[node.ConfigType]; @@ -15,7 +16,7 @@ public partial class CoreConfigSingboxService case EConfigType.VMess: { outbound.uuid = node.Id; - outbound.alter_id = node.AlterId; + outbound.alter_id = int.TryParse(extraItem?.AlterId, out var result) ? result : 0; if (Global.VmessSecurities.Contains(node.Security)) { outbound.security = node.Security; @@ -112,13 +113,13 @@ public partial class CoreConfigSingboxService outbound.packet_encoding = "xudp"; - if (node.Flow.IsNullOrEmpty()) + if (extraItem.Flow.IsNullOrEmpty()) { await GenOutboundMux(node, outbound); } else { - outbound.flow = node.Flow; + outbound.flow = extraItem.Flow; } await GenOutboundTransport(node, outbound); @@ -145,12 +146,14 @@ public partial class CoreConfigSingboxService }; } - outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null; - outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null; - if (node.Ports.IsNotEmpty() && (node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(','))) + var extra = node.GetExtraItem(); + outbound.up_mbps = int.TryParse(extra?.UpMbps, out var upMbps) && upMbps >= 0 ? upMbps : (_config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null); + outbound.down_mbps = int.TryParse(extra?.DownMbps, out var downMbps) && downMbps >= 0 ? downMbps : (_config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null); + var ports = extra?.Ports?.IsNullOrEmpty() == false ? extra.Ports : null; + if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) { outbound.server_port = null; - outbound.server_ports = node.Ports.Split(',') + outbound.server_ports = ports.Split(',') .Select(p => p.Trim()) .Where(p => p.IsNotEmpty()) .Select(p => @@ -453,13 +456,13 @@ public partial class CoreConfigSingboxService { return -1; } - var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + var hasCycle = await GroupProfileManager.HasCycle(node); if (hasCycle) { return -1; } - var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { return -1; @@ -467,13 +470,14 @@ public partial class CoreConfigSingboxService switch (node.ConfigType) { case EConfigType.PolicyGroup: + var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing; if (ignoreOriginChain) { - await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, baseTagName); + await GenOutboundsList(childProfiles, singboxConfig, multipleLoad, baseTagName); } else { - await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, baseTagName); + await GenOutboundsListWithChain(childProfiles, singboxConfig, multipleLoad, baseTagName); } break; @@ -585,7 +589,7 @@ public partial class CoreConfigSingboxService if (node.ConfigType.IsGroupType()) { - var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { continue; @@ -594,7 +598,8 @@ public partial class CoreConfigSingboxService var ret = node.ConfigType switch { EConfigType.PolicyGroup => - await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName), + await GenOutboundsListWithChain(childProfiles, singboxConfig, + profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName), EConfigType.ProxyChain => await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName), _ => throw new NotImplementedException() @@ -763,7 +768,7 @@ public partial class CoreConfigSingboxService if (node.ConfigType.IsGroupType()) { - var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { continue; @@ -772,7 +777,7 @@ public partial class CoreConfigSingboxService var ret = node.ConfigType switch { EConfigType.PolicyGroup => - await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName), + await GenOutboundsList(childProfiles, singboxConfig, profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing, childBaseTagName), EConfigType.ProxyChain => await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName), _ => throw new NotImplementedException() diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index d3575685..17fc7a09 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -6,6 +6,7 @@ public partial class CoreConfigV2rayService { try { + var extraItem = node.GetExtraItem(); var muxEnabled = node.MuxEnabled ?? _config.CoreBasicItem.MuxEnabled; switch (node.ConfigType) { @@ -36,7 +37,7 @@ public partial class CoreConfigV2rayService } usersItem.id = node.Id; - usersItem.alterId = node.AlterId; + usersItem.alterId = int.TryParse(extraItem?.AlterId, out var result) ? result : 0; usersItem.email = Global.UserEMail; if (Global.VmessSecurities.Contains(node.Security)) { @@ -142,13 +143,13 @@ public partial class CoreConfigV2rayService usersItem.email = Global.UserEMail; usersItem.encryption = node.Security; - if (node.Flow.IsNullOrEmpty()) + if (extraItem.Flow.IsNullOrEmpty()) { await GenOutboundMux(node, outbound, muxEnabled, muxEnabled); } else { - usersItem.flow = node.Flow; + usersItem.flow = extraItem.Flow; await GenOutboundMux(node, outbound, false, muxEnabled); } outbound.settings.servers = null; @@ -509,13 +510,15 @@ public partial class CoreConfigV2rayService break; case "hysteria": + var extraItem = node.GetExtraItem(); + var ports = extraItem?.Ports; HysteriaUdpHop4Ray? udpHop = null; - if (node.Ports.IsNotEmpty() && - (node.Ports.Contains(':') || node.Ports.Contains('-') || node.Ports.Contains(','))) + if (!ports.IsNullOrEmpty() && + (ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) { udpHop = new() { - ports = node.Ports.Replace(':', '-'), + ports = ports.Replace(':', '-'), interval = _config.HysteriaItem.HopInterval > 0 ? _config.HysteriaItem.HopInterval : null, @@ -592,13 +595,13 @@ public partial class CoreConfigV2rayService { return -1; } - var hasCycle = ProfileGroupItemManager.HasCycle(node.IndexId); + var hasCycle = await GroupProfileManager.HasCycle(node); if (hasCycle) { return -1; } - var (childProfiles, profileGroupItem) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, profileExtraItem) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { return -1; @@ -627,8 +630,9 @@ public partial class CoreConfigV2rayService //add balancers if (node.ConfigType == EConfigType.PolicyGroup) { - await GenObservatory(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); - await GenBalancer(v2rayConfig, profileGroupItem.MultipleLoad, baseTagName); + var multipleLoad = profileExtraItem?.MultipleLoad ?? EMultipleLoad.LeastPing; + await GenObservatory(v2rayConfig, multipleLoad, baseTagName); + await GenBalancer(v2rayConfig, multipleLoad, baseTagName); } } catch (Exception ex) @@ -737,7 +741,7 @@ public partial class CoreConfigV2rayService if (node.ConfigType.IsGroupType()) { - var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { continue; @@ -891,7 +895,7 @@ public partial class CoreConfigV2rayService if (node.ConfigType.IsGroupType()) { - var (childProfiles, _) = await ProfileGroupItemManager.GetChildProfileItems(node.IndexId); + var (childProfiles, _) = await GroupProfileManager.GetChildProfileItems(node); if (childProfiles.Count <= 0) { continue; diff --git a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs index 5b0778a5..3789bafa 100644 --- a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs @@ -79,8 +79,8 @@ public class AddGroupServerViewModel : MyReactiveObject public async Task Init() { - ProfileGroupItemManager.Instance.TryGet(SelectedSource.IndexId, out var profileGroup); - PolicyGroupType = (profileGroup?.MultipleLoad ?? EMultipleLoad.LeastPing) switch + var extra = SelectedSource.GetExtraItem(); + PolicyGroupType = (extra?.MultipleLoad ?? EMultipleLoad.LeastPing) switch { EMultipleLoad.LeastPing => ResUI.TbLeastPing, EMultipleLoad.Fallback => ResUI.TbFallback, @@ -93,22 +93,18 @@ public class AddGroupServerViewModel : MyReactiveObject var subs = await AppManager.Instance.SubItems(); subs.Add(new SubItem()); SubItems.AddRange(subs); - SelectedSubItem = SubItems.Where(s => s.Id == profileGroup?.SubChildItems).FirstOrDefault(); - Filter = profileGroup?.Filter; + SelectedSubItem = SubItems.FirstOrDefault(s => s.Id == extra?.SubChildItems); + Filter = extra?.Filter; - var childItemMulti = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource?.IndexId); - if (childItemMulti != null) + var childIndexIds = Utils.String2List(extra?.ChildItems) ?? []; + foreach (var item in childIndexIds) { - var childIndexIds = Utils.String2List(childItemMulti.ChildItems) ?? []; - foreach (var item in childIndexIds) + var child = await AppManager.Instance.GetProfileItem(item); + if (child == null) { - var child = await AppManager.Instance.GetProfileItem(item); - if (child == null) - { - continue; - } - ChildItemsObs.Add(child); + continue; } + ChildItemsObs.Add(child); } } @@ -205,18 +201,11 @@ public class AddGroupServerViewModel : MyReactiveObject { return; } - var childIndexIds = new List(); - foreach (var item in ChildItemsObs) - { - if (item.IndexId.IsNullOrEmpty()) - { - continue; - } - childIndexIds.Add(item.IndexId); - } - var profileGroup = ProfileGroupItemManager.Instance.GetOrCreateAndMarkDirty(SelectedSource.IndexId); - profileGroup.ChildItems = Utils.List2String(childIndexIds); - profileGroup.MultipleLoad = PolicyGroupType switch + + var extra = SelectedSource.GetExtraItem(); + extra.ChildItems = + Utils.List2String(ChildItemsObs.Where(s => !s.IndexId.IsNullOrEmpty()).Select(s => s.IndexId).ToList()); + extra.MultipleLoad = PolicyGroupType switch { var s when s == ResUI.TbLeastPing => EMultipleLoad.LeastPing, var s when s == ResUI.TbFallback => EMultipleLoad.Fallback, @@ -226,17 +215,19 @@ public class AddGroupServerViewModel : MyReactiveObject _ => EMultipleLoad.LeastPing, }; - profileGroup.SubChildItems = SelectedSubItem?.Id; - profileGroup.Filter = Filter; + extra.SubChildItems = SelectedSubItem?.Id; + extra.Filter = Filter; - var hasCycle = ProfileGroupItemManager.HasCycle(profileGroup.IndexId); + var hasCycle = await GroupProfileManager.HasCycle(SelectedSource.IndexId, extra); if (hasCycle) { NoticeManager.Instance.Enqueue(string.Format(ResUI.GroupSelfReference, remarks)); return; } - if (await ConfigHandler.AddGroupServerCommon(_config, SelectedSource, profileGroup, true) == 0) + SelectedSource.SetExtraItem(extra); + + if (await ConfigHandler.AddServerCommon(_config, SelectedSource) == 0) { NoticeManager.Instance.Enqueue(ResUI.OperationSuccess); _updateView?.Invoke(EViewAction.CloseWindow, null); diff --git a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs index 775274d7..589aa8df 100644 --- a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs @@ -17,6 +17,15 @@ public class AddServerViewModel : MyReactiveObject [Reactive] public string CertSha { get; set; } + [Reactive] + public int AlterId { get; set; } + + [Reactive] + public string Ports { get; set; } + + [Reactive] + public string Flow { get; set; } + public ReactiveCommand FetchCertCmd { get; } public ReactiveCommand FetchCertChainCmd { get; } public ReactiveCommand SaveCmd { get; } @@ -63,6 +72,11 @@ public class AddServerViewModel : MyReactiveObject CoreType = SelectedSource?.CoreType?.ToString(); Cert = SelectedSource?.Cert?.ToString() ?? string.Empty; CertSha = SelectedSource?.CertSha?.ToString() ?? string.Empty; + + var extraItem = SelectedSource?.GetExtraItem(); + Ports = extraItem?.Ports ?? string.Empty; + AlterId = int.TryParse(extraItem?.AlterId, out var result) ? result : 0; + Flow = extraItem?.Flow ?? string.Empty; } private async Task SaveServerAsync() @@ -109,6 +123,11 @@ public class AddServerViewModel : MyReactiveObject SelectedSource.CoreType = CoreType.IsNullOrEmpty() ? null : (ECoreType)Enum.Parse(typeof(ECoreType), CoreType); SelectedSource.Cert = Cert.IsNullOrEmpty() ? string.Empty : Cert; SelectedSource.CertSha = CertSha.IsNullOrEmpty() ? string.Empty : CertSha; + var extraItem = SelectedSource.GetExtraItem(); + extraItem.Ports = Ports; + extraItem.AlterId = AlterId > 0 ? AlterId.ToString() : string.Empty; + extraItem.Flow = Flow; + SelectedSource.SetExtraItem(extraItem); if (await ConfigHandler.AddServer(_config, SelectedSource) == 0) { diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs index 9220e8ae..74610bae 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs @@ -120,7 +120,7 @@ public partial class AddServerWindow : WindowBase { case EConfigType.VMess: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables); break; @@ -139,21 +139,21 @@ public partial class AddServerWindow : WindowBase case EConfigType.VLESS: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables); break; case EConfigType.Trojan: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables); break; case EConfigType.Hysteria2: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); break; case EConfigType.TUIC: diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs index 1136220d..f353eb9c 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs @@ -115,7 +115,7 @@ public partial class AddServerWindow { case EConfigType.VMess: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AlterId, v => v.txtAlterId.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.cmbSecurity.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables); break; @@ -134,21 +134,21 @@ public partial class AddServerWindow case EConfigType.VLESS: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId5.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow5.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Flow, v => v.cmbFlow5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Security, v => v.txtSecurity5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled5.IsChecked).DisposeWith(disposables); break; case EConfigType.Trojan: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId6.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Flow, v => v.cmbFlow6.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Flow, v => v.cmbFlow6.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled6.IsChecked).DisposeWith(disposables); break; case EConfigType.Hysteria2: this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); break; case EConfigType.TUIC: