From 49963a16622e0a26a5fdcd9e83472753de0ba4d3 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 14 Nov 2026 20:05:32 +0800 Subject: [PATCH] Extract database queries from AppManager Move configuration queries to ConfigDbQuery and profile migrations to ConfigDbManager. Update desktop, Web API, and test callers to use the new locations. --- .../ConfigHandlerCustomSubscriptionTests.cs | 4 +- .../Builder/CoreConfigContextBuilder.cs | 12 +- .../ServiceLib/Handler/SubscriptionHandler.cs | 2 +- v2rayN/ServiceLib/Manager/AppManager.cs | 476 +----------------- v2rayN/ServiceLib/Manager/CoreManager.cs | 2 +- .../Manager/Data/ConfigDbManager.cs | 376 +++++++++++++- .../ServiceLib/Manager/Data/ConfigDbQuery.cs | 155 ++++++ .../ServiceLib/Manager/GroupProfileManager.cs | 6 +- v2rayN/ServiceLib/Manager/TaskManager.cs | 2 +- .../ServiceLib/Services/SpeedtestService.cs | 2 +- v2rayN/ServiceLib/Services/UpdateService.cs | 4 +- .../ViewModels/AddGroupServerViewModel.cs | 4 +- .../ViewModels/AddServer2ViewModel.cs | 2 +- .../ViewModels/DNSSettingViewModel.cs | 8 +- .../ViewModels/FullConfigTemplateViewModel.cs | 8 +- .../ViewModels/MainWindowViewModel.cs | 2 +- .../ViewModels/ProfilesSelectViewModel.cs | 8 +- .../ViewModels/ProfilesViewModel.cs | 18 +- .../ViewModels/RoutingSettingViewModel.cs | 8 +- .../ViewModels/StatusBarViewModel.cs | 6 +- .../ViewModels/SubSettingViewModel.cs | 4 +- .../Services/V2rayRuntime.CoreUpdate.cs | 6 +- .../Services/V2rayRuntime.Profiles.cs | 34 +- .../Services/V2rayRuntime.Scheduling.cs | 2 +- .../Services/V2rayRuntime.Settings.cs | 62 +-- v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.cs | 46 +- .../Tests/SubscriptionCreationTests.cs | 4 +- 27 files changed, 634 insertions(+), 629 deletions(-) create mode 100644 v2rayN/ServiceLib/Manager/Data/ConfigDbQuery.cs diff --git a/v2rayN/ServiceLib.Tests/Handler/ConfigHandlerCustomSubscriptionTests.cs b/v2rayN/ServiceLib.Tests/Handler/ConfigHandlerCustomSubscriptionTests.cs index e3d52fd7..19b84ea8 100644 --- a/v2rayN/ServiceLib.Tests/Handler/ConfigHandlerCustomSubscriptionTests.cs +++ b/v2rayN/ServiceLib.Tests/Handler/ConfigHandlerCustomSubscriptionTests.cs @@ -33,7 +33,7 @@ public class ConfigHandlerCustomSubscriptionTests await SQLiteHelper.Instance.InsertAsync(oldProfile); var count = await ConfigDbManager.AddBatchServers(config, FullXrayConfigs, subId, true); - var profiles = await AppManager.Instance.ProfileItems(subId) ?? []; + var profiles = await ConfigDbQuery.ProfileItems(subId) ?? []; await count.Should().BeEqualTo(2); await profiles.Should().HaveCount(2); @@ -67,7 +67,7 @@ public class ConfigHandlerCustomSubscriptionTests var invalidSubscription = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("not a valid profile")); var count = await ConfigDbManager.AddBatchServers(config, invalidSubscription, subId, true); - var profiles = await AppManager.Instance.ProfileItems(subId) ?? []; + var profiles = await ConfigDbQuery.ProfileItems(subId) ?? []; await (count < 1).Should().BeTrue(); await profiles.Should().HaveCount(1); diff --git a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs index d0b8fe32..b9012c89 100644 --- a/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs +++ b/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs @@ -41,11 +41,11 @@ public class CoreConfigContextBuilder RunCoreType = runCoreType, AllProxiesMap = [], AppConfig = config, - FullConfigTemplate = await AppManager.Instance.GetFullConfigTemplateItem(coreType), + FullConfigTemplate = await ConfigDbQuery.GetFullConfigTemplateItem(coreType), IsTunEnabled = config.TunModeItem.EnableTun, SimpleDnsItem = config.SimpleDNSItem, ProtectDomainList = [], - RawDnsItem = await AppManager.Instance.GetDNSItem(coreType), + RawDnsItem = await ConfigDbQuery.GetDNSItem(coreType), RoutingItem = await ConfigDbManager.GetDefaultRouting(config), IsWindows = Utils.IsWindows(), IsMacOS = Utils.IsMacOS(), @@ -73,7 +73,7 @@ public class CoreConfigContextBuilder ruleItem.OutboundTag = Global.ProxyTag; continue; } - var ruleOutboundNode = await AppManager.Instance.GetProfileItemViaRemarks(ruleItem.OutboundTag); + var ruleOutboundNode = await ConfigDbQuery.GetProfileItemViaRemarks(ruleItem.OutboundTag); if (ruleOutboundNode == null) { validatorResult.Warnings.Add(string.Format(ResUI.MsgRoutingRuleOutboundNodeNotFound, @@ -277,7 +277,7 @@ public class CoreConfigContextBuilder return (null, result); } - var subItem = await AppManager.Instance.GetSubItem(node.Subid); + var subItem = await ConfigDbQuery.GetSubItem(node.Subid); if (subItem == null) { return (null, result); @@ -288,7 +288,7 @@ public class CoreConfigContextBuilder if (!subItem.PrevProfile.IsNullOrEmpty()) { - prevNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); + prevNode = await ConfigDbQuery.GetProfileItemViaRemarks(subItem.PrevProfile); if (prevNode == null) { result.Warnings.Add(string.Format(ResUI.MsgSubscriptionPrevProfileNotFound, subItem.PrevProfile)); @@ -296,7 +296,7 @@ public class CoreConfigContextBuilder } if (!subItem.NextProfile.IsNullOrEmpty()) { - nextNode = await AppManager.Instance.GetProfileItemViaRemarks(subItem.NextProfile); + nextNode = await ConfigDbQuery.GetProfileItemViaRemarks(subItem.NextProfile); if (nextNode == null) { result.Warnings.Add(string.Format(ResUI.MsgSubscriptionNextProfileNotFound, subItem.NextProfile)); diff --git a/v2rayN/ServiceLib/Handler/SubscriptionHandler.cs b/v2rayN/ServiceLib/Handler/SubscriptionHandler.cs index c55c187b..58721ec7 100644 --- a/v2rayN/ServiceLib/Handler/SubscriptionHandler.cs +++ b/v2rayN/ServiceLib/Handler/SubscriptionHandler.cs @@ -13,7 +13,7 @@ public class SubscriptionHandler( public async Task UpdateProcess(string subId) { await updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart); - var subItem = await AppManager.Instance.SubItems(); + var subItem = await ConfigDbQuery.SubItems(); if (subItem is not { Count: > 0 }) { diff --git a/v2rayN/ServiceLib/Manager/AppManager.cs b/v2rayN/ServiceLib/Manager/AppManager.cs index b45a6501..5a7ac6d0 100644 --- a/v2rayN/ServiceLib/Manager/AppManager.cs +++ b/v2rayN/ServiceLib/Manager/AppManager.cs @@ -104,7 +104,7 @@ public sealed class AppManager Task.Run(async () => { - await MigrateProfileExtra(); + await ConfigDbManager.MigrateProfileExtra(); }).Wait(); return true; @@ -168,480 +168,6 @@ public sealed class AppManager #endregion Config - #region SqliteHelper - - public async Task?> SubItems() - { - return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); - } - - public async Task GetSubItem(string? subid) - { - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(t => t.Id == subid); - } - - public async Task?> ProfileItems(string subid) - { - if (subid.IsNullOrEmpty()) - { - return await SQLiteHelper.Instance.TableAsync().ToListAsync(); - } - else - { - return await SQLiteHelper.Instance.TableAsync().Where(t => t.Subid == subid).ToListAsync(); - } - } - - public async Task?> ProfileItemIndexes(string subid) - { - return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList(); - } - - public async Task?> ProfileModels(string subid, string filter) - { - var sql = @$"select a.IndexId - ,a.ConfigType - ,a.Remarks - ,a.Address - ,a.Port - ,a.Network - ,a.StreamSecurity - ,a.Subid - ,b.remarks as subRemarks - from ProfileItem a - left join SubItem b on a.subid = b.id - where 1=1 "; - if (subid.IsNotEmpty()) - { - sql += $" and a.subid = '{subid}'"; - } - if (filter.IsNotEmpty()) - { - if (filter.Contains('\'')) - { - filter = filter.Replace("'", ""); - } - sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter); - } - - return await SQLiteHelper.Instance.QueryAsync(sql); - } - - public async Task GetProfileItem(string indexId) - { - if (indexId.IsNullOrEmpty()) - { - return null; - } - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); - } - - public async Task> GetProfileItemsByIndexIds(IEnumerable indexIds) - { - var ids = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); - if (ids.Count == 0) - { - return []; - } - - if (ids.Count <= Global.SqliteMaxBatchSize) - { - return await SQLiteHelper.Instance.TableAsync() - .Where(it => ids.Contains(it.IndexId)) - .ToListAsync(); - } - - var items = new List(); - for (var size = 0; size < ids.Count; size += Global.SqliteMaxBatchSize) - { - var chunk = ids.Skip(size).Take(Global.SqliteMaxBatchSize).ToList(); - var chunkItems = await SQLiteHelper.Instance.TableAsync() - .Where(it => chunk.Contains(it.IndexId)) - .ToListAsync(); - - items.AddRange(chunkItems); - } - - return items; - } - - public async Task> GetProfileItemsByIndexIdsAsMap(IEnumerable indexIds) - { - var items = await GetProfileItemsByIndexIds(indexIds); - return items.ToDictionary(it => it.IndexId); - } - - public async Task> GetProfileItemsOrderedByIndexIds(IEnumerable indexIds) - { - var ids = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); - var items = await GetProfileItemsByIndexIds(ids); - var itemMap = items.ToDictionary(it => it.IndexId); - - return ids.Select(itemMap.GetValueOrDefault) - .Where(item => item != null) - .ToList(); - } - - public async Task GetProfileItemViaRemarks(string? remarks) - { - if (remarks.IsNullOrEmpty()) - { - return null; - } - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Remarks == remarks); - } - - public async Task?> RoutingItems() - { - return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); - } - - public async Task GetRoutingItem(string id) - { - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Id == id); - } - - public async Task?> DNSItems() - { - return await SQLiteHelper.Instance.TableAsync().ToListAsync(); - } - - public async Task GetDNSItem(ECoreType eCoreType) - { - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); - } - - public async Task?> FullConfigTemplateItem() - { - return await SQLiteHelper.Instance.TableAsync().ToListAsync(); - } - - public async Task GetFullConfigTemplateItem(ECoreType eCoreType) - { - return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); - } - -#pragma warning disable CS0618 - - public async Task MigrateProfileExtra() - { - await MigrateProfileExtraGroupV2ToV3(); - - await MigrateProfileExtraV2ToV3(); - - await MigrateProfileTransportV3ToV4(); - } - - private async Task MigrateProfileExtraV2ToV3() - { - const int pageSize = 100; - var offset = 0; - - while (true) - { - var sql = $"SELECT * FROM ProfileItem " + - $"WHERE ConfigVersion < 3 " + - $"AND ConfigType NOT IN ({(int)EConfigType.PolicyGroup}, {(int)EConfigType.ProxyChain}) " + - $"LIMIT {pageSize} OFFSET {offset}"; - var batch = await SQLiteHelper.Instance.QueryAsync(sql); - if (batch is null || batch.Count == 0) - { - break; - } - - var batchSuccessCount = await MigrateProfileExtraV2ToV3Sub(batch); - - // Only increment offset by the number of failed items that remain in the result set - // Successfully updated items are automatically excluded from future queries due to ConfigVersion = 3 - offset += batch.Count - batchSuccessCount; - } - - //await ProfileGroupItemManager.Instance.ClearAll(); - } - - private async Task MigrateProfileTransportV3ToV4() - { - const int pageSize = 100; - var offset = 0; - - while (true) - { - var sql = $"SELECT * FROM ProfileItem WHERE ConfigVersion = 3 LIMIT {pageSize} OFFSET {offset}"; - var batch = await SQLiteHelper.Instance.QueryAsync(sql); - if (batch is null || batch.Count == 0) - { - break; - } - - var updateProfileItems = new List(); - foreach (var item in batch) - { - try - { - if (item.Network == Global.RawNetworkAlias) - { - item.Network = nameof(ETransport.raw); - } - var transport = item.GetTransportExtra(); - var network = item.GetNetwork(); - - switch (network) - { - case nameof(ETransport.raw): - transport = transport with - { - RawHeaderType = item.HeaderType.NullIfEmpty(), - Host = item.RequestHost.NullIfEmpty(), - Path = item.Path.NullIfEmpty(), - }; - break; - - case nameof(ETransport.ws): - case nameof(ETransport.httpupgrade): - transport = transport with - { - Host = item.RequestHost.NullIfEmpty(), - Path = item.Path.NullIfEmpty(), - }; - break; - - case nameof(ETransport.xhttp): - transport = transport with - { - Host = item.RequestHost.NullIfEmpty(), - Path = item.Path.NullIfEmpty(), - XhttpMode = item.HeaderType.NullIfEmpty(), - XhttpExtra = item.Extra.NullIfEmpty(), - }; - break; - - case nameof(ETransport.grpc): - transport = transport with - { - GrpcAuthority = item.RequestHost.NullIfEmpty(), - GrpcServiceName = item.Path.NullIfEmpty(), - GrpcMode = item.HeaderType.NullIfEmpty(), - }; - break; - - case nameof(ETransport.kcp): - transport = transport with - { - KcpHeaderType = item.HeaderType.NullIfEmpty(), - KcpSeed = item.Path.NullIfEmpty(), - }; - break; - - default: - item.Network = Global.DefaultNetwork; - transport = transport with - { - RawHeaderType = item.HeaderType.NullIfEmpty(), - Host = item.RequestHost.NullIfEmpty(), - }; - break; - } - - item.SetTransportExtra(transport); - item.ConfigVersion = 4; - updateProfileItems.Add(item); - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileTransportV3ToV4 Error: {ex}"); - } - } - - if (updateProfileItems.Count > 0) - { - try - { - var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); - offset += batch.Count - count; - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileTransportV3ToV4 update error: {ex}"); - offset += batch.Count; - } - } - else - { - offset += batch.Count; - } - } - } - - private async Task MigrateProfileExtraV2ToV3Sub(List batch) - { - var updateProfileItems = new List(); - - foreach (var item in batch) - { - try - { - var extra = item.GetProtocolExtra(); - switch (item.ConfigType) - { - case EConfigType.Shadowsocks: - extra = extra with { SsMethod = item.Security.NullIfEmpty() }; - break; - - case EConfigType.VMess: - extra = extra with - { - AlterId = item.AlterId.ToString(), - VmessSecurity = item.Security.NullIfEmpty(), - }; - break; - - case EConfigType.VLESS: - extra = extra with - { - Flow = item.Flow.NullIfEmpty(), - VlessEncryption = item.Security, - }; - break; - - case EConfigType.Hysteria2: - extra = extra with - { - SalamanderPass = item.Path.NullIfEmpty(), - Ports = item.Ports.NullIfEmpty(), - UpMbps = _config.HysteriaItem.UpMbps, - DownMbps = _config.HysteriaItem.DownMbps, - HopInterval = _config.HysteriaItem.HopInterval.ToString(), - }; - break; - - case EConfigType.TUIC: - extra = extra with { CongestionControl = item.HeaderType.NullIfEmpty(), }; - item.Username = item.Id; - item.Id = item.Security; - item.Password = item.Security; - break; - - case EConfigType.HTTP: - case EConfigType.SOCKS: - item.Username = item.Security; - break; - - case EConfigType.WireGuard: - extra = extra with - { - WgPublicKey = item.PublicKey.NullIfEmpty(), - WgInterfaceAddress = item.RequestHost.NullIfEmpty(), - WgReserved = item.Path.NullIfEmpty(), - WgMtu = int.TryParse(item.ShortId, out var mtu) ? mtu : 1280 - }; - break; - } - - item.SetProtocolExtra(extra); - - item.Password = item.Id; - - item.ConfigVersion = 3; - - updateProfileItems.Add(item); - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileExtra Error: {ex}"); - } - } - - if (updateProfileItems.Count > 0) - { - try - { - var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); - return count; - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileExtraGroup update error: {ex}"); - return 0; - } - } - else - { - return 0; - } - } - - private async Task MigrateProfileExtraGroupV2ToV3() - { - var list = await SQLiteHelper.Instance.TableAsync().ToListAsync(); - var groupItems = new ConcurrentDictionary(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!)); - - var sql = $"SELECT * FROM ProfileItem WHERE ConfigVersion < 3 AND ConfigType IN ({(int)EConfigType.PolicyGroup}, {(int)EConfigType.ProxyChain})"; - var items = await SQLiteHelper.Instance.QueryAsync(sql); - - if (items is null || items.Count == 0) - { - Logging.SaveLog("MigrateProfileExtraGroup: No items to migrate."); - return true; - } - - Logging.SaveLog($"MigrateProfileExtraGroup: Found {items.Count} group items to migrate."); - - var updateProfileItems = new List(); - - foreach (var item in items) - { - try - { - var extra = item.GetProtocolExtra(); - - extra = extra with { GroupType = nameof(item.ConfigType) }; - groupItems.TryGetValue(item.IndexId, out var groupItem); - if (groupItem != null && !groupItem.NotHasChild()) - { - extra = extra with - { - ChildItems = groupItem.ChildItems, - SubChildItems = groupItem.SubChildItems, - Filter = groupItem.Filter, - MultipleLoad = groupItem.MultipleLoad, - }; - } - - item.SetProtocolExtra(extra); - - item.ConfigVersion = 3; - updateProfileItems.Add(item); - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileExtraGroup item error [{item.IndexId}]: {ex}"); - } - } - - if (updateProfileItems.Count > 0) - { - try - { - var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); - Logging.SaveLog($"MigrateProfileExtraGroup: Successfully updated {updateProfileItems.Count} items."); - return updateProfileItems.Count == count; - } - catch (Exception ex) - { - Logging.SaveLog($"MigrateProfileExtraGroup update error: {ex}"); - return false; - } - } - - return true; - - //await ProfileGroupItemManager.Instance.ClearAll(); - } - -#pragma warning restore CS0618 - - #endregion SqliteHelper - #region Core Type public List GetShadowsocksSecurities(ProfileItem profileItem) diff --git a/v2rayN/ServiceLib/Manager/CoreManager.cs b/v2rayN/ServiceLib/Manager/CoreManager.cs index b1efe4c8..8f691e16 100644 --- a/v2rayN/ServiceLib/Manager/CoreManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreManager.cs @@ -134,7 +134,7 @@ public class CoreManager public async Task LoadCoreConfigSpeedtest(ServerTestItem testItem) { - var node = await AppManager.Instance.GetProfileItem(testItem.IndexId); + var node = await ConfigDbQuery.GetProfileItem(testItem.IndexId); if (node is null) { return null; diff --git a/v2rayN/ServiceLib/Manager/Data/ConfigDbManager.cs b/v2rayN/ServiceLib/Manager/Data/ConfigDbManager.cs index d4648ddb..cc25bc9f 100644 --- a/v2rayN/ServiceLib/Manager/Data/ConfigDbManager.cs +++ b/v2rayN/ServiceLib/Manager/Data/ConfigDbManager.cs @@ -20,7 +20,7 @@ public static class ConfigDbManager /// Result of the operation (0 if successful, -1 if failed) public static async Task AddServer(Config config, ProfileItem profileItem) { - var item = await AppManager.Instance.GetProfileItem(profileItem.IndexId); + var item = await ConfigDbQuery.GetProfileItem(profileItem.IndexId); if (item is null) { item = profileItem; @@ -142,7 +142,7 @@ public static class ConfigDbManager { foreach (var it in indexes) { - var item = await AppManager.Instance.GetProfileItem(it.IndexId); + var item = await ConfigDbQuery.GetProfileItem(it.IndexId); if (item is null) { continue; @@ -231,7 +231,7 @@ public static class ConfigDbManager /// The default profile item or null if none exists public static async Task GetDefaultServer(Config config) { - var item = await AppManager.Instance.GetProfileItem(config.IndexId); + var item = await ConfigDbQuery.GetProfileItem(config.IndexId); if (item is null) { var item2 = await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(); @@ -470,7 +470,7 @@ public static class ConfigDbManager /// 0 if successful, -1 if failed public static async Task EditCustomServer(Config config, ProfileItem profileItem) { - var item = await AppManager.Instance.GetProfileItem(profileItem.IndexId); + var item = await ConfigDbQuery.GetProfileItem(profileItem.IndexId); if (item is null) { item = profileItem; @@ -862,7 +862,7 @@ public static class ConfigDbManager /// 0 if successful, -1 if failed public static async Task SortServers(Config config, string subId, string colName, bool asc) { - var lstModel = await AppManager.Instance.ProfileModels(subId, ""); + var lstModel = await ConfigDbQuery.ProfileModels(subId, ""); if (lstModel.Count <= 0) { return -1; @@ -1014,7 +1014,7 @@ public static class ConfigDbManager /// Tuple with total count and remaining count after deduplication public static async Task> DedupServerList(Config config, string subId) { - var lstProfile = await AppManager.Instance.ProfileItems(subId); + var lstProfile = await ConfigDbQuery.ProfileItems(subId); if (lstProfile == null) { return new Tuple(0, 0); @@ -1251,7 +1251,7 @@ public static class ConfigDbManager { try { - var item = await AppManager.Instance.GetProfileItem(indexId); + var item = await ConfigDbQuery.GetProfileItem(indexId); if (item == null) { return 0; @@ -1352,7 +1352,7 @@ public static class ConfigDbManager result.Success = false; return result; } - var childProfiles = await AppManager.Instance.ProfileItems(subId); + var childProfiles = await ConfigDbQuery.ProfileItems(subId); List indexIdList = []; foreach (var regionFilter in PolicyGroupRegionFilters) @@ -1453,7 +1453,7 @@ public static class ConfigDbManager /// Number of removed servers or -1 if failed public static async Task RemoveInvalidServerResult(Config config, string subid) { - var lstModel = await AppManager.Instance.ProfileModels(subid, ""); + var lstModel = await ConfigDbQuery.ProfileModels(subid, ""); lstModel.RemoveAll(t => t.ConfigType.IsComplexType()); if (lstModel is { Count: <= 0 }) { @@ -1494,8 +1494,8 @@ public static class ConfigDbManager var preResolver = string.Empty; if (isSub && subid.IsNotEmpty()) { - subFilter = (await AppManager.Instance.GetSubItem(subid))?.Filter ?? ""; - preResolver = (await AppManager.Instance.GetSubItem(subid))?.PreResolver ?? ""; + subFilter = (await ConfigDbQuery.GetSubItem(subid))?.Filter ?? ""; + preResolver = (await ConfigDbQuery.GetSubItem(subid))?.PreResolver ?? ""; } var dnsClient = preResolver.IsNullOrEmpty() ? null : EndpointResolveManager.BuildDnsClient(preResolver); @@ -1599,7 +1599,7 @@ public static class ConfigDbManager return -1; } - var subItem = await AppManager.Instance.GetSubItem(subid); + var subItem = await ConfigDbQuery.GetSubItem(subid); if (subItem?.CustomCoreType is null) { @@ -1926,7 +1926,7 @@ public static class ConfigDbManager ProfileItem? activeProfile = null; if (isSub && subid.IsNotEmpty()) { - lstOriSub = await AppManager.Instance.ProfileItems(subid); + lstOriSub = await ConfigDbQuery.ProfileItems(subid); activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId); } @@ -1995,7 +1995,7 @@ public static class ConfigDbManager //Select active node if (activeProfile != null) { - var lstSub = await AppManager.Instance.ProfileItems(subid); + var lstSub = await ConfigDbQuery.ProfileItems(subid); var existItem = FindMatchedProfileItem(lstSub, activeProfile); if (existItem != null) { @@ -2006,7 +2006,7 @@ public static class ConfigDbManager //Keep the last traffic statistics if (lstOriSub != null) { - var lstSub = await AppManager.Instance.ProfileItems(subid); + var lstSub = await ConfigDbQuery.ProfileItems(subid); foreach (var item in lstSub) { var existItem = FindMatchedProfileItem(lstOriSub, item); @@ -2072,7 +2072,7 @@ public static class ConfigDbManager /// 0 if successful, -1 if failed public static async Task AddSubItem(Config config, SubItem subItem) { - var item = await AppManager.Instance.GetSubItem(subItem.Id); + var item = await ConfigDbQuery.GetSubItem(subItem.Id); if (item is null) { item = subItem; @@ -2107,7 +2107,7 @@ public static class ConfigDbManager var maxSort = 0; if (await SQLiteHelper.Instance.TableAsync().CountAsync() > 0) { - var lstSubs = await AppManager.Instance.SubItems(); + var lstSubs = await ConfigDbQuery.SubItems(); maxSort = lstSubs.LastOrDefault()?.Sort ?? 0; } item.Sort = maxSort + 1; @@ -2161,7 +2161,7 @@ public static class ConfigDbManager /// 0 if successful public static async Task DeleteSubItem(Config config, string id) { - var item = await AppManager.Instance.GetSubItem(id); + var item = await ConfigDbQuery.GetSubItem(id); if (item is null) { return 0; @@ -2171,7 +2171,7 @@ public static class ConfigDbManager if (item.Id == config.SubIndexId) { - var subs = await AppManager.Instance.SubItems(); + var subs = await ConfigDbQuery.SubItems(); config.SubIndexId = subs.LastOrDefault()?.Id; } @@ -2351,7 +2351,7 @@ public static class ConfigDbManager /// 0 if successful public static async Task SetDefaultRouting(Config config, RoutingItem routingItem) { - var items = await AppManager.Instance.RoutingItems(); + var items = await ConfigDbQuery.RoutingItems(); if (items.Any(t => t.Id == routingItem.Id && t.IsActive == true)) { return -1; @@ -2435,7 +2435,7 @@ public static class ConfigDbManager return await InitBuiltinRouting(config, blImportAdvancedRules); // fallback } - var items = await AppManager.Instance.RoutingItems(); + var items = await ConfigDbQuery.RoutingItems(); var maxSort = items.Count; if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(template.Version)).ToList().Count > 0) { @@ -2486,14 +2486,14 @@ public static class ConfigDbManager public static async Task InitBuiltinRouting(Config config, bool blImportAdvancedRules = false) { var ver = "V4-"; - var items = await AppManager.Instance.RoutingItems(); + var items = await ConfigDbQuery.RoutingItems(); //TODO Temporary code to be removed later var lockItem = items?.FirstOrDefault(t => t.Locked == true); if (lockItem != null) { await ConfigDbManager.RemoveRoutingItem(lockItem); - items = await AppManager.Instance.RoutingItems(); + items = await ConfigDbQuery.RoutingItems(); } if (!blImportAdvancedRules && items.Count() > 0) // items.Count(u => u.Remarks.StartsWith(ver)) > 0) @@ -2570,7 +2570,7 @@ public static class ConfigDbManager /// 0 if successful public static async Task InitBuiltinDNS(Config config) { - var items = await AppManager.Instance.DNSItems(); + var items = await ConfigDbQuery.DNSItems(); // Check existing DNS items and disable those with empty NormalDNS var needsUpdate = false; @@ -2648,7 +2648,7 @@ public static class ConfigDbManager /// DNS item with configuration from the URL public static async Task GetExternalDNSItem(ECoreType type, string url) { - var currentItem = await AppManager.Instance.GetDNSItem(type); + var currentItem = await ConfigDbQuery.GetDNSItem(type); using var downloadHandle = await DownloadService.CreateDownloadServiceWithCheck(); var templateContent = await downloadHandle.TryDownloadString(url); @@ -2720,7 +2720,7 @@ public static class ConfigDbManager public static async Task InitBuiltinFullConfigTemplate(Config config) { - var items = await AppManager.Instance.FullConfigTemplateItem(); + var items = await ConfigDbQuery.FullConfigTemplateItem(); if (items.Count <= 0) { var item = new FullConfigTemplateItem() @@ -2840,4 +2840,328 @@ public static class ConfigDbManager } #endregion Regional Presets + + #region SqliteHelper + +#pragma warning disable CS0618 + + public static async Task MigrateProfileExtra() + { + await MigrateProfileExtraGroupV2ToV3(); + + await MigrateProfileExtraV2ToV3(); + + await MigrateProfileTransportV3ToV4(); + } + + private static async Task MigrateProfileExtraV2ToV3() + { + const int pageSize = 100; + var offset = 0; + + while (true) + { + var sql = $"SELECT * FROM ProfileItem " + + $"WHERE ConfigVersion < 3 " + + $"AND ConfigType NOT IN ({(int)EConfigType.PolicyGroup}, {(int)EConfigType.ProxyChain}) " + + $"LIMIT {pageSize} OFFSET {offset}"; + var batch = await SQLiteHelper.Instance.QueryAsync(sql); + if (batch is null || batch.Count == 0) + { + break; + } + + var batchSuccessCount = await MigrateProfileExtraV2ToV3Sub(batch); + + // Only increment offset by the number of failed items that remain in the result set + // Successfully updated items are automatically excluded from future queries due to ConfigVersion = 3 + offset += batch.Count - batchSuccessCount; + } + + //await ProfileGroupItemManager.Instance.ClearAll(); + } + + private static async Task MigrateProfileTransportV3ToV4() + { + const int pageSize = 100; + var offset = 0; + + while (true) + { + var sql = $"SELECT * FROM ProfileItem WHERE ConfigVersion = 3 LIMIT {pageSize} OFFSET {offset}"; + var batch = await SQLiteHelper.Instance.QueryAsync(sql); + if (batch is null || batch.Count == 0) + { + break; + } + + var updateProfileItems = new List(); + foreach (var item in batch) + { + try + { + if (item.Network == Global.RawNetworkAlias) + { + item.Network = nameof(ETransport.raw); + } + var transport = item.GetTransportExtra(); + var network = item.GetNetwork(); + + switch (network) + { + case nameof(ETransport.raw): + transport = transport with + { + RawHeaderType = item.HeaderType.NullIfEmpty(), + Host = item.RequestHost.NullIfEmpty(), + Path = item.Path.NullIfEmpty(), + }; + break; + + case nameof(ETransport.ws): + case nameof(ETransport.httpupgrade): + transport = transport with + { + Host = item.RequestHost.NullIfEmpty(), + Path = item.Path.NullIfEmpty(), + }; + break; + + case nameof(ETransport.xhttp): + transport = transport with + { + Host = item.RequestHost.NullIfEmpty(), + Path = item.Path.NullIfEmpty(), + XhttpMode = item.HeaderType.NullIfEmpty(), + XhttpExtra = item.Extra.NullIfEmpty(), + }; + break; + + case nameof(ETransport.grpc): + transport = transport with + { + GrpcAuthority = item.RequestHost.NullIfEmpty(), + GrpcServiceName = item.Path.NullIfEmpty(), + GrpcMode = item.HeaderType.NullIfEmpty(), + }; + break; + + case nameof(ETransport.kcp): + transport = transport with + { + KcpHeaderType = item.HeaderType.NullIfEmpty(), + KcpSeed = item.Path.NullIfEmpty(), + }; + break; + + default: + item.Network = Global.DefaultNetwork; + transport = transport with + { + RawHeaderType = item.HeaderType.NullIfEmpty(), + Host = item.RequestHost.NullIfEmpty(), + }; + break; + } + + item.SetTransportExtra(transport); + item.ConfigVersion = 4; + updateProfileItems.Add(item); + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileTransportV3ToV4 Error: {ex}"); + } + } + + if (updateProfileItems.Count > 0) + { + try + { + var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); + offset += batch.Count - count; + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileTransportV3ToV4 update error: {ex}"); + offset += batch.Count; + } + } + else + { + offset += batch.Count; + } + } + } + + private static async Task MigrateProfileExtraV2ToV3Sub(List batch) + { + var updateProfileItems = new List(); + var config = ConfigTextManager.Instance.Config; + + foreach (var item in batch) + { + try + { + var extra = item.GetProtocolExtra(); + switch (item.ConfigType) + { + case EConfigType.Shadowsocks: + extra = extra with { SsMethod = item.Security.NullIfEmpty() }; + break; + + case EConfigType.VMess: + extra = extra with + { + AlterId = item.AlterId.ToString(), + VmessSecurity = item.Security.NullIfEmpty(), + }; + break; + + case EConfigType.VLESS: + extra = extra with + { + Flow = item.Flow.NullIfEmpty(), + VlessEncryption = item.Security, + }; + break; + + case EConfigType.Hysteria2: + extra = extra with + { + SalamanderPass = item.Path.NullIfEmpty(), + Ports = item.Ports.NullIfEmpty(), + UpMbps = config.HysteriaItem.UpMbps, + DownMbps = config.HysteriaItem.DownMbps, + HopInterval = config.HysteriaItem.HopInterval.ToString(), + }; + break; + + case EConfigType.TUIC: + extra = extra with { CongestionControl = item.HeaderType.NullIfEmpty(), }; + item.Username = item.Id; + item.Id = item.Security; + item.Password = item.Security; + break; + + case EConfigType.HTTP: + case EConfigType.SOCKS: + item.Username = item.Security; + break; + + case EConfigType.WireGuard: + extra = extra with + { + WgPublicKey = item.PublicKey.NullIfEmpty(), + WgInterfaceAddress = item.RequestHost.NullIfEmpty(), + WgReserved = item.Path.NullIfEmpty(), + WgMtu = int.TryParse(item.ShortId, out var mtu) ? mtu : 1280 + }; + break; + } + + item.SetProtocolExtra(extra); + + item.Password = item.Id; + + item.ConfigVersion = 3; + + updateProfileItems.Add(item); + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileExtra Error: {ex}"); + } + } + + if (updateProfileItems.Count > 0) + { + try + { + var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); + return count; + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileExtraGroup update error: {ex}"); + return 0; + } + } + else + { + return 0; + } + } + + private static async Task MigrateProfileExtraGroupV2ToV3() + { + var list = await SQLiteHelper.Instance.TableAsync().ToListAsync(); + var groupItems = new ConcurrentDictionary(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!)); + + var sql = $"SELECT * FROM ProfileItem WHERE ConfigVersion < 3 AND ConfigType IN ({(int)EConfigType.PolicyGroup}, {(int)EConfigType.ProxyChain})"; + var items = await SQLiteHelper.Instance.QueryAsync(sql); + + if (items is null || items.Count == 0) + { + Logging.SaveLog("MigrateProfileExtraGroup: No items to migrate."); + return true; + } + + Logging.SaveLog($"MigrateProfileExtraGroup: Found {items.Count} group items to migrate."); + + var updateProfileItems = new List(); + + foreach (var item in items) + { + try + { + var extra = item.GetProtocolExtra(); + + extra = extra with { GroupType = nameof(item.ConfigType) }; + groupItems.TryGetValue(item.IndexId, out var groupItem); + if (groupItem != null && !groupItem.NotHasChild()) + { + extra = extra with + { + ChildItems = groupItem.ChildItems, + SubChildItems = groupItem.SubChildItems, + Filter = groupItem.Filter, + MultipleLoad = groupItem.MultipleLoad, + }; + } + + item.SetProtocolExtra(extra); + + item.ConfigVersion = 3; + updateProfileItems.Add(item); + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileExtraGroup item error [{item.IndexId}]: {ex}"); + } + } + + if (updateProfileItems.Count > 0) + { + try + { + var count = await SQLiteHelper.Instance.UpdateAllAsync(updateProfileItems); + Logging.SaveLog($"MigrateProfileExtraGroup: Successfully updated {updateProfileItems.Count} items."); + return updateProfileItems.Count == count; + } + catch (Exception ex) + { + Logging.SaveLog($"MigrateProfileExtraGroup update error: {ex}"); + return false; + } + } + + return true; + + //await ProfileGroupItemManager.Instance.ClearAll(); + } + +#pragma warning restore CS0618 + + #endregion SqliteHelper } diff --git a/v2rayN/ServiceLib/Manager/Data/ConfigDbQuery.cs b/v2rayN/ServiceLib/Manager/Data/ConfigDbQuery.cs new file mode 100644 index 00000000..d0a9a5bf --- /dev/null +++ b/v2rayN/ServiceLib/Manager/Data/ConfigDbQuery.cs @@ -0,0 +1,155 @@ +namespace ServiceLib.Manager.Data; + +public class ConfigDbQuery +{ + public static async Task?> SubItems() + { + return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); + } + + public static async Task GetSubItem(string? subid) + { + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(t => t.Id == subid); + } + + public static async Task?> ProfileItems(string subid) + { + if (subid.IsNullOrEmpty()) + { + return await SQLiteHelper.Instance.TableAsync().ToListAsync(); + } + else + { + return await SQLiteHelper.Instance.TableAsync().Where(t => t.Subid == subid).ToListAsync(); + } + } + + public static async Task?> ProfileItemIndexes(string subid) + { + return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList(); + } + + public static async Task?> ProfileModels(string subid, string filter) + { + var sql = @$"select a.IndexId + ,a.ConfigType + ,a.Remarks + ,a.Address + ,a.Port + ,a.Network + ,a.StreamSecurity + ,a.Subid + ,b.remarks as subRemarks + from ProfileItem a + left join SubItem b on a.subid = b.id + where 1=1 "; + if (subid.IsNotEmpty()) + { + sql += $" and a.subid = '{subid}'"; + } + if (filter.IsNotEmpty()) + { + if (filter.Contains('\'')) + { + filter = filter.Replace("'", ""); + } + sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter); + } + + return await SQLiteHelper.Instance.QueryAsync(sql); + } + + public static async Task GetProfileItem(string indexId) + { + if (indexId.IsNullOrEmpty()) + { + return null; + } + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); + } + + public static async Task> GetProfileItemsByIndexIds(IEnumerable indexIds) + { + var ids = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); + if (ids.Count == 0) + { + return []; + } + + if (ids.Count <= Global.SqliteMaxBatchSize) + { + return await SQLiteHelper.Instance.TableAsync() + .Where(it => ids.Contains(it.IndexId)) + .ToListAsync(); + } + + var items = new List(); + for (var size = 0; size < ids.Count; size += Global.SqliteMaxBatchSize) + { + var chunk = ids.Skip(size).Take(Global.SqliteMaxBatchSize).ToList(); + var chunkItems = await SQLiteHelper.Instance.TableAsync() + .Where(it => chunk.Contains(it.IndexId)) + .ToListAsync(); + + items.AddRange(chunkItems); + } + + return items; + } + + public static async Task> GetProfileItemsByIndexIdsAsMap(IEnumerable indexIds) + { + var items = await GetProfileItemsByIndexIds(indexIds); + return items.ToDictionary(it => it.IndexId); + } + + public static async Task> GetProfileItemsOrderedByIndexIds(IEnumerable indexIds) + { + var ids = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); + var items = await GetProfileItemsByIndexIds(ids); + var itemMap = items.ToDictionary(it => it.IndexId); + + return ids.Select(itemMap.GetValueOrDefault) + .Where(item => item != null) + .ToList(); + } + + public static async Task GetProfileItemViaRemarks(string? remarks) + { + if (remarks.IsNullOrEmpty()) + { + return null; + } + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Remarks == remarks); + } + + public static async Task?> RoutingItems() + { + return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); + } + + public static async Task GetRoutingItem(string id) + { + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Id == id); + } + + public static async Task?> DNSItems() + { + return await SQLiteHelper.Instance.TableAsync().ToListAsync(); + } + + public static async Task GetDNSItem(ECoreType eCoreType) + { + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); + } + + public static async Task?> FullConfigTemplateItem() + { + return await SQLiteHelper.Instance.TableAsync().ToListAsync(); + } + + public static async Task GetFullConfigTemplateItem(ECoreType eCoreType) + { + return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); + } +} diff --git a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs index 97cbec78..cc24bb73 100644 --- a/v2rayN/ServiceLib/Manager/GroupProfileManager.cs +++ b/v2rayN/ServiceLib/Manager/GroupProfileManager.cs @@ -52,7 +52,7 @@ public class GroupProfileManager return false; } - var childItems = await AppManager.Instance.GetProfileItemsByIndexIds(childIds); + var childItems = await ConfigDbQuery.GetProfileItemsByIndexIds(childIds); foreach (var childItem in childItems) { if (await HasCycle(childItem.IndexId, childItem.GetProtocolExtra(), visited, stack)) @@ -103,7 +103,7 @@ public class GroupProfileManager return []; } - var ordered = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childProfileIds); + var ordered = await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(childProfileIds); return ordered; } @@ -113,7 +113,7 @@ public class GroupProfileManager { return []; } - var childProfiles = await AppManager.Instance.ProfileItems(extra.SubChildItems ?? string.Empty); + var childProfiles = await ConfigDbQuery.ProfileItems(extra.SubChildItems ?? string.Empty); return childProfiles?.Where(p => p != null && diff --git a/v2rayN/ServiceLib/Manager/TaskManager.cs b/v2rayN/ServiceLib/Manager/TaskManager.cs index a548e1bc..d998b958 100644 --- a/v2rayN/ServiceLib/Manager/TaskManager.cs +++ b/v2rayN/ServiceLib/Manager/TaskManager.cs @@ -89,7 +89,7 @@ public class TaskManager private async Task UpdateTaskRunSubscription() { var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); - var lstSubs = (await AppManager.Instance.SubItems())? + var lstSubs = (await ConfigDbQuery.SubItems())? .Where(t => t.AutoUpdateInterval > 0) .Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60) .ToList(); diff --git a/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayN/ServiceLib/Services/SpeedtestService.cs index c07c7765..6de1d63b 100644 --- a/v2rayN/ServiceLib/Services/SpeedtestService.cs +++ b/v2rayN/ServiceLib/Services/SpeedtestService.cs @@ -137,7 +137,7 @@ public class SpeedtestService(Config config, Func updateF && (it.ConfigType.IsComplexType() || it.Port > 0)) .Select(it => it.IndexId) .ToList(); - var profileMap = await AppManager.Instance.GetProfileItemsByIndexIdsAsMap(ids); + var profileMap = await ConfigDbQuery.GetProfileItemsByIndexIdsAsMap(ids); for (var i = 0; i < selecteds.Count; i++) { var it = selecteds[i]; diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs index 6e98da66..07fa7cbc 100644 --- a/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayN/ServiceLib/Services/UpdateService.cs @@ -420,7 +420,7 @@ public partial class UpdateService(DownloadService downloadService, Config confi var geoSiteFiles = new List(); // Collect from routing rules - var routingItems = await AppManager.Instance.RoutingItems(); + var routingItems = await ConfigDbQuery.RoutingItems(); foreach (var routing in routingItems) { var rules = JsonUtils.Deserialize>(routing.RuleSet); @@ -432,7 +432,7 @@ public partial class UpdateService(DownloadService downloadService, Config confi } // Collect from DNS configuration - var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var dnsItem = await ConfigDbQuery.GetDNSItem(ECoreType.sing_box); if (dnsItem != null) { ExtractDnsRuleSets(dnsItem.NormalDNS, geoipFiles, geoSiteFiles); diff --git a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs index af63204f..73fc75b2 100644 --- a/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs @@ -97,14 +97,14 @@ public partial class AddGroupServerViewModel : MyReactiveObject, ICloseable _ => ResUI.TbLeastPing, }; - var subs = await AppManager.Instance.SubItems(); + var subs = await ConfigDbQuery.SubItems(); subs.Add(new SubItem()); SubItems.AddRange(subs); SelectedSubItem = SubItems.FirstOrDefault(s => s.Id == protocolExtra?.SubChildItems); Filter = protocolExtra?.Filter; var childIndexIds = Utils.String2List(protocolExtra?.ChildItems) ?? []; - var childItemList = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(childIndexIds); + var childItemList = await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(childIndexIds); ChildItemsObs.AddRange(childItemList); } diff --git a/v2rayN/ServiceLib/ViewModels/AddServer2ViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddServer2ViewModel.cs index 09c8e2e1..c3118963 100644 --- a/v2rayN/ServiceLib/ViewModels/AddServer2ViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/AddServer2ViewModel.cs @@ -89,7 +89,7 @@ public partial class AddServer2ViewModel : MyReactiveObject, ICloseable return; } - var item = await AppManager.Instance.GetProfileItem(SelectedSource.IndexId); + var item = await ConfigDbQuery.GetProfileItem(SelectedSource.IndexId); item ??= SelectedSource; item.Address = fileName; var result = item.ConfigType == EConfigType.Outbound ? await ConfigDbManager.AddCustomOutboundServer(_config, item, false) : await ConfigDbManager.AddCustomServer(_config, item, false); diff --git a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs index 459be253..37452d89 100644 --- a/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/DNSSettingViewModel.cs @@ -103,7 +103,7 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable ParallelQuery = item.ParallelQuery ?? false; ServeStale = item.ServeStale ?? false; EnableHappyEyeballs = item.EnableHappyEyeballs ?? false; - var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray); + var item1 = await ConfigDbQuery.GetDNSItem(ECoreType.Xray); RayCustomDNSEnableCompatible = item1.Enabled; UseSystemHostsCompatible = item1.UseSystemHosts; DomainStrategy4FreedomCompatible = item1?.DomainStrategy4Freedom ?? string.Empty; @@ -111,7 +111,7 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable NormalDNSCompatible = item1?.NormalDNS ?? string.Empty; TunDNSCompatible = item1?.TunDNS ?? string.Empty; - var item2 = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var item2 = await ConfigDbQuery.GetDNSItem(ECoreType.sing_box); SBCustomDNSEnableCompatible = item2.Enabled; DomainStrategy4Freedom2Compatible = item2?.DomainStrategy4Freedom ?? string.Empty; DomainDNSAddress2Compatible = item2?.DomainDNSAddress ?? string.Empty; @@ -200,7 +200,7 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable } } - var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray); + var item1 = await ConfigDbQuery.GetDNSItem(ECoreType.Xray); item1.Enabled = RayCustomDNSEnableCompatible; item1.DomainStrategy4Freedom = DomainStrategy4FreedomCompatible; item1.DomainDNSAddress = DomainDNSAddressCompatible; @@ -209,7 +209,7 @@ public partial class DNSSettingViewModel : MyReactiveObject, ICloseable item1.TunDNS = TunDNSCompatible; await ConfigDbManager.SaveDNSItems(_config, item1); - var item2 = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var item2 = await ConfigDbQuery.GetDNSItem(ECoreType.sing_box); item2.Enabled = SBCustomDNSEnableCompatible; item2.DomainStrategy4Freedom = DomainStrategy4Freedom2Compatible; item2.DomainDNSAddress = DomainDNSAddress2Compatible; diff --git a/v2rayN/ServiceLib/ViewModels/FullConfigTemplateViewModel.cs b/v2rayN/ServiceLib/ViewModels/FullConfigTemplateViewModel.cs index 5a21eba3..20e2839b 100644 --- a/v2rayN/ServiceLib/ViewModels/FullConfigTemplateViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/FullConfigTemplateViewModel.cs @@ -55,7 +55,7 @@ public partial class FullConfigTemplateViewModel : MyReactiveObject, ICloseable private async Task Init() { - var item = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.Xray); + var item = await ConfigDbQuery.GetFullConfigTemplateItem(ECoreType.Xray); if (item == null) { return; @@ -66,7 +66,7 @@ public partial class FullConfigTemplateViewModel : MyReactiveObject, ICloseable AddProxyOnly4Ray = item.AddProxyOnly ?? false; ProxyDetour4Ray = item.ProxyDetour ?? string.Empty; - var item2 = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.sing_box); + var item2 = await ConfigDbQuery.GetFullConfigTemplateItem(ECoreType.sing_box); EnableFullConfigTemplate4Singbox = item2?.Enabled ?? false; FullConfigTemplate4Singbox = item2?.Config ?? string.Empty; FullTunConfigTemplate4Singbox = item2?.TunConfig ?? string.Empty; @@ -92,7 +92,7 @@ public partial class FullConfigTemplateViewModel : MyReactiveObject, ICloseable private async Task SaveXrayConfigAsync() { - var item = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.Xray); + var item = await ConfigDbQuery.GetFullConfigTemplateItem(ECoreType.Xray); if (item == null) { return false; @@ -110,7 +110,7 @@ public partial class FullConfigTemplateViewModel : MyReactiveObject, ICloseable private async Task SaveSingboxConfigAsync() { - var item = await AppManager.Instance.GetFullConfigTemplateItem(ECoreType.sing_box); + var item = await ConfigDbQuery.GetFullConfigTemplateItem(ECoreType.sing_box); if (item == null) { return false; diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index b4edb324..3e0bfd86 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -377,7 +377,7 @@ public partial class MainWindowViewModel : MyReactiveObject else { // The activity config belongs to the current group. - var profile = await AppManager.Instance.GetProfileItem(_config.IndexId); + var profile = await ConfigDbQuery.GetProfileItem(_config.IndexId); if (profile != null && profile.Subid == _config.SubIndexId) { await Reload(); diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs index c733ad92..1b40e6e8 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs @@ -169,7 +169,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable private async Task RefreshSubscriptions() { - var subItems = await AppManager.Instance.SubItems(); + var subItems = await ConfigDbQuery.SubItems(); subItems.Insert(0, new SubItem { Remarks = ResUI.AllGroupServers }); SubItems.ReplaceRange(subItems); @@ -181,7 +181,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable private async Task?> GetProfileItemsEx(string subid, string filter) { - var lstModel = await AppManager.Instance.ProfileModels(_subIndexId, filter); + var lstModel = await ConfigDbQuery.ProfileModels(_subIndexId, filter); var lstProfileExs = await ProfileExManager.Instance.GetProfileExs(); lstModel = (from t in lstModel join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b @@ -230,7 +230,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable return null; } var indexId = SelectedProfile.IndexId; - var item = await AppManager.Instance.GetProfileItem(indexId); + var item = await ConfigDbQuery.GetProfileItem(indexId); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); @@ -245,7 +245,7 @@ public partial class ProfilesSelectViewModel : MyReactiveObject, ICloseable { return null; } - var lst = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(SelectedProfiles.Select(sp => sp?.IndexId)); + var lst = await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(SelectedProfiles.Select(sp => sp?.IndexId)); if (lst.Count == 0) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 34d84205..5aa24bee 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -382,7 +382,7 @@ public partial class ProfilesViewModel : MyReactiveObject public async Task RefreshSubscriptions() { - var subItems = await AppManager.Instance.SubItems(); + var subItems = await ConfigDbQuery.SubItems(); subItems.Insert(0, new SubItem { Remarks = ResUI.AllGroupServers }); SubItems.ReplaceRange(subItems); @@ -399,7 +399,7 @@ public partial class ProfilesViewModel : MyReactiveObject private async Task?> GetProfileItemsEx(string subid, string filter) { - var lstModel = await AppManager.Instance.ProfileModels(_config.SubIndexId, filter); + var lstModel = await ConfigDbQuery.ProfileModels(_config.SubIndexId, filter); await ConfigDbManager.SetDefaultServer(_config, lstModel); @@ -453,7 +453,7 @@ public partial class ProfilesViewModel : MyReactiveObject var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort).ToList(); if (latest) { - lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId))); + lstSelected.AddRange(await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId))); } else { @@ -469,7 +469,7 @@ public partial class ProfilesViewModel : MyReactiveObject { return; } - var item = await AppManager.Instance.GetProfileItem(SelectedProfile.IndexId); + var item = await ConfigDbQuery.GetProfileItem(SelectedProfile.IndexId); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); @@ -578,7 +578,7 @@ public partial class ProfilesViewModel : MyReactiveObject { return; } - var item = await AppManager.Instance.GetProfileItem(indexId); + var item = await ConfigDbQuery.GetProfileItem(indexId); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); @@ -594,7 +594,7 @@ public partial class ProfilesViewModel : MyReactiveObject public async Task ShareServerAsync() { - var item = await AppManager.Instance.GetProfileItem(SelectedProfile.IndexId); + var item = await ConfigDbQuery.GetProfileItem(SelectedProfile.IndexId); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); @@ -771,7 +771,7 @@ public partial class ProfilesViewModel : MyReactiveObject private async Task Export2ClientConfigAsync(bool blClipboard) { - var item = await AppManager.Instance.GetProfileItem(SelectedProfile.IndexId); + var item = await ConfigDbQuery.GetProfileItem(SelectedProfile.IndexId); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer); @@ -897,7 +897,7 @@ public partial class ProfilesViewModel : MyReactiveObject } else { - item = await AppManager.Instance.GetSubItem(_config.SubIndexId); + item = await ConfigDbQuery.GetSubItem(_config.SubIndexId); if (item is null) { return; @@ -913,7 +913,7 @@ public partial class ProfilesViewModel : MyReactiveObject private async Task DeleteSubAsync() { - var item = await AppManager.Instance.GetSubItem(_config.SubIndexId); + var item = await ConfigDbQuery.GetSubItem(_config.SubIndexId); if (item is null) { return; diff --git a/v2rayN/ServiceLib/ViewModels/RoutingSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/RoutingSettingViewModel.cs index 98eb3306..acbc1c87 100644 --- a/v2rayN/ServiceLib/ViewModels/RoutingSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/RoutingSettingViewModel.cs @@ -87,7 +87,7 @@ public partial class RoutingSettingViewModel : MyReactiveObject { var models = new List(); - var routings = await AppManager.Instance.RoutingItems(); + var routings = await ConfigDbQuery.RoutingItems(); foreach (var item in routings) { var it = new RoutingItemModel() @@ -127,7 +127,7 @@ public partial class RoutingSettingViewModel : MyReactiveObject } else { - item = await AppManager.Instance.GetRoutingItem(SelectedSource?.Id); + item = await ConfigDbQuery.GetRoutingItem(SelectedSource?.Id); if (item is null) { return; @@ -154,7 +154,7 @@ public partial class RoutingSettingViewModel : MyReactiveObject } foreach (var it in SelectedSources ?? [SelectedSource]) { - var item = await AppManager.Instance.GetRoutingItem(it?.Id); + var item = await ConfigDbQuery.GetRoutingItem(it?.Id); if (item != null) { await ConfigDbManager.RemoveRoutingItem(item); @@ -167,7 +167,7 @@ public partial class RoutingSettingViewModel : MyReactiveObject public async Task RoutingAdvancedSetDefault() { - var item = await AppManager.Instance.GetRoutingItem(SelectedSource?.Id); + var item = await ConfigDbQuery.GetRoutingItem(SelectedSource?.Id); if (item is null) { NoticeManager.Instance.Enqueue(ResUI.PleaseSelectRules); diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs index a403e822..16107290 100644 --- a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs @@ -287,7 +287,7 @@ public partial class StatusBarViewModel : MyReactiveObject private async Task RefreshServersMenu() { - var lstModel = await AppManager.Instance.ProfileModels(_config.SubIndexId, ""); + var lstModel = await ConfigDbQuery.ProfileModels(_config.SubIndexId, ""); if (lstModel?.Count > _config.GuiItem.TrayMenuServersLimit) { @@ -393,7 +393,7 @@ public partial class StatusBarViewModel : MyReactiveObject public async Task RefreshRoutingsMenu() { - var routings = await AppManager.Instance.RoutingItems(); + var routings = await ConfigDbQuery.RoutingItems(); RoutingItems.ReplaceRange(routings); @@ -407,7 +407,7 @@ public partial class StatusBarViewModel : MyReactiveObject return; } - var item = await AppManager.Instance.GetRoutingItem(SelectedRouting?.Id); + var item = await ConfigDbQuery.GetRoutingItem(SelectedRouting?.Id); if (item is null) { return; diff --git a/v2rayN/ServiceLib/ViewModels/SubSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/SubSettingViewModel.cs index e01d3e9e..3db882f6 100644 --- a/v2rayN/ServiceLib/ViewModels/SubSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/SubSettingViewModel.cs @@ -57,7 +57,7 @@ public partial class SubSettingViewModel : MyReactiveObject public async Task RefreshSubItems() { - SubItems.ReplaceRange(await AppManager.Instance.SubItems()); + SubItems.ReplaceRange(await ConfigDbQuery.SubItems()); } public async Task EditSubAsync(bool blNew) @@ -69,7 +69,7 @@ public partial class SubSettingViewModel : MyReactiveObject } else { - item = await AppManager.Instance.GetSubItem(SelectedSource?.Id); + item = await ConfigDbQuery.GetSubItem(SelectedSource?.Id); if (item is null) { return; diff --git a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.CoreUpdate.cs b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.CoreUpdate.cs index 8cb7e69a..bc3145c7 100644 --- a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.CoreUpdate.cs +++ b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.CoreUpdate.cs @@ -758,7 +758,7 @@ public sealed partial class V2rayRuntime { if (originalCoreWasRunning) { - runningProfile = await AppManager.Instance.GetProfileItem(CurrentCoreRuntime.ProfileId ?? string.Empty); + runningProfile = await ConfigDbQuery.GetProfileItem(CurrentCoreRuntime.ProfileId ?? string.Empty); if (runningProfile is null) { return new CoreUpdateApplyResult(false, false, true, "The active profile could not be loaded; the running Core was left unchanged."); @@ -1213,7 +1213,7 @@ public sealed partial class V2rayRuntime var geoipRules = new List(); var geositeRules = new List(); - var routingItems = await AppManager.Instance.RoutingItems(); + var routingItems = await ConfigDbQuery.RoutingItems(); foreach (var routing in routingItems ?? []) { var rules = JsonUtils.Deserialize>(routing.RuleSet); @@ -1224,7 +1224,7 @@ public sealed partial class V2rayRuntime } } - var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); + var dnsItem = await ConfigDbQuery.GetDNSItem(ECoreType.sing_box); if (dnsItem is not null) { ExtractDnsRuleSets(dnsItem.NormalDNS, geoipRules, geositeRules); diff --git a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Profiles.cs b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Profiles.cs index 963fdcdd..c46a907b 100644 --- a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Profiles.cs +++ b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Profiles.cs @@ -9,8 +9,8 @@ public sealed partial class V2rayRuntime { public async Task> GetProfileGroupsAsync() { - var subscriptions = await AppManager.Instance.SubItems() ?? []; - var profiles = await AppManager.Instance.ProfileItems(string.Empty) ?? []; + var subscriptions = await ConfigDbQuery.SubItems() ?? []; + var profiles = await ConfigDbQuery.ProfileItems(string.Empty) ?? []; var counts = profiles.GroupBy(item => item.Subid).ToDictionary(group => group.Key, group => group.Count()); var groups = new List { @@ -31,7 +31,7 @@ public sealed partial class V2rayRuntime public async Task SelectProfileGroupAsync(string? subscriptionId) { if (!string.IsNullOrWhiteSpace(subscriptionId) - && await AppManager.Instance.GetSubItem(subscriptionId) is null) + && await ConfigDbQuery.GetSubItem(subscriptionId) is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound); } @@ -53,7 +53,7 @@ public sealed partial class V2rayRuntime } var groupId = request.SubscriptionId ?? Config.SubIndexId ?? string.Empty; - if (!string.IsNullOrEmpty(groupId) && await AppManager.Instance.GetSubItem(groupId) is null) + if (!string.IsNullOrEmpty(groupId) && await ConfigDbQuery.GetSubItem(groupId) is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound, new { imported = 0 }); } @@ -87,7 +87,7 @@ public sealed partial class V2rayRuntime var isNew = string.IsNullOrWhiteSpace(profileId); if (!isNew) { - var existing = await AppManager.Instance.GetProfileItem(profileId!); + var existing = await ConfigDbQuery.GetProfileItem(profileId!); if (existing is null) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -106,7 +106,7 @@ public sealed partial class V2rayRuntime profile.Subid = Config.SubIndexId ?? string.Empty; profile.IsSub = false; if (!string.IsNullOrEmpty(profile.Subid) - && await AppManager.Instance.GetSubItem(profile.Subid) is null) + && await ConfigDbQuery.GetSubItem(profile.Subid) is null) { AddLog("profile", $"Rejected profile creation for missing subscription group {profile.Subid}."); return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound, @@ -126,11 +126,11 @@ public sealed partial class V2rayRuntime return OperationView.Fail("profile_group_invalid", ApiMessageKeys.ProfileInvalid); } if (!string.IsNullOrWhiteSpace(protocolExtra.SubChildItems) - && await AppManager.Instance.GetSubItem(protocolExtra.SubChildItems) is null) + && await ConfigDbQuery.GetSubItem(protocolExtra.SubChildItems) is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound); } - var children = await AppManager.Instance.GetProfileItemsByIndexIds(childIds); + var children = await ConfigDbQuery.GetProfileItemsByIndexIds(childIds); if (children.Count != childIds.Distinct(StringComparer.Ordinal).Count() || await GroupProfileManager.HasCycle(profile)) { @@ -243,7 +243,7 @@ public sealed partial class V2rayRuntime return OperationView.Fail("profile_selection_required", ApiMessageKeys.ProfileSelectRequired); } - var selected = await AppManager.Instance.GetProfileItemsByIndexIds(ids); + var selected = await ConfigDbQuery.GetProfileItemsByIndexIds(ids); if (selected.Count == 0) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -291,7 +291,7 @@ public sealed partial class V2rayRuntime public async Task CopyProfilesAsync(IEnumerable profileIds) { var ids = profileIds.Where(id => !string.IsNullOrWhiteSpace(id)).Distinct(StringComparer.Ordinal).ToArray(); - var items = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(ids); + var items = await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(ids); if (items.Count == 0) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -308,12 +308,12 @@ public sealed partial class V2rayRuntime public async Task MoveProfilesToGroupAsync(MoveProfilesRequest request) { if (!string.IsNullOrEmpty(request.SubscriptionId) - && await AppManager.Instance.GetSubItem(request.SubscriptionId) is null) + && await ConfigDbQuery.GetSubItem(request.SubscriptionId) is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound); } - var items = await AppManager.Instance.GetProfileItemsByIndexIds(request.ProfileIds); + var items = await ConfigDbQuery.GetProfileItemsByIndexIds(request.ProfileIds); if (items.Count == 0) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -381,7 +381,7 @@ public sealed partial class V2rayRuntime SubItem? subscription = null; if (!string.IsNullOrEmpty(subscriptionId)) { - subscription = await AppManager.Instance.GetSubItem(subscriptionId); + subscription = await ConfigDbQuery.GetSubItem(subscriptionId); if (subscription is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound); @@ -402,7 +402,7 @@ public sealed partial class V2rayRuntime public async Task> ExportProfileDataAsync(ProfileExportRequest request) { - var items = await AppManager.Instance.GetProfileItemsOrderedByIndexIds(request.ProfileIds); + var items = await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(request.ProfileIds); var output = new List(); if (request.IncludeShareUris) @@ -445,7 +445,7 @@ public sealed partial class V2rayRuntime public async Task GetSubscriptionShareAsync(string id) { - return (await AppManager.Instance.GetSubItem(id))?.Url; + return (await ConfigDbQuery.GetSubItem(id))?.Url; } public async Task StartSpeedTestAsync(SpeedTestRequest request, CancellationToken cancellationToken) @@ -453,8 +453,8 @@ public sealed partial class V2rayRuntime cancellationToken.ThrowIfCancellationRequested(); var action = request.Action == ESpeedActionType.FastRealping ? ESpeedActionType.Realping : request.Action; var profiles = request.ProfileIds is { Length: > 0 } - ? await AppManager.Instance.GetProfileItemsOrderedByIndexIds(request.ProfileIds) - : await AppManager.Instance.ProfileItems(Config.SubIndexId ?? string.Empty) ?? []; + ? await ConfigDbQuery.GetProfileItemsOrderedByIndexIds(request.ProfileIds) + : await ConfigDbQuery.ProfileItems(Config.SubIndexId ?? string.Empty) ?? []; if (profiles.Count == 0) { return OperationView.Fail("speedtest_profile_selection_required", ApiMessageKeys.SpeedTestSelectRequired); diff --git a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Scheduling.cs b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Scheduling.cs index e4369c44..439c94c9 100644 --- a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Scheduling.cs +++ b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Scheduling.cs @@ -114,7 +114,7 @@ public sealed partial class V2rayRuntime IReadOnlyList subscriptions; await using (var operation = await _operations.EnterOperationAsync(cancellationToken)) { - subscriptions = (await AppManager.Instance.SubItems() ?? []) + subscriptions = (await ConfigDbQuery.SubItems() ?? []) .Where(item => item.AutoUpdateInterval > 0 && now - item.UpdateTime >= item.AutoUpdateInterval * 60L) .ToArray(); diff --git a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Settings.cs b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Settings.cs index d6207e5f..3832c7f4 100644 --- a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Settings.cs +++ b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.Settings.cs @@ -528,7 +528,7 @@ public sealed partial class V2rayRuntime } public async Task> GetDnsProfilesAsync() => - (await AppManager.Instance.DNSItems() ?? []) + (await ConfigDbQuery.DNSItems() ?? []) .Select(ToDnsProfileView) .ToArray(); @@ -550,7 +550,7 @@ public sealed partial class V2rayRuntime var result = await _mutations.RunAsync(async () => { - var current = await AppManager.Instance.GetDNSItem(coreType); + var current = await ConfigDbQuery.GetDNSItem(coreType); if (current is null) { return (Result: -2, Changed: false); @@ -622,7 +622,7 @@ public sealed partial class V2rayRuntime return json is not null && json["servers"] is not null; } - public async Task> GetRoutingProfilesAsync() => await AppManager.Instance.RoutingItems() ?? []; + public async Task> GetRoutingProfilesAsync() => await ConfigDbQuery.RoutingItems() ?? []; public async Task SaveRoutingProfileAsync(RoutingItem input, string? routingId = null) { @@ -656,12 +656,12 @@ public sealed partial class V2rayRuntime item = input; item.Id = string.Empty; item.IsActive = false; - var existing = await AppManager.Instance.RoutingItems() ?? []; + var existing = await ConfigDbQuery.RoutingItems() ?? []; item.Sort = item.Sort > 0 ? item.Sort : (existing.MaxBy(route => route.Sort)?.Sort ?? 0) + 1; } else { - var existingItem = await AppManager.Instance.GetRoutingItem(routingId); + var existingItem = await ConfigDbQuery.GetRoutingItem(routingId); if (existingItem is null) { return (Result: -2, Item: null, Changed: false); @@ -723,7 +723,7 @@ public sealed partial class V2rayRuntime var removed = await _mutations.RunAsync(async () => { - var item = await AppManager.Instance.GetRoutingItem(id); + var item = await ConfigDbQuery.GetRoutingItem(id); if (item is null) { return (Removed: false, AffectsCore: false); @@ -731,7 +731,7 @@ public sealed partial class V2rayRuntime await ConfigDbManager.RemoveRoutingItem(item); if (item.IsActive) { - var remaining = await AppManager.Instance.RoutingItems() ?? []; + var remaining = await ConfigDbQuery.RoutingItems() ?? []; var fallback = remaining.FirstOrDefault(); if (fallback is not null) { @@ -766,7 +766,7 @@ public sealed partial class V2rayRuntime var result = await _mutations.RunAsync(async () => { - var item = await AppManager.Instance.GetRoutingItem(id); + var item = await ConfigDbQuery.GetRoutingItem(id); if (item is null) { return (Result: -2, Changed: false); @@ -788,7 +788,7 @@ public sealed partial class V2rayRuntime public async Task> GetRoutingRulesAsync(string routingId) { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); return JsonUtils.Deserialize>(item?.RuleSet ?? "[]") ?? []; } @@ -801,7 +801,7 @@ public sealed partial class V2rayRuntime } var items = rules.ToArray(); - var before = await AppManager.Instance.GetRoutingItem(routingId); + var before = await ConfigDbQuery.GetRoutingItem(routingId); var changed = before is not null && before.IsActive && before.RuleSet != JsonUtils.Serialize(items, false); var saved = await _mutations.RunAsync(() => SaveRoutingRulesLockedAsync(routingId, items)); @@ -818,7 +818,7 @@ public sealed partial class V2rayRuntime private static async Task SaveRoutingRulesLockedAsync(string routingId, IReadOnlyList rules) { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); if (item is null) { return -2; @@ -828,7 +828,7 @@ public sealed partial class V2rayRuntime private async Task GetActiveRoutingSignatureAsync() { - var active = (await AppManager.Instance.RoutingItems() ?? []).FirstOrDefault(item => item.IsActive); + var active = (await ConfigDbQuery.RoutingItems() ?? []).FirstOrDefault(item => item.IsActive); return active is null ? string.Empty : System.Text.Json.JsonSerializer.Serialize(new @@ -855,13 +855,13 @@ public sealed partial class V2rayRuntime return applyFailure; } - var activeBefore = await AppManager.Instance.GetRoutingItem(routingId); + var activeBefore = await ConfigDbQuery.GetRoutingItem(routingId); var beforeRuleSet = activeBefore?.RuleSet; var saved = await _mutations.RunAsync(async () => { if (request.Append) { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); if (item is null) { return -2; @@ -880,14 +880,14 @@ public sealed partial class V2rayRuntime { return OperationView.Fail("routing_rules_save_failed", ApiMessageKeys.RoutingSaveFailed); } - var activeAfter = await AppManager.Instance.GetRoutingItem(routingId); + var activeAfter = await ConfigDbQuery.GetRoutingItem(routingId); var changed = activeBefore?.IsActive == true && activeAfter?.RuleSet != beforeRuleSet; return await CompleteCoreAffectingChangeAsync("routing-rules", changed, applyContext, data: new { routingId }); } public async Task ImportRoutingRulesFromUrlAsync(string routingId, bool append, CancellationToken cancellationToken) { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); if (item is null) { return OperationView.Fail("routing_profile_not_found", ApiMessageKeys.RoutingProfileNotFound); @@ -916,10 +916,10 @@ public sealed partial class V2rayRuntime return applyFailure; } - var routeWasActive = (await AppManager.Instance.GetRoutingItem(routingId))?.IsActive == true; + var routeWasActive = (await ConfigDbQuery.GetRoutingItem(routingId))?.IsActive == true; var result = await _mutations.RunAsync(async () => { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); if (item is null) { return -2; @@ -957,10 +957,10 @@ public sealed partial class V2rayRuntime return applyFailure; } - var routeWasActive = (await AppManager.Instance.GetRoutingItem(routingId))?.IsActive == true; + var routeWasActive = (await ConfigDbQuery.GetRoutingItem(routingId))?.IsActive == true; var result = await _mutations.RunAsync(async () => { - var item = await AppManager.Instance.GetRoutingItem(routingId); + var item = await ConfigDbQuery.GetRoutingItem(routingId); if (item is null) { return -2; @@ -1003,7 +1003,7 @@ public sealed partial class V2rayRuntime } public async Task> GetFullConfigTemplatesAsync() => - (await AppManager.Instance.FullConfigTemplateItem() ?? []) + (await ConfigDbQuery.FullConfigTemplateItem() ?? []) .Select(ToCoreConfigTemplateView) .ToArray(); @@ -1033,7 +1033,7 @@ public sealed partial class V2rayRuntime return applyFailure; } - var existingBefore = await AppManager.Instance.GetFullConfigTemplateItem(coreType); + var existingBefore = await ConfigDbQuery.GetFullConfigTemplateItem(coreType); var changed = existingBefore is not null && (existingBefore.Remarks != (input.Remarks ?? existingBefore.Remarks) || existingBefore.Enabled != input.Enabled @@ -1042,7 +1042,7 @@ public sealed partial class V2rayRuntime || existingBefore.ProxyDetour != input.ProxyDetour); var result = await _mutations.RunAsync(async () => { - var current = await AppManager.Instance.GetFullConfigTemplateItem(coreType); + var current = await ConfigDbQuery.GetFullConfigTemplateItem(coreType); if (current is null) { return -2; @@ -1074,8 +1074,8 @@ public sealed partial class V2rayRuntime await _regionalPresetGate.WaitAsync(cancellationToken); try { - var existingDnsItems = await AppManager.Instance.DNSItems() ?? []; - var existingRoutingItems = await AppManager.Instance.RoutingItems() ?? []; + var existingDnsItems = await ConfigDbQuery.DNSItems() ?? []; + var existingRoutingItems = await ConfigDbQuery.RoutingItems() ?? []; var proxy = preset == EPresetType.Default ? null : await GetRegionalPresetProxyAsync(cancellationToken); @@ -1185,7 +1185,7 @@ public sealed partial class V2rayRuntime foreach (var itemId in stage.Routing.RemoveItemIds ?? []) { - var item = await AppManager.Instance.GetRoutingItem(itemId); + var item = await ConfigDbQuery.GetRoutingItem(itemId); if (item is not null) { await ConfigDbManager.RemoveRoutingItem(item); @@ -1197,7 +1197,7 @@ public sealed partial class V2rayRuntime Config.RoutingBasicItem.RoutingIndexId = string.Empty; } - var currentRoutes = await AppManager.Instance.RoutingItems() ?? []; + var currentRoutes = await ConfigDbQuery.RoutingItems() ?? []; var hasVersion = stage.Routing.TemplateVersion is { Length: > 0 } version && currentRoutes.Any(item => item.Remarks?.StartsWith(version, StringComparison.Ordinal) == true); var builtinFallbackAlreadyInitialized = stage.Routing.IsBuiltinFallback && currentRoutes.Count > 0; @@ -1589,9 +1589,9 @@ public sealed partial class V2rayRuntime new { runtimeState = oldRuntime.State.ToString().ToLowerInvariant(), processIds = GetActiveCoreProcessIds() }), _ => null, }; - var oldRoutingItems = failure is null ? await AppManager.Instance.RoutingItems() ?? [] : []; - var oldDnsItems = failure is null ? await AppManager.Instance.DNSItems() ?? [] : []; - var oldFullConfigTemplates = failure is null ? await AppManager.Instance.FullConfigTemplateItem() ?? [] : []; + var oldRoutingItems = failure is null ? await ConfigDbQuery.RoutingItems() ?? [] : []; + var oldDnsItems = failure is null ? await ConfigDbQuery.DNSItems() ?? [] : []; + var oldFullConfigTemplates = failure is null ? await ConfigDbQuery.FullConfigTemplateItem() ?? [] : []; return new CoreSettingsApplyContext(_coreGate, oldConfig, oldRuntime, hasActiveChild, oldRoutingItems.ToArray(), oldDnsItems.ToArray(), oldFullConfigTemplates.ToArray(), failure); } @@ -1702,7 +1702,7 @@ public sealed partial class V2rayRuntime await CoreManager.Instance.Init(Config, OnCoreMessageAsync); var oldProfileId = context.OldRuntime.ProfileId ?? Config.IndexId; - var oldProfile = await AppManager.Instance.GetProfileItem(oldProfileId) + var oldProfile = await ConfigDbQuery.GetProfileItem(oldProfileId) ?? throw new InvalidOperationException($"The previous Core profile {oldProfileId} no longer exists."); var restored = await StartCoreLockedAsync(oldProfile, CancellationToken.None); if (!restored.Success) diff --git a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.cs b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.cs index 707ca153..e051333a 100644 --- a/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.cs +++ b/v2rayN/v2rayN.WebAPI/Services/V2rayRuntime.cs @@ -250,7 +250,7 @@ public sealed partial class V2rayRuntime( await ConfigDbManager.InitBuiltinDNS(Config); await BuiltinDnsProfileBootstrap.EnsureAsync( Config, - async () => await AppManager.Instance.DNSItems() ?? [], + async () => await ConfigDbQuery.DNSItems() ?? [], ConfigDbManager.SaveDNSItems); await ConfigDbManager.InitBuiltinFullConfigTemplate(Config); // Keep startup aligned with Desktop's StatusBarViewModel. In particular, @@ -258,7 +258,7 @@ public sealed partial class V2rayRuntime( // run even when a restored Desktop database already has routing rows. await ConfigDbManager.InitBuiltinRouting(Config); _ = await ConfigDbManager.GetDefaultRouting(Config); - var restoredSubscriptions = await AppManager.Instance.SubItems() ?? []; + var restoredSubscriptions = await ConfigDbQuery.SubItems() ?? []; var normalizedSubIndexId = NormalizeSelectedSubscriptionId( Config.SubIndexId, restoredSubscriptions.Select(item => item.Id).ToArray()); @@ -303,7 +303,7 @@ public sealed partial class V2rayRuntime( startupRuntimeIntent, selectedProfileId, defaultProfile?.IndexId, - async (profileId, _) => await AppManager.Instance.GetProfileItem(profileId) is not null, + async (profileId, _) => await ConfigDbQuery.GetProfileItem(profileId) is not null, StartCoreAsync, message => AddLog(restoreState is not null ? "restore" : "update", message), cancellationToken); @@ -425,7 +425,7 @@ public sealed partial class V2rayRuntime( public async Task> GetSubscriptionsAsync() { - var items = await AppManager.Instance.SubItems() ?? []; + var items = await ConfigDbQuery.SubItems() ?? []; return items.Select(ToSubscriptionView).ToArray(); } @@ -443,7 +443,7 @@ public sealed partial class V2rayRuntime( return new(false, "subscription_save_failed", ApiMessageKeys.SubscriptionSaveFailed, null); } - var saved = await AppManager.Instance.GetSubItem(item.Id); + var saved = await ConfigDbQuery.GetSubItem(item.Id); return saved is null ? new(false, "subscription_save_failed", ApiMessageKeys.SubscriptionSaveFailed, null) : new(true, "ok", ApiMessageKeys.SubscriptionAdded, ToSubscriptionView(saved)); @@ -458,7 +458,7 @@ public sealed partial class V2rayRuntime( return await _mutations.RunAsync(async () => { - var existing = await AppManager.Instance.GetSubItem(id); + var existing = await ConfigDbQuery.GetSubItem(id); if (existing is null) { return new SubscriptionMutationResult(false, "subscription_not_found", ApiMessageKeys.SubscriptionNotFound, null); @@ -472,7 +472,7 @@ public sealed partial class V2rayRuntime( return new SubscriptionMutationResult(false, "subscription_save_failed", ApiMessageKeys.SubscriptionSaveFailed, null); } - var saved = await AppManager.Instance.GetSubItem(id); + var saved = await ConfigDbQuery.GetSubItem(id); return saved is not null ? new SubscriptionMutationResult(true, "ok", ApiMessageKeys.SubscriptionSaved, ToSubscriptionView(saved)) : new SubscriptionMutationResult(false, "subscription_save_failed", ApiMessageKeys.SubscriptionSaveFailed, null); @@ -481,13 +481,13 @@ public sealed partial class V2rayRuntime( public async Task DeleteSubscriptionAsync(string id) { - var subscription = await AppManager.Instance.GetSubItem(id); + var subscription = await ConfigDbQuery.GetSubItem(id); if (subscription is null) { return OperationView.Fail("subscription_not_found", ApiMessageKeys.SubscriptionNotFound); } - var selectedProfile = await AppManager.Instance.GetProfileItem(Config.IndexId); + var selectedProfile = await ConfigDbQuery.GetProfileItem(Config.IndexId); var removesCurrentProfile = selectedProfile?.Subid == id; if (removesCurrentProfile) { @@ -582,10 +582,10 @@ public sealed partial class V2rayRuntime( public async Task> GetProfilesAsync(string? subscriptionId, string? filter) { var groupId = subscriptionId ?? Config.SubIndexId ?? string.Empty; - var profiles = await AppManager.Instance.ProfileItems(groupId) ?? []; - var profileModels = await AppManager.Instance.ProfileModels(groupId, string.Empty) ?? []; + var profiles = await ConfigDbQuery.ProfileItems(groupId) ?? []; + var profileModels = await ConfigDbQuery.ProfileModels(groupId, string.Empty) ?? []; var modelMap = profileModels.ToDictionary(item => item.IndexId); - var subscriptions = (await AppManager.Instance.SubItems() ?? []).ToDictionary(item => item.Id, item => item.Remarks); + var subscriptions = (await ConfigDbQuery.SubItems() ?? []).ToDictionary(item => item.Id, item => item.Remarks); var extensions = await ProfileExManager.Instance.GetProfileExs(); var extensionMap = extensions.ToDictionary(item => item.IndexId); var statistics = (Config.GuiItem.EnableStatistics ? StatisticsManager.Instance.ServerStat : null) ?? []; @@ -630,13 +630,13 @@ public sealed partial class V2rayRuntime( } public async Task GetProfileDetailsAsync(string profileId) => - await AppManager.Instance.GetProfileItem(profileId); + await ConfigDbQuery.GetProfileItem(profileId); public async Task GetStatusAsync() { - var selectedProfile = await AppManager.Instance.GetProfileItem(Config.IndexId); - var profileItems = await AppManager.Instance.ProfileItems(string.Empty) ?? []; - var subscriptions = await AppManager.Instance.SubItems() ?? []; + var selectedProfile = await ConfigDbQuery.GetProfileItem(Config.IndexId); + var profileItems = await ConfigDbQuery.ProfileItems(string.Empty) ?? []; + var subscriptions = await ConfigDbQuery.SubItems() ?? []; var snapshot = CurrentCoreRuntime; var processIds = GetActiveCoreProcessIds(); var listenerDefinitions = snapshot.ProxyPort.HasValue && snapshot.State != CoreRuntimeState.Stopped @@ -674,7 +674,7 @@ public sealed partial class V2rayRuntime( var runningProfile = string.IsNullOrEmpty(snapshot.ProfileId) ? null - : await AppManager.Instance.GetProfileItem(snapshot.ProfileId); + : await ConfigDbQuery.GetProfileItem(snapshot.ProfileId); var configuredProxyPort = Config.Inbound.FirstOrDefault()?.LocalPort; return new StatusView( coreRunning, @@ -715,7 +715,7 @@ public sealed partial class V2rayRuntime( public async Task SelectProfileAsync(string profileId, CancellationToken cancellationToken) { - var profile = await AppManager.Instance.GetProfileItem(profileId); + var profile = await ConfigDbQuery.GetProfileItem(profileId); if (profile is null) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -729,7 +729,7 @@ public sealed partial class V2rayRuntime( ProfileItem? profile = null; if (!string.IsNullOrWhiteSpace(profileId)) { - profile = await AppManager.Instance.GetProfileItem(profileId); + profile = await ConfigDbQuery.GetProfileItem(profileId); if (profile is null) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound); @@ -1055,7 +1055,7 @@ public sealed partial class V2rayRuntime( new { runtimeState = previous.State.ToString(), processIds = GetActiveCoreProcessIds() }); } - var profile = await AppManager.Instance.GetProfileItem(previous.ProfileId); + var profile = await ConfigDbQuery.GetProfileItem(previous.ProfileId); if (profile is null) { return OperationView.Fail("profile_not_found", ApiMessageKeys.ProfileNotFound, @@ -1105,7 +1105,7 @@ public sealed partial class V2rayRuntime( public async Task StartLatencyTestAsync(string profileId) { - var profile = await AppManager.Instance.GetProfileItem(profileId); + var profile = await ConfigDbQuery.GetProfileItem(profileId); if (profile is null || profile.IsComplex() || profile.Port <= 0) { return OperationView.Fail("speedtest_invalid_profile", ApiMessageKeys.SpeedTestInvalidProfile); @@ -1174,7 +1174,7 @@ public sealed partial class V2rayRuntime( var updateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); if (subscriptionId.Length > 0) { - var item = await AppManager.Instance.GetSubItem(subscriptionId); + var item = await ConfigDbQuery.GetSubItem(subscriptionId); if (item is not null) { item.UpdateTime = updateTime; @@ -1186,7 +1186,7 @@ public sealed partial class V2rayRuntime( return; } - foreach (var item in await AppManager.Instance.SubItems() ?? []) + foreach (var item in await ConfigDbQuery.SubItems() ?? []) { if (item.Enabled) { diff --git a/v2rayN/v2rayN.WebAPI/Tests/SubscriptionCreationTests.cs b/v2rayN/v2rayN.WebAPI/Tests/SubscriptionCreationTests.cs index 8fe8325f..d8081ca5 100644 --- a/v2rayN/v2rayN.WebAPI/Tests/SubscriptionCreationTests.cs +++ b/v2rayN/v2rayN.WebAPI/Tests/SubscriptionCreationTests.cs @@ -29,7 +29,7 @@ public class SubscriptionCreationTests if (result.Data is not null) { - saved = await manager.GetSubItem(result.Data.Id); + saved = await ConfigDbQuery.GetSubItem(result.Data.Id); } await result.Success.Should().BeTrue(); @@ -48,7 +48,7 @@ public class SubscriptionCreationTests await updateResult.Success.Should().BeTrue(); await updateResult.Data!.Url.Should().BeEqualTo(string.Empty); - saved = await manager.GetSubItem(result.Data.Id); + saved = await ConfigDbQuery.GetSubItem(result.Data.Id); await (saved is not null).Should().BeTrue(); await saved!.Remarks.Should().BeEqualTo("自建(已编辑)"); await saved.Url.Should().BeEqualTo(string.Empty);