Allow REST fallback via remote config.

This commit is contained in:
Cody Henthorne
2025-05-15 10:52:36 -04:00
committed by GitHub
parent 2bc9926d97
commit 96ece3f424
3 changed files with 54 additions and 10 deletions

View File

@@ -170,7 +170,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
keysApi, keysApi,
Optional.of(new SecurityEventListener(context)), Optional.of(new SecurityEventListener(context)),
SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30), SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30),
ByteUnit.KILOBYTES.toBytes(256)); ByteUnit.KILOBYTES.toBytes(256),
RemoteConfig::useMessageSendRestFallback);
} }
@Override @Override

View File

@@ -1087,5 +1087,13 @@ object RemoteConfig {
hotSwappable = false hotSwappable = false
) )
@JvmStatic
@get:JvmName("useMessageSendRestFallback")
val useMessageSendRestFallback: Boolean by remoteBoolean(
key = "android.useMessageSendRestFallback",
defaultValue = false,
hotSwappable = true
)
// endregion // endregion
} }

View File

@@ -140,6 +140,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -180,6 +181,7 @@ public class SignalServiceMessageSender {
private final Scheduler scheduler; private final Scheduler scheduler;
private final long maxEnvelopeSize; private final long maxEnvelopeSize;
private final BooleanSupplier useRestFallback;
public SignalServiceMessageSender(PushServiceSocket pushServiceSocket, public SignalServiceMessageSender(PushServiceSocket pushServiceSocket,
SignalServiceDataStore store, SignalServiceDataStore store,
@@ -189,7 +191,8 @@ public class SignalServiceMessageSender {
KeysApi keysApi, KeysApi keysApi,
Optional<EventListener> eventListener, Optional<EventListener> eventListener,
ExecutorService executor, ExecutorService executor,
long maxEnvelopeSize) long maxEnvelopeSize,
BooleanSupplier useRestFallback)
{ {
CredentialsProvider credentialsProvider = pushServiceSocket.getCredentialsProvider(); CredentialsProvider credentialsProvider = pushServiceSocket.getCredentialsProvider();
@@ -206,6 +209,7 @@ public class SignalServiceMessageSender {
this.localPniIdentity = store.pni().getIdentityKeyPair(); this.localPniIdentity = store.pni().getIdentityKeyPair();
this.scheduler = Schedulers.from(executor, false, false); this.scheduler = Schedulers.from(executor, false, false);
this.keysApi = keysApi; this.keysApi = keysApi;
this.useRestFallback = useRestFallback;
} }
/** /**
@@ -1941,14 +1945,25 @@ public class SignalServiceMessageSender {
throw e; throw e;
} catch (WebSocketUnavailableException e) { } catch (WebSocketUnavailableException e) {
String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe"; String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe";
Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); if (useRestFallback.getAsBoolean()) {
Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
} else {
Log.i(TAG, "[sendMessage][" + timestamp + "] " + pipe + " unavailable (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
throw e;
}
} catch (IOException e) { } catch (IOException e) {
String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe"; String pipe = sealedSenderAccess == null ? "Pipe" : "Unidentified pipe";
Throwable cause = e; Throwable cause = e;
if (e.getCause() != null) { if (e.getCause() != null) {
cause = e.getCause(); cause = e.getCause();
} }
Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")");
if (useRestFallback.getAsBoolean()) {
Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")");
} else {
Log.w(TAG, "[sendMessage][" + timestamp + "] " + pipe + " failed (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")");
throw (cause instanceof IOException) ? (IOException) cause : e;
}
} }
if (cancelationSignal != null && cancelationSignal.isCanceled()) { if (cancelationSignal != null && cancelationSignal.isCanceled()) {
@@ -2137,7 +2152,7 @@ public class SignalServiceMessageSender {
content.getContent() content.getContent()
); );
return Single.just(result); return Single.just(result);
} catch (Throwable throwable) { } catch (IOException throwable) {
if (cancelationSignal != null && cancelationSignal.isCanceled()) { if (cancelationSignal != null && cancelationSignal.isCanceled()) {
return Single.error(new CancelationException()); return Single.error(new CancelationException());
} }
@@ -2152,10 +2167,20 @@ public class SignalServiceMessageSender {
// Non-technical failures shouldn't be retried with socket // Non-technical failures shouldn't be retried with socket
return Single.error(throwable); return Single.error(throwable);
} else if (throwable instanceof WebSocketUnavailableException) { } else if (throwable instanceof WebSocketUnavailableException) {
Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable, falling back... (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")"); if (useRestFallback.getAsBoolean()) {
} else if (throwable instanceof IOException) { Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable, falling back... (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")");
} else {
Log.i(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe unavailable (" + throwable.getClass().getSimpleName() + ": " + throwable.getMessage() + ")");
return Single.error(throwable);
}
} else {
Throwable cause = throwable.getCause() != null ? throwable.getCause() : throwable; Throwable cause = throwable.getCause() != null ? throwable.getCause() : throwable;
Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")"); if (useRestFallback.getAsBoolean()) {
Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed, falling back... (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")");
} else {
Log.w(TAG, "[sendMessage][" + timestamp + "] " + (sealedSenderAccess != null ? "Unidentified " : "") + "pipe failed (" + cause.getClass().getSimpleName() + ": " + cause.getMessage() + ")");
return Single.error((cause instanceof IOException) ? cause : throwable);
}
} }
return Single.fromCallable(() -> { return Single.fromCallable(() -> {
@@ -2431,9 +2456,19 @@ public class SignalServiceMessageSender {
// Non-technical failures shouldn't be retried with socket // Non-technical failures shouldn't be retried with socket
throw e; throw e;
} catch (WebSocketUnavailableException e) { } catch (WebSocketUnavailableException e) {
Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); if (useRestFallback.getAsBoolean()) {
Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
} else {
Log.i(TAG, "[sendGroupMessage][" + timestamp + "] Pipe unavailable (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
throw e;
}
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"); if (useRestFallback.getAsBoolean()) {
Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
} else {
Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
throw e;
}
} }
SendGroupMessageResponse response = socket.sendGroupMessage(ciphertext, sealedSenderAccess, timestamp, online, urgent, story); SendGroupMessageResponse response = socket.sendGroupMessage(ciphertext, sealedSenderAccess, timestamp, online, urgent, story);