Start app immediately, wait for Tor only before connecting

Previously runMigrations() blocked the entire app startup (and UI) waiting
for the built-in Tor daemon to come online. This moves the startup gate so:

- TorManager.start() is called immediately at migration start
- isStartingApp is set to false right after the lifecycle observer is
  registered, so the UI becomes visible without waiting for Tor
- The Tor readiness wait (with retry logic) is kept but now happens *after*
  isStartingApp=false, delaying only relay connections
- ConnectivityService.waitForTorIfNeeded() is called after the startup gate
  so it also holds off on client.connect() until Tor is ready
- A new Amber.waitForTorIfNeeded() helper encapsulates the TorManager check

https://claude.ai/code/session_01QfnSvDcaWayKwrAM71QUeA
This commit is contained in:
Claude
2026-03-18 09:00:12 +00:00
parent bb0dcfa0bb
commit 54863e37dc
2 changed files with 35 additions and 17 deletions
@@ -262,24 +262,10 @@ class Amber :
LocalPreferences.switchToAccount(this@Amber, LocalPreferences.allSavedAccounts(this@Amber).first().npub)
}
LocalPreferences.reloadApp()
// Start Tor immediately in the background without blocking app startup
if (settings.torMode == TorMode.BUILTIN && !BuildFlavorChecker.isOfflineFlavor()) {
var attempt = 0
while (!TorManager.isRunning.value) {
if (attempt > 0) {
TorManager.showRetrying()
TorManager.stop()
delay(3000)
}
TorManager.start(this@Amber, applicationIOScope)
attempt++
withTimeoutOrNull(120_000L) {
TorManager.isRunning.first { it }
}
}
}
checkForNewRelaysAndUpdateAllFilters(true)
if (settings.killSwitch.value) {
disconnectIntentionally()
TorManager.start(this@Amber, applicationIOScope)
}
launch(Dispatchers.Main) {
@@ -307,7 +293,31 @@ class Amber :
}
})
}
// Signal app startup complete so UI shows immediately
isStartingApp.value = false
// Wait for Tor to be ready before establishing relay connections
if (settings.torMode == TorMode.BUILTIN && !BuildFlavorChecker.isOfflineFlavor()) {
var attempt = 0
while (!TorManager.isRunning.value) {
if (attempt > 0) {
TorManager.showRetrying()
TorManager.stop()
delay(3000)
TorManager.start(this@Amber, applicationIOScope)
}
attempt++
withTimeoutOrNull(120_000L) {
TorManager.isRunning.first { it }
}
}
}
checkForNewRelaysAndUpdateAllFilters(true)
if (settings.killSwitch.value) {
disconnectIntentionally()
}
} catch (e: Exception) {
Log.e(TAG, "Failed to run migrations", e)
isStartingApp.value = false
@@ -317,6 +327,12 @@ class Amber :
}
}
suspend fun waitForTorIfNeeded() {
if (settings.torMode == TorMode.BUILTIN && !BuildFlavorChecker.isOfflineFlavor()) {
TorManager.isRunning.first { it }
}
}
fun startServiceFromUi() {
startService()
}
@@ -93,6 +93,8 @@ class ConnectivityService : Service() {
while (Amber.instance.isStartingAppState.value) {
delay(1000)
}
// Wait for Tor to be ready before connecting (if using built-in Tor)
Amber.instance.waitForTorIfNeeded()
if (!BuildFlavorChecker.isOfflineFlavor() && !Amber.instance.settings.killSwitch.value) {
Amber.instance.client.connect()
Amber.instance.applicationIOScope.launch {