Add 10s timeout to user facing CDSI requests.

This commit is contained in:
Clark Chen 2023-06-28 14:04:08 -04:00 committed by Greyson Parrelli
parent 8d20669e46
commit 36fc9aa82a
8 changed files with 34 additions and 15 deletions

View file

@ -59,6 +59,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -121,7 +122,7 @@ public class NewConversationActivity extends ContactSelectionActivity
if (!resolved.isRegistered() || !resolved.hasServiceId()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.");
try {
ContactDiscovery.refresh(this, resolved, false);
ContactDiscovery.refresh(this, resolved, false, TimeUnit.SECONDS.toMillis(10));
resolved = Recipient.resolved(resolved.getId());
} catch (IOException e) {
Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact.");

View file

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
import java.io.IOException
import java.util.Optional
import java.util.function.Consumer
import kotlin.time.Duration.Companion.seconds
class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment.NewCallCallback {
@ -49,7 +50,7 @@ class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment
if (!resolved.isRegistered || !resolved.hasServiceId()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.")
resolved = try {
refresh(this, resolved, false)
refresh(this, resolved, false, 10.seconds.inWholeMilliseconds)
Recipient.resolved(resolved.id)
} catch (e: IOException) {
Log.w(TAG, "[onContactSelected] Failed to refresh directory for new contact.")

View file

@ -91,14 +91,15 @@ object ContactDiscovery {
}
@JvmStatic
@JvmOverloads
@Throws(IOException::class)
@WorkerThread
fun refresh(context: Context, recipient: Recipient, notifyOfNewUsers: Boolean): RecipientTable.RegisteredState {
fun refresh(context: Context, recipient: Recipient, notifyOfNewUsers: Boolean, timeoutMs: Long? = null): RecipientTable.RegisteredState {
val result: RefreshResult = refreshRecipients(
context = context,
descriptor = "refresh-single",
refresh = {
ContactDiscoveryRefreshV2.refresh(context, listOf(recipient), useCompat = !FeatureFlags.phoneNumberPrivacy(), ignoreResults = false)
ContactDiscoveryRefreshV2.refresh(context, listOf(recipient), useCompat = !FeatureFlags.phoneNumberPrivacy(), ignoreResults = false, timeoutMs = timeoutMs)
},
removeSystemContactLinksIfMissing = false,
notifyOfNewUsers = notifyOfNewUsers

View file

@ -49,7 +49,7 @@ object ContactDiscoveryRefreshV2 {
@WorkerThread
@Synchronized
@JvmStatic
fun refreshAll(context: Context, useCompat: Boolean, ignoreResults: Boolean): ContactDiscovery.RefreshResult {
fun refreshAll(context: Context, useCompat: Boolean, ignoreResults: Boolean, timeoutMs: Long? = null): ContactDiscovery.RefreshResult {
val recipientE164s: Set<String> = SignalDatabase.recipients.getAllE164s().sanitize()
val systemE164s: Set<String> = SystemContactsRepository.getAllDisplayNumbers(context).toE164s(context).sanitize()
@ -59,7 +59,8 @@ object ContactDiscoveryRefreshV2 {
inputPreviousE164s = SignalDatabase.cds.getAllE164s(),
isPartialRefresh = false,
useCompat = useCompat,
ignoreResults = ignoreResults
ignoreResults = ignoreResults,
timeoutMs = timeoutMs
)
}
@ -67,14 +68,14 @@ object ContactDiscoveryRefreshV2 {
@WorkerThread
@Synchronized
@JvmStatic
fun refresh(context: Context, inputRecipients: List<Recipient>, useCompat: Boolean, ignoreResults: Boolean): ContactDiscovery.RefreshResult {
fun refresh(context: Context, inputRecipients: List<Recipient>, useCompat: Boolean, ignoreResults: Boolean, timeoutMs: Long? = null): ContactDiscovery.RefreshResult {
val recipients: List<Recipient> = inputRecipients.map { it.resolve() }
val inputE164s: Set<String> = recipients.mapNotNull { it.e164.orElse(null) }.toSet().sanitize()
return if (inputE164s.size > MAXIMUM_ONE_OFF_REQUEST_SIZE) {
Log.i(TAG, "List of specific recipients to refresh is too large! (Size: ${recipients.size}). Doing a full refresh instead.")
val fullResult: ContactDiscovery.RefreshResult = refreshAll(context, useCompat = useCompat, ignoreResults = ignoreResults)
val fullResult: ContactDiscovery.RefreshResult = refreshAll(context, useCompat = useCompat, ignoreResults = ignoreResults, timeoutMs = timeoutMs)
val inputIds: Set<RecipientId> = recipients.map { it.id }.toSet()
ContactDiscovery.RefreshResult(
@ -88,7 +89,8 @@ object ContactDiscoveryRefreshV2 {
inputPreviousE164s = emptySet(),
isPartialRefresh = true,
useCompat = useCompat,
ignoreResults = ignoreResults
ignoreResults = ignoreResults,
timeoutMs = timeoutMs
)
}
}
@ -100,7 +102,8 @@ object ContactDiscoveryRefreshV2 {
inputPreviousE164s: Set<String>,
isPartialRefresh: Boolean,
useCompat: Boolean,
ignoreResults: Boolean
ignoreResults: Boolean,
timeoutMs: Long? = null
): ContactDiscovery.RefreshResult {
val tag = "refreshInternal-${if (useCompat) "compat" else "v2"}"
val stopwatch = Stopwatch(tag)
@ -134,7 +137,8 @@ object ContactDiscoveryRefreshV2 {
SignalDatabase.recipients.getAllServiceIdProfileKeyPairs(),
useCompat,
Optional.ofNullable(token),
BuildConfig.CDSI_MRENCLAVE
BuildConfig.CDSI_MRENCLAVE,
timeoutMs
) { tokenToSave ->
stopwatch.split("network-pre-token")
if (!isPartialRefresh) {

View file

@ -723,7 +723,7 @@ public class ConversationParentFragment extends Fragment
case ADD_CONTACT:
SimpleTask.run(() -> {
try {
ContactDiscovery.refresh(requireContext(), recipient.get(), false);
ContactDiscovery.refresh(requireContext(), recipient.get(), false, TimeUnit.SECONDS.toMillis(10));
} catch (IOException e) {
Log.w(TAG, "Failed to refresh user after adding to contacts.");
}

View file

@ -33,6 +33,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -160,7 +161,7 @@ public class CreateGroupActivity extends ContactSelectionActivity {
for (Recipient recipient : registeredChecks) {
try {
ContactDiscovery.refresh(this, recipient, false);
ContactDiscovery.refresh(this, recipient, false, TimeUnit.SECONDS.toMillis(10));
} catch (IOException e) {
Log.w(TAG, "Failed to refresh registered status for " + recipient.getId(), e);
}

View file

@ -49,6 +49,7 @@ import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
public class CommunicationActions {
@ -303,7 +304,7 @@ public class CommunicationActions {
if (!recipient.isRegistered() || !recipient.hasServiceId()) {
try {
ContactDiscovery.refresh(activity, recipient, false);
ContactDiscovery.refresh(activity, recipient, false, TimeUnit.SECONDS.toMillis(10));
recipient = Recipient.resolved(recipient.getId());
} catch (IOException e) {
Log.w(TAG, "[handlePotentialSignalMeUrl] Failed to refresh directory for new contact.");

View file

@ -390,6 +390,7 @@ public class SignalServiceAccountManager {
boolean requireAcis,
Optional<byte[]> token,
String mrEnclave,
Long timeoutMs,
Consumer<byte[]> tokenSaver)
throws IOException
{
@ -400,11 +401,20 @@ public class SignalServiceAccountManager {
ServiceResponse<CdsiV2Service.Response> serviceResponse;
try {
serviceResponse = single.blockingGet();
if (timeoutMs == null) {
serviceResponse = single
.blockingGet();
} else {
serviceResponse = single
.timeout(timeoutMs, TimeUnit.MILLISECONDS)
.blockingGet();
}
} catch (RuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof InterruptedException) {
throw new IOException("Interrupted", cause);
} else if (cause instanceof TimeoutException) {
throw new IOException("Timed out");
} else {
throw e;
}