diff --git a/app/src/main/java/com/bitchat/android/util/GitHubReleaseClient.kt b/app/src/main/java/com/bitchat/android/util/GitHubReleaseClient.kt index d33c1531..25922b27 100644 --- a/app/src/main/java/com/bitchat/android/util/GitHubReleaseClient.kt +++ b/app/src/main/java/com/bitchat/android/util/GitHubReleaseClient.kt @@ -69,6 +69,7 @@ object GitHubReleaseClient { suspend fun fetchLatestRelease( forceRefresh: Boolean = false, onAwaitingNetworkRoute: (() -> Unit)? = null, + onResolvingRelease: (() -> Unit)? = null, ): Result = withContext(Dispatchers.IO) { fetchMutex.withLock { @@ -108,6 +109,11 @@ object GitHubReleaseClient { ) ) } + // The wait is over, so stop saying we are waiting. In direct mode it + // returned immediately and never really started, and the fetch below + // retries -- either way the caller must not keep reporting a Tor wait + // for the whole metadata request. + onResolvingRelease?.invoke() var lastFailure: Throwable = ReleaseFetchException( "Failed to fetch the latest release from GitHub" @@ -121,6 +127,18 @@ object GitHubReleaseClient { } lastFailure = result.exceptionOrNull() ?: lastFailure + // The response that just set the gate is the one the user is waiting + // on. Reporting an error here and only serving the cache on the next + // call makes the first check fail and an immediate retry succeed from + // metadata we already had. + if (System.currentTimeMillis() < blockedUntilMillis) { + cached?.let { + Log.w(TAG, "Rate limited; serving the cached release instead of failing") + return@withLock Result.success(it.release) + } + return@withLock Result.failure(lastFailure) + } + if (!isRetryable(lastFailure) || attempt == MAX_FETCH_ATTEMPTS - 1) { return@withLock Result.failure(lastFailure) } diff --git a/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt b/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt index 47789582..a457c8b2 100644 --- a/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt +++ b/app/src/main/java/com/bitchat/android/util/UniversalApkManager.kt @@ -228,6 +228,9 @@ class UniversalApkManager(private val context: Context) { val release = GitHubReleaseClient.fetchLatestRelease( onAwaitingNetworkRoute = { phaseCallback?.invoke(ApkDownloader.DownloadPhase.AwaitingNetworkRoute) + }, + onResolvingRelease = { + phaseCallback?.invoke(ApkDownloader.DownloadPhase.ResolvingRelease) } ).getOrElse { error -> return@withContext Result.failure(error)