Add REST fallback to RemoteConfig fetch.

This commit is contained in:
andrew-signal
2025-07-03 13:34:52 -04:00
committed by GitHub
parent 45d8dbc35c
commit a384bf5e35
7 changed files with 30 additions and 6 deletions

View File

@@ -446,7 +446,7 @@ object AppDependencies {
fun provideProvisioningApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): ProvisioningApi
fun provideCertificateApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): CertificateApi
fun provideProfileApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket, pushServiceSocket: PushServiceSocket, clientZkProfileOperations: ClientZkProfileOperations): ProfileApi
fun provideRemoteConfigApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): RemoteConfigApi
fun provideRemoteConfigApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): RemoteConfigApi
fun provideDonationsApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, unauthWebSocket: SignalWebSocket.UnauthenticatedWebSocket): DonationsApi
}
}

View File

@@ -564,8 +564,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
}
@Override
public @NonNull RemoteConfigApi provideRemoteConfigApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
return new RemoteConfigApi(authWebSocket);
public @NonNull RemoteConfigApi provideRemoteConfigApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket, @NonNull PushServiceSocket pushServiceSocket) {
return new RemoteConfigApi(authWebSocket, pushServiceSocket);
}
@Override

View File

@@ -211,7 +211,7 @@ class NetworkDependenciesModule(
}
val remoteConfigApi: RemoteConfigApi by lazy {
provider.provideRemoteConfigApi(authWebSocket)
provider.provideRemoteConfigApi(authWebSocket, pushServiceSocket)
}
val donationsApi: DonationsApi by lazy {

View File

@@ -293,7 +293,7 @@ class MockApplicationDependencyProvider : AppDependencies.Provider {
return mockk(relaxed = true)
}
override fun provideRemoteConfigApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): RemoteConfigApi {
override fun provideRemoteConfigApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): RemoteConfigApi {
return mockk(relaxed = true)
}

View File

@@ -8,6 +8,7 @@ package org.whispersystems.signalservice.api.remoteconfig
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
import org.whispersystems.signalservice.internal.get
import org.whispersystems.signalservice.internal.push.PushServiceSocket
import org.whispersystems.signalservice.internal.util.JsonUtil
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage
import org.whispersystems.signalservice.internal.websocket.WebsocketResponse
@@ -17,7 +18,7 @@ import org.whispersystems.signalservice.internal.websocket.WebsocketResponse
*
* Configuration values change over time, and the list should be refreshed periodically.
*/
class RemoteConfigApi(val authWebSocket: SignalWebSocket.AuthenticatedWebSocket) {
class RemoteConfigApi(val authWebSocket: SignalWebSocket.AuthenticatedWebSocket, val pushServiceSocket: PushServiceSocket) {
/**
* Get remote config data from the server.
@@ -28,6 +29,16 @@ class RemoteConfigApi(val authWebSocket: SignalWebSocket.AuthenticatedWebSocket)
fun getRemoteConfig(): NetworkResult<RemoteConfigResult> {
val request = WebSocketRequestMessage.get("/v1/config")
return NetworkResult.fromWebSocketRequest(signalWebSocket = authWebSocket, request = request, webSocketResponseConverter = RemoteConfigResultWebSocketResponseConverter())
.fallback {
NetworkResult.fromFetch {
val response = pushServiceSocket.getRemoteConfig()
val transformed = response.config.associate { it.name to (it.value ?: it.isEnabled) }
RemoteConfigResult(
config = transformed,
serverEpochTimeMilliseconds = response.serverEpochTime.takeIf { it > 0 }?.times(1000) ?: System.currentTimeMillis()
)
}
}
}
/**

View File

@@ -15,10 +15,17 @@ public class RemoteConfigResponse {
@JsonProperty
private List<Config> config;
@JsonProperty
private long serverEpochTime;
public List<Config> getConfig() {
return config;
}
public long getServerEpochTime() {
return serverEpochTime;
}
public static class Config {
@JsonProperty
private String name;

View File

@@ -35,6 +35,7 @@ import org.whispersystems.signalservice.api.messages.calls.CallingResponse;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException;
import org.whispersystems.signalservice.api.remoteconfig.RemoteConfigResponse;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.ChallengeRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.ConflictException;
@@ -533,6 +534,11 @@ public class PushServiceSocket {
}
}
public RemoteConfigResponse getRemoteConfig() throws IOException {
String response = makeServiceRequest("/v1/config", "GET", null);
return JsonUtil.fromJson(response, RemoteConfigResponse.class);
}
public void cancelInFlightRequests() {
synchronized (connections) {
Log.w(TAG, "Canceling: " + connections.size());