Stop HEAD requests for possibly-unlisted contacts during CDS refresh.

This commit is contained in:
Greyson Parrelli 2023-07-06 17:00:41 -04:00 committed by Clark Chen
parent 002279f6a7
commit 4b6c308ae9

View file

@ -4,7 +4,6 @@ import android.content.Context
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import org.signal.contacts.SystemContactsRepository import org.signal.contacts.SystemContactsRepository
import org.signal.core.util.Stopwatch import org.signal.core.util.Stopwatch
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.BuildConfig import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.contacts.sync.FuzzyPhoneNumberHelper.InputResult import org.thoughtcrime.securesms.contacts.sync.FuzzyPhoneNumberHelper.InputResult
@ -12,7 +11,6 @@ import org.thoughtcrime.securesms.contacts.sync.FuzzyPhoneNumberHelper.OutputRes
import org.thoughtcrime.securesms.database.RecipientTable.CdsV2Result import org.thoughtcrime.securesms.database.RecipientTable.CdsV2Result
import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob
import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
@ -24,8 +22,6 @@ import org.whispersystems.signalservice.api.push.exceptions.CdsiResourceExhauste
import org.whispersystems.signalservice.api.services.CdsiV2Service import org.whispersystems.signalservice.api.services.CdsiV2Service
import java.io.IOException import java.io.IOException
import java.util.Optional import java.util.Optional
import java.util.concurrent.Callable
import java.util.concurrent.Future
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@ -190,7 +186,7 @@ object ContactDiscoveryRefreshV2 {
val existingIds: Set<RecipientId> = SignalDatabase.recipients.getAllPossiblyRegisteredByE164(recipientE164s + rewrites.values) val existingIds: Set<RecipientId> = SignalDatabase.recipients.getAllPossiblyRegisteredByE164(recipientE164s + rewrites.values)
stopwatch.split("get-ids") stopwatch.split("get-ids")
val inactiveIds: Set<RecipientId> = (existingIds - registeredIds).removeRegisteredButUnlisted() val inactiveIds: Set<RecipientId> = (existingIds - registeredIds).removePossiblyRegisteredButUnlisted()
stopwatch.split("registered-but-unlisted") stopwatch.split("registered-but-unlisted")
SignalDatabase.recipients.bulkUpdatedRegisteredStatus(aciMap, inactiveIds) SignalDatabase.recipients.bulkUpdatedRegisteredStatus(aciMap, inactiveIds)
@ -213,7 +209,7 @@ object ContactDiscoveryRefreshV2 {
val existingIds: Set<RecipientId> = SignalDatabase.recipients.getAllPossiblyRegisteredByE164(recipientE164s + rewrites.values) val existingIds: Set<RecipientId> = SignalDatabase.recipients.getAllPossiblyRegisteredByE164(recipientE164s + rewrites.values)
stopwatch.split("get-ids") stopwatch.split("get-ids")
val inactiveIds: Set<RecipientId> = (existingIds - registeredIds).removeRegisteredButUnlisted() val inactiveIds: Set<RecipientId> = (existingIds - registeredIds).removePossiblyRegisteredButUnlisted()
stopwatch.split("registered-but-unlisted") stopwatch.split("registered-but-unlisted")
SignalDatabase.recipients.bulkUpdatedRegisteredStatusV2(registeredIds, inactiveIds) SignalDatabase.recipients.bulkUpdatedRegisteredStatusV2(registeredIds, inactiveIds)
@ -230,42 +226,19 @@ object ContactDiscoveryRefreshV2 {
return SignalDatabase.threads.hasThread(recipient.id) || (recipient.hasServiceId() && SignalDatabase.sessions.hasSessionFor(localAci, recipient.requireServiceId().toString())) return SignalDatabase.threads.hasThread(recipient.id) || (recipient.hasServiceId() && SignalDatabase.sessions.hasSessionFor(localAci, recipient.requireServiceId().toString()))
} }
/**
* If an account is unlisted, it won't come back in the CDS response. So just because we're missing a entry doesn't mean they've become unregistered.
* This function removes people from the list that both have a serviceId and some history of communication. We consider this a good hueristic for
* "maybe this person just removed themselves from CDS". We'll rely on profile fetches that occur during chat opens to check registered status and clear
* actually-unregistered users out.
*/
@WorkerThread @WorkerThread
private fun Set<RecipientId>.removeRegisteredButUnlisted(): Set<RecipientId> { private fun Set<RecipientId>.removePossiblyRegisteredButUnlisted(): Set<RecipientId> {
val futures: List<Future<Pair<RecipientId, Boolean?>>> = Recipient.resolvedList(this) return this - Recipient.resolvedList(this)
.filter { it.hasServiceId() } .filter { it.hasServiceId() }
.filter { hasCommunicatedWith(it) } .filter { hasCommunicatedWith(it) }
.map { .map { it.id }
SignalExecutors.UNBOUNDED.submit( .toSet()
Callable {
try {
it.id to ApplicationDependencies.getSignalServiceAccountManager().isIdentifierRegistered(it.requireServiceId())
} catch (e: IOException) {
it.id to null
}
}
)
}
val registeredIds: MutableSet<RecipientId> = mutableSetOf()
val retryIds: MutableSet<RecipientId> = mutableSetOf()
for (future in futures) {
val (id, registered) = future.get()
if (registered == null) {
retryIds += id
registeredIds += id
} else if (registered) {
registeredIds += id
}
}
if (retryIds.isNotEmpty()) {
Log.w(TAG, "Failed to determine registered status of ${retryIds.size} recipients. Assuming registered, but enqueuing profile jobs to check later.")
RetrieveProfileJob.enqueue(retryIds)
}
return this - registeredIds
} }
private fun Set<String>.toE164s(context: Context): Set<String> { private fun Set<String>.toE164s(context: Context): Set<String> {