improve UP timeout behavior

Hopefully more reliable.
This commit is contained in:
Henry Hiles 2026-10-05 17:00:56 -04:00
commit 3c6c610f7c
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 93 additions and 55 deletions

View file

@ -18,6 +18,8 @@ import "package:unifiedpush_storage_shared_preferences/storage.dart";
import "package:window_manager/window_manager.dart"; import "package:window_manager/window_manager.dart";
class UnifiedPushController extends AsyncNotifier<bool> { class UnifiedPushController extends AsyncNotifier<bool> {
Completer<void>? _endpoint;
@override @override
Future<bool> build() async { Future<bool> build() async {
if (!Platform.isLinux && !Platform.isAndroid) return false; if (!Platform.isLinux && !Platform.isAndroid) return false;
@ -30,6 +32,7 @@ class UnifiedPushController extends AsyncNotifier<bool> {
shouldWriteService: false, shouldWriteService: false,
), ),
onNewEndpoint: (endpoint, instance) async { onNewEndpoint: (endpoint, instance) async {
final task = Future(() async {
final pushKey = endpoint.pubKeySet!.pubKey; final pushKey = endpoint.pubKeySet!.pubKey;
await ref await ref
.read(PushKeyController.provider(instance).notifier) .read(PushKeyController.provider(instance).notifier)
@ -54,9 +57,20 @@ class UnifiedPushController extends AsyncNotifier<bool> {
); );
state = .data(true); state = .data(true);
});
if (_endpoint case final completer? when !completer.isCompleted) {
completer.complete(task);
} else {
await task;
}
}, },
onRegistrationFailed: (reason, instance) { onRegistrationFailed: (reason, instance) {
if (_endpoint case final completer? when !completer.isCompleted) {
completer.completeError(reason);
} else {
throw reason; throw reason;
}
}, },
onMessage: (message, instance) async { onMessage: (message, instance) async {
debugPrint("UP message received for $instance"); debugPrint("UP message received for $instance");
@ -111,27 +125,34 @@ class UnifiedPushController extends AsyncNotifier<bool> {
onUnregistered: deregister, onUnregistered: deregister,
); );
ref.listen( if (!registered) return false;
ClientStateController.provider.select((value) => value?.deviceId),
(_, _) => register(),
);
if (registered) { try {
// Needs to be registered every startup return await register();
await register(); } catch (error, stackTrace) {
showError(error, stackTrace);
return false;
}
} }
return registered; Future<bool> register() async {
}
Future<void> register() async {
state = .loading(); state = .loading();
try { try {
final deviceId = ref.read( final deviceIdCompleter = Completer<String>();
final subscription = ref.listen(
ClientStateController.provider.select((value) => value?.deviceId), ClientStateController.provider.select((value) => value?.deviceId),
(_, next) {
if (next != null && !deviceIdCompleter.isCompleted) {
deviceIdCompleter.complete(next);
}
},
fireImmediately: true,
);
final deviceId = await deviceIdCompleter.future.whenComplete(
subscription.close,
); );
if (deviceId == null) return;
await Future(() async {
final capabilities = await ref final capabilities = await ref
.read(ClientController.provider.notifier) .read(ClientController.provider.notifier)
.getCapabilities(); .getCapabilities();
@ -146,13 +167,26 @@ class UnifiedPushController extends AsyncNotifier<bool> {
throw Exception("No UnifiedPush distributors found."); throw Exception("No UnifiedPush distributors found.");
} }
await UnifiedPush.register( final endpoint = _endpoint = Completer<void>();
try {
await Future.wait([
UnifiedPush.register(
instance: deviceId, instance: deviceId,
vapid: capabilities.webpush?.vapid, vapid: capabilities.webpush?.vapid,
).timeout( ),
.new(seconds: 15), endpoint.future,
], eagerError: true);
} finally {
if (_endpoint == endpoint) _endpoint = null;
}
}).timeout(
.new(seconds: 10),
onTimeout: () => throw Exception("UnifiedPush registration timed out."), onTimeout: () => throw Exception("UnifiedPush registration timed out."),
); );
state = .data(true);
return true;
} catch (_) { } catch (_) {
state = .data(false); state = .data(false);
rethrow; rethrow;

View file

@ -7,7 +7,11 @@ import "package:unifiedpush/unifiedpush.dart";
class UnifiedPushAllowedController extends AsyncNotifier<String?> { class UnifiedPushAllowedController extends AsyncNotifier<String?> {
@override @override
Future<String?> build() async { Future<String?> build() async {
if (!await UnifiedPush.tryUseCurrentOrDefaultDistributor()) { if (!await UnifiedPush.tryUseCurrentOrDefaultDistributor().timeout(
.new(seconds: 10),
onTimeout: () =>
throw Exception("UnifiedPush distributor check timed out."),
)) {
return "No valid distributors found. ${Platform.isLinux return "No valid distributors found. ${Platform.isLinux
? "Try installing KUnifiedPush" ? "Try installing KUnifiedPush"
: Platform.isAndroid : Platform.isAndroid