mirror of
https://github.com/hiddify/hiddify-next.git
synced 2026-06-05 21:05:07 +08:00
fix: temporarily patch Riverpod lazy build-phase collision on connection status changes
Temporary hotfix to resolve fatal 'setState() called during build' errors caused by lazy evaluation of dirty provider dependency chains during high-frequency status transitions. - Establishes eager evaluation by listening to `activeProxyNotifierProvider` at the root container level during bootstrap to resolve dirty state flushes in microtasks. - Refactors `serviceRunningProvider` and all downstream dependent stream/future notifiers to execute synchronously to prevent build-phase timing hops. - Defers secondary state updates using `Future.microtask()`. Note: This is a temporary architectural patch to bypass Riverpod's lazy widget evaluation mechanics under high-frequency stream updates. A full core communication redesign is recommended for future maintenance to address this natively.
This commit is contained in:
parent
3152857060
commit
116c79e797
@ -22,6 +22,7 @@ import 'package:hiddify/features/chain/notifier/chain_profile_notifier.dart';
|
||||
import 'package:hiddify/features/log/data/log_data_providers.dart';
|
||||
import 'package:hiddify/features/profile/data/profile_data_providers.dart';
|
||||
import 'package:hiddify/features/profile/notifier/active_profile_notifier.dart';
|
||||
import 'package:hiddify/features/proxy/active/active_proxy_notifier.dart';
|
||||
import 'package:hiddify/features/system_tray/notifier/system_tray_notifier.dart';
|
||||
import 'package:hiddify/features/window/notifier/window_notifier.dart';
|
||||
import 'package:hiddify/hiddifycore/hiddify_core_service_provider.dart';
|
||||
@ -98,6 +99,10 @@ Future<void> lazyBootstrap(WidgetsBinding widgetsBinding, Environment env) async
|
||||
);
|
||||
await _init("hiddify-core", () => container.read(hiddifyCoreServiceProvider).init());
|
||||
|
||||
// Eagerly listen to activeProxyNotifierProvider to force synchronous evaluation in microtasks,
|
||||
// avoiding lazy build-phase flushes and sibling dependency collisions on the Home page.
|
||||
container.listen(activeProxyNotifierProvider, (previous, next) {});
|
||||
|
||||
if (!kIsWeb) {
|
||||
// await _safeInit(
|
||||
// "deep link service",
|
||||
|
||||
@ -57,7 +57,7 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
||||
|
||||
yield* _connectionRepo.watchConnectionStatus().doOnData((event) {
|
||||
if (event case Disconnected(connectionFailure: final _?) when PlatformUtils.isDesktop) {
|
||||
ref.read(Preferences.startedByUser.notifier).update(false);
|
||||
Future.microtask(() => ref.read(Preferences.startedByUser.notifier).update(false));
|
||||
}
|
||||
loggy.info("connection status: ${event.format()}");
|
||||
});
|
||||
@ -170,11 +170,9 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<bool> serviceRunning(Ref ref) async {
|
||||
bool serviceRunning(Ref ref) {
|
||||
// ref.watch(coreRestartSignalProvider);
|
||||
return await ref
|
||||
.watch(connectionNotifierProvider.selectAsync((data) => data.isConnected))
|
||||
.onError((error, stackTrace) => false);
|
||||
return ref.watch(connectionNotifierProvider).valueOrNull?.isConnected ?? false;
|
||||
}
|
||||
|
||||
class SingleCall {
|
||||
|
||||
@ -6,10 +6,11 @@ import 'package:hiddify/core/preferences/general_preferences.dart';
|
||||
import 'package:hiddify/core/utils/throttler.dart';
|
||||
import 'package:hiddify/features/connection/notifier/connection_notifier.dart';
|
||||
import 'package:hiddify/features/proxy/data/proxy_data_providers.dart';
|
||||
import 'package:hiddify/features/proxy/data/proxy_repository.dart';
|
||||
import 'package:hiddify/features/proxy/model/ip_info_entity.dart' as oldipinfo;
|
||||
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||
import 'package:hiddify/hiddifycore/generated/v2/hcore/hcore.pb.dart';
|
||||
import 'package:hiddify/hiddifycore/init_signal.dart';
|
||||
|
||||
import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@ -32,7 +33,7 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
||||
ref.listen(serviceRunningProvider, (_, next) => _idle = false);
|
||||
|
||||
final autoCheck = ref.watch(Preferences.autoCheckIp);
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||
// loggy.debug(
|
||||
// "idle? [$_idle], forced? [$_forceCheck], connected? [$serviceRunning]",
|
||||
// );
|
||||
@ -74,20 +75,20 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
||||
@Riverpod(keepAlive: true)
|
||||
class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger {
|
||||
@override
|
||||
Stream<OutboundInfo> build() async* {
|
||||
Stream<OutboundInfo> build() {
|
||||
// ref.disposeDelay(const Duration(seconds: 20));
|
||||
ref.watch(coreRestartSignalProvider);
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||
if (!serviceRunning) {
|
||||
throw const ServiceNotRunning();
|
||||
return Stream.error(const ServiceNotRunning());
|
||||
}
|
||||
final proxyprovider = ref.watch(proxyRepositoryProvider);
|
||||
yield* proxyprovider
|
||||
return _proxyRepo
|
||||
.watchActiveProxies()
|
||||
.map((event) => event.getOrElse((l) => List<OutboundGroup>.empty()))
|
||||
.map((event) => event.firstOrNull?.items.first ?? OutboundInfo());
|
||||
}
|
||||
|
||||
ProxyRepository get _proxyRepo => ref.read(proxyRepositoryProvider);
|
||||
|
||||
final _urlTestThrottler = Throttler(const Duration(seconds: 1));
|
||||
|
||||
Future<void> urlTest(String? groupTag_) async {
|
||||
|
||||
@ -10,7 +10,7 @@ import 'package:hiddify/features/connection/notifier/connection_notifier.dart';
|
||||
import 'package:hiddify/features/proxy/data/proxy_data_providers.dart';
|
||||
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||
import 'package:hiddify/hiddifycore/generated/v2/hcore/hcore.pb.dart';
|
||||
import 'package:hiddify/hiddifycore/init_signal.dart';
|
||||
|
||||
import 'package:hiddify/utils/riverpod_utils.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@ -57,12 +57,11 @@ class ProxiesSortNotifier extends _$ProxiesSortNotifier with AppLogger {
|
||||
@riverpod
|
||||
class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
|
||||
@override
|
||||
Stream<OutboundGroup?> build() async* {
|
||||
Stream<OutboundGroup?> build() {
|
||||
ref.disposeDelay(const Duration(seconds: 15));
|
||||
ref.watch(coreRestartSignalProvider);
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||
if (!serviceRunning) {
|
||||
throw const ServiceNotRunning();
|
||||
return Stream.error(const ServiceNotRunning());
|
||||
}
|
||||
final sortBy = ref.watch(proxiesSortNotifierProvider);
|
||||
// yield* ref
|
||||
@ -82,7 +81,7 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
|
||||
// ),
|
||||
// )
|
||||
// .asyncMap((proxies) async => _sortOutbounds(proxies, sortBy));
|
||||
yield* ref
|
||||
return ref
|
||||
.watch(proxyRepositoryProvider)
|
||||
.watchProxies()
|
||||
.map(
|
||||
|
||||
@ -21,7 +21,7 @@ part 'config_option_notifier.g.dart';
|
||||
class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger {
|
||||
@override
|
||||
Future<bool> build() async {
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||
final serviceSingboxOptions = ref.read(connectionRepositoryProvider).configOptionsSnapshot;
|
||||
|
||||
ref.listen(ConfigOptions.singboxConfigOptions, (previous, next) async {
|
||||
|
||||
@ -10,16 +10,16 @@ part 'stats_notifier.g.dart';
|
||||
@riverpod
|
||||
class StatsNotifier extends _$StatsNotifier with AppLogger {
|
||||
@override
|
||||
Stream<SystemInfo> build() async* {
|
||||
Stream<SystemInfo> build() {
|
||||
ref.disposeDelay(const Duration(seconds: 10));
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||
if (serviceRunning) {
|
||||
yield* ref
|
||||
return ref
|
||||
.watch(statsRepositoryProvider)
|
||||
.watchStats()
|
||||
.map((event) => event.getOrElse((_) => SystemInfo.create()));
|
||||
} else {
|
||||
yield* Stream.value(SystemInfo.create());
|
||||
return Stream.value(SystemInfo.create());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user