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/log/data/log_data_providers.dart';
|
||||||
import 'package:hiddify/features/profile/data/profile_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/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/system_tray/notifier/system_tray_notifier.dart';
|
||||||
import 'package:hiddify/features/window/notifier/window_notifier.dart';
|
import 'package:hiddify/features/window/notifier/window_notifier.dart';
|
||||||
import 'package:hiddify/hiddifycore/hiddify_core_service_provider.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());
|
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) {
|
if (!kIsWeb) {
|
||||||
// await _safeInit(
|
// await _safeInit(
|
||||||
// "deep link service",
|
// "deep link service",
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
|||||||
|
|
||||||
yield* _connectionRepo.watchConnectionStatus().doOnData((event) {
|
yield* _connectionRepo.watchConnectionStatus().doOnData((event) {
|
||||||
if (event case Disconnected(connectionFailure: final _?) when PlatformUtils.isDesktop) {
|
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()}");
|
loggy.info("connection status: ${event.format()}");
|
||||||
});
|
});
|
||||||
@ -170,11 +170,9 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
Future<bool> serviceRunning(Ref ref) async {
|
bool serviceRunning(Ref ref) {
|
||||||
// ref.watch(coreRestartSignalProvider);
|
// ref.watch(coreRestartSignalProvider);
|
||||||
return await ref
|
return ref.watch(connectionNotifierProvider).valueOrNull?.isConnected ?? false;
|
||||||
.watch(connectionNotifierProvider.selectAsync((data) => data.isConnected))
|
|
||||||
.onError((error, stackTrace) => false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SingleCall {
|
class SingleCall {
|
||||||
|
|||||||
@ -6,10 +6,11 @@ import 'package:hiddify/core/preferences/general_preferences.dart';
|
|||||||
import 'package:hiddify/core/utils/throttler.dart';
|
import 'package:hiddify/core/utils/throttler.dart';
|
||||||
import 'package:hiddify/features/connection/notifier/connection_notifier.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_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/ip_info_entity.dart' as oldipinfo;
|
||||||
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||||
import 'package:hiddify/hiddifycore/generated/v2/hcore/hcore.pb.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/riverpod_utils.dart';
|
||||||
import 'package:hiddify/utils/utils.dart';
|
import 'package:hiddify/utils/utils.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
@ -32,7 +33,7 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
|||||||
ref.listen(serviceRunningProvider, (_, next) => _idle = false);
|
ref.listen(serviceRunningProvider, (_, next) => _idle = false);
|
||||||
|
|
||||||
final autoCheck = ref.watch(Preferences.autoCheckIp);
|
final autoCheck = ref.watch(Preferences.autoCheckIp);
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||||
// loggy.debug(
|
// loggy.debug(
|
||||||
// "idle? [$_idle], forced? [$_forceCheck], connected? [$serviceRunning]",
|
// "idle? [$_idle], forced? [$_forceCheck], connected? [$serviceRunning]",
|
||||||
// );
|
// );
|
||||||
@ -74,20 +75,20 @@ class IpInfoNotifier extends _$IpInfoNotifier with AppLogger {
|
|||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger {
|
class ActiveProxyNotifier extends _$ActiveProxyNotifier with AppLogger {
|
||||||
@override
|
@override
|
||||||
Stream<OutboundInfo> build() async* {
|
Stream<OutboundInfo> build() {
|
||||||
// ref.disposeDelay(const Duration(seconds: 20));
|
// ref.disposeDelay(const Duration(seconds: 20));
|
||||||
ref.watch(coreRestartSignalProvider);
|
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
|
||||||
if (!serviceRunning) {
|
if (!serviceRunning) {
|
||||||
throw const ServiceNotRunning();
|
return Stream.error(const ServiceNotRunning());
|
||||||
}
|
}
|
||||||
final proxyprovider = ref.watch(proxyRepositoryProvider);
|
return _proxyRepo
|
||||||
yield* proxyprovider
|
|
||||||
.watchActiveProxies()
|
.watchActiveProxies()
|
||||||
.map((event) => event.getOrElse((l) => List<OutboundGroup>.empty()))
|
.map((event) => event.getOrElse((l) => List<OutboundGroup>.empty()))
|
||||||
.map((event) => event.firstOrNull?.items.first ?? OutboundInfo());
|
.map((event) => event.firstOrNull?.items.first ?? OutboundInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProxyRepository get _proxyRepo => ref.read(proxyRepositoryProvider);
|
||||||
|
|
||||||
final _urlTestThrottler = Throttler(const Duration(seconds: 1));
|
final _urlTestThrottler = Throttler(const Duration(seconds: 1));
|
||||||
|
|
||||||
Future<void> urlTest(String? groupTag_) async {
|
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/data/proxy_data_providers.dart';
|
||||||
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
|
||||||
import 'package:hiddify/hiddifycore/generated/v2/hcore/hcore.pb.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/riverpod_utils.dart';
|
||||||
import 'package:hiddify/utils/utils.dart';
|
import 'package:hiddify/utils/utils.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
@ -57,12 +57,11 @@ class ProxiesSortNotifier extends _$ProxiesSortNotifier with AppLogger {
|
|||||||
@riverpod
|
@riverpod
|
||||||
class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
|
class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
|
||||||
@override
|
@override
|
||||||
Stream<OutboundGroup?> build() async* {
|
Stream<OutboundGroup?> build() {
|
||||||
ref.disposeDelay(const Duration(seconds: 15));
|
ref.disposeDelay(const Duration(seconds: 15));
|
||||||
ref.watch(coreRestartSignalProvider);
|
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
|
||||||
if (!serviceRunning) {
|
if (!serviceRunning) {
|
||||||
throw const ServiceNotRunning();
|
return Stream.error(const ServiceNotRunning());
|
||||||
}
|
}
|
||||||
final sortBy = ref.watch(proxiesSortNotifierProvider);
|
final sortBy = ref.watch(proxiesSortNotifierProvider);
|
||||||
// yield* ref
|
// yield* ref
|
||||||
@ -82,7 +81,7 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
|
|||||||
// ),
|
// ),
|
||||||
// )
|
// )
|
||||||
// .asyncMap((proxies) async => _sortOutbounds(proxies, sortBy));
|
// .asyncMap((proxies) async => _sortOutbounds(proxies, sortBy));
|
||||||
yield* ref
|
return ref
|
||||||
.watch(proxyRepositoryProvider)
|
.watch(proxyRepositoryProvider)
|
||||||
.watchProxies()
|
.watchProxies()
|
||||||
.map(
|
.map(
|
||||||
|
|||||||
@ -21,7 +21,7 @@ part 'config_option_notifier.g.dart';
|
|||||||
class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger {
|
class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger {
|
||||||
@override
|
@override
|
||||||
Future<bool> build() async {
|
Future<bool> build() async {
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||||
final serviceSingboxOptions = ref.read(connectionRepositoryProvider).configOptionsSnapshot;
|
final serviceSingboxOptions = ref.read(connectionRepositoryProvider).configOptionsSnapshot;
|
||||||
|
|
||||||
ref.listen(ConfigOptions.singboxConfigOptions, (previous, next) async {
|
ref.listen(ConfigOptions.singboxConfigOptions, (previous, next) async {
|
||||||
|
|||||||
@ -10,16 +10,16 @@ part 'stats_notifier.g.dart';
|
|||||||
@riverpod
|
@riverpod
|
||||||
class StatsNotifier extends _$StatsNotifier with AppLogger {
|
class StatsNotifier extends _$StatsNotifier with AppLogger {
|
||||||
@override
|
@override
|
||||||
Stream<SystemInfo> build() async* {
|
Stream<SystemInfo> build() {
|
||||||
ref.disposeDelay(const Duration(seconds: 10));
|
ref.disposeDelay(const Duration(seconds: 10));
|
||||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
final serviceRunning = ref.watch(serviceRunningProvider);
|
||||||
if (serviceRunning) {
|
if (serviceRunning) {
|
||||||
yield* ref
|
return ref
|
||||||
.watch(statsRepositoryProvider)
|
.watch(statsRepositoryProvider)
|
||||||
.watchStats()
|
.watchStats()
|
||||||
.map((event) => event.getOrElse((_) => SystemInfo.create()));
|
.map((event) => event.getOrElse((_) => SystemInfo.create()));
|
||||||
} else {
|
} else {
|
||||||
yield* Stream.value(SystemInfo.create());
|
return Stream.value(SystemInfo.create());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user