Network Reconnection Delay
Nucleic-Session: 4BE3E40C-E939-444C-8AED-93C0AFE13C07 Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -320,12 +320,48 @@ final class RemoteStore: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returning to the foreground: the network may have changed while the app was suspended (and
|
/// Returning to the foreground: the network may have changed while the app was suspended (and
|
||||||
/// path/keepalive callbacks were frozen). Re-read the path and re-dial anything not live so the
|
/// path/keepalive callbacks were frozen). Re-read the path, re-dial anything not live, then
|
||||||
/// transport is correct by the time the UI is on screen, rather than after a backoff.
|
/// actively revalidate the connections that still *look* live — a socket the OS killed while we
|
||||||
|
/// were suspended wakes marked `.connected`, and trusting that would stall the reconnect until
|
||||||
|
/// the 55s keepalive deadline. `revalidate` pings each such link and re-dials the instant it
|
||||||
|
/// fails to answer, so the transport is correct (and fast) by the time the UI is on screen.
|
||||||
func onForeground() {
|
func onForeground() {
|
||||||
|
endBackgroundHold()
|
||||||
guard !demoMode, isPaired else { return }
|
guard !demoMode, isPaired else { return }
|
||||||
pathMonitor.refresh()
|
pathMonitor.refresh()
|
||||||
|
// Ensure a connection exists for every paired host (and drop unpaired); this re-dials the
|
||||||
|
// ones already known to be offline.
|
||||||
reconnect()
|
reconnect()
|
||||||
|
// The zombies from suspension still read `.connected` — probe and re-dial the dead ones.
|
||||||
|
for conn in connections.values where conn.connectivity.isLive { conn.revalidate() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#if canImport(UIKit)
|
||||||
|
/// Held while backgrounded so iOS keeps the process (and thus the live sockets + 20s keepalive)
|
||||||
|
/// running for its short grant, instead of suspending us the moment we background.
|
||||||
|
private var backgroundTask: UIBackgroundTaskIdentifier = .invalid
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Entering the background: ask iOS to keep us running briefly so a quick app-switch (glance at
|
||||||
|
/// another app, tap a Live Activity, answer a banner) doesn't tear the connection down and force
|
||||||
|
/// a cold reconnect on return. The grant is short (~30s) and best-effort; once it lapses the OS
|
||||||
|
/// suspends us and the socket dies, which the next `onForeground` revalidation reconnects fast.
|
||||||
|
func onBackground() {
|
||||||
|
guard !demoMode else { return }
|
||||||
|
#if canImport(UIKit)
|
||||||
|
endBackgroundHold()
|
||||||
|
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "nucleic.sync.hold") {
|
||||||
|
[weak self] in self?.endBackgroundHold()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private func endBackgroundHold() {
|
||||||
|
#if canImport(UIKit)
|
||||||
|
guard backgroundTask != .invalid else { return }
|
||||||
|
UIApplication.shared.endBackgroundTask(backgroundTask)
|
||||||
|
backgroundTask = .invalid
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private func seedDemo() {
|
private func seedDemo() {
|
||||||
|
|||||||
Reference in New Issue
Block a user