Files
FlClash/lib/providers/state/profile.dart
T
chen08209 5984c161c5 fix(core): keep very large profiles from crashing the app
Changelog: Large profiles no longer crash; downloads trust core CAs
2026-10-16 22:54:53 +08:00

124 lines
4.0 KiB
Dart

part of '../state.dart';
@riverpod
ProfilesState profilesState(Ref ref) {
final currentProfileId = ref.watch(currentProfileIdProvider);
final profiles = ref.watch(profilesProvider);
return ProfilesState(profiles: profiles, currentProfileId: currentProfileId);
}
@riverpod
Profile? currentProfile(Ref ref) {
final profileId = ref.watch(currentProfileIdProvider);
return ref.watch(
profilesProvider.select((state) => state.getProfile(profileId)),
);
}
@riverpod
Profile? profile(Ref ref, int? profileId) {
return ref.watch(
profilesProvider.select((state) => state.getProfile(profileId)),
);
}
@riverpod
ExtendType extendType(Ref ref, int? profileId) {
return ref.watch(
profileProvider(
profileId,
).select((state) => state?.extendType ?? ExtendType.standard),
);
}
@riverpod
Future<ClashConfig> clashConfig(Ref ref, int profileId) async {
final type = ref.read(profileProvider(profileId))?.type;
if (type == ProfileType.custom) {
return const ClashConfig();
}
final outbounds = await ref
.read(coreHandlerProvider)
.getProfileOutbounds(profileId);
return clashConfigTask(outbounds);
}
@riverpod
Future<SetupState> setupState(Ref ref, int? profileId) async {
final profile = ref.watch(profileProvider(profileId));
final scriptId = profile?.scriptId;
final profileLastUpdateDate = profile?.lastUpdateDate?.millisecondsSinceEpoch;
final profileType = profile?.type ?? ProfileType.file;
final extendType = profile?.extendType ?? ExtendType.standard;
final overrides = profileType == ProfileType.custom
? profile?.overrides ?? const ProfileOverrides()
: ref.watch(
patchClashConfigProvider.select(
(state) => ProfileOverrides(
dns: state.dns,
dnsOverrideKeys: state.dnsOverrideKeys.intersection(
DnsOverrideKey.normalProfileKeys,
),
),
),
);
final allProfileProviders = ref.watch(profileProvidersProvider);
List<ProxyGroup> proxyGroups = [];
List<Rule> rules = [];
List<Rule> addedRules = [];
List<ClashProvider> clashProviders = [];
Map<String, int> profileProviders = const {};
List<CustomProxy> appProxies = [];
Map<int, String> proxyDialers = const {};
Script? script;
if (profileId != null) {
if (profileType == ProfileType.custom) {
rules = await database.rulesDao.queryProfileRules(profileId).get();
proxyGroups = await database.proxyGroupsDao.query(profileId).get();
clashProviders = await database.clashProvidersDao.query().get();
profileProviders = allProfileProviders;
appProxies = await database.customProxiesDao.query().get();
proxyDialers = {
for (final dialer
in await database.proxyDialersDao.query(profileId).get())
dialer.proxyId: dialer.target,
};
} else if (extendType == ExtendType.standard) {
addedRules = await database.rulesDao.queryAddedRules(profileId).get();
} else if (extendType == ExtendType.script) {
script = scriptId == null
? null
: await database.scriptsDao.get(scriptId).getSingleOrNull();
}
}
return SetupState(
clashProviders: clashProviders,
profileProviders: profileProviders,
appProxies: appProxies,
proxyDialers: proxyDialers,
rules: rules,
proxyGroups: proxyGroups,
profileId: profileId,
profileLastUpdateDate: profileLastUpdateDate,
profileType: profileType,
extendType: extendType,
addedRules: addedRules,
script: script,
overrides: overrides,
matchTarget:
profileType != ProfileType.custom && extendType == ExtendType.standard
? profile?.matchTarget
: null,
);
}
/// Subscription profiles double as proxy providers for custom profiles.
@riverpod
Map<String, int> profileProviders(Ref ref) {
final profiles = ref.watch(profilesProvider);
return {
for (final profile in profiles)
if (profile.type != ProfileType.custom) profile.realLabel: profile.id,
};
}