mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-24 19:00:26 +01:00
Use remote config v2.
This commit is contained in:
committed by
Jeffrey Starke
parent
dcce8ea35a
commit
7d35cf1374
@@ -12,6 +12,7 @@ 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
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Remote configuration is a list of namespaced keys that clients may use for consistent configuration or behavior.
|
||||
@@ -23,19 +24,22 @@ class RemoteConfigApi(val authWebSocket: SignalWebSocket.AuthenticatedWebSocket,
|
||||
/**
|
||||
* Get remote config data from the server.
|
||||
*
|
||||
* GET /v1/config
|
||||
* GET /v2/config
|
||||
* - 200: Success
|
||||
* - 304: No changes since the last fetch
|
||||
* - 401: Requires authentication
|
||||
*/
|
||||
fun getRemoteConfig(): NetworkResult<RemoteConfigResult> {
|
||||
val request = WebSocketRequestMessage.get("/v1/config")
|
||||
fun getRemoteConfig(eTag: String = ""): NetworkResult<RemoteConfigResult> {
|
||||
val headers = if (eTag.isNotEmpty()) mapOf("If-None-Match" to eTag) else mapOf()
|
||||
val request = WebSocketRequestMessage.get("/v2/config", headers = headers)
|
||||
return NetworkResult.fromWebSocketRequest(signalWebSocket = authWebSocket, request = request, webSocketResponseConverter = RemoteConfigResultWebSocketResponseConverter())
|
||||
.fallback {
|
||||
.fallback(predicate = { it is NetworkResult.StatusCodeError && it.code != 304 }) {
|
||||
NetworkResult.fromFetch {
|
||||
val response = pushServiceSocket.getRemoteConfig()
|
||||
val transformed = response.config.associate { it.name to (it.value ?: it.isEnabled) }
|
||||
val transformed = response.config.map { it.key to (it.value.lowercase(Locale.getDefault()).toBooleanStrictOrNull() ?: it.value) }.toMap()
|
||||
RemoteConfigResult(
|
||||
config = transformed,
|
||||
serverEpochTimeMilliseconds = response.serverEpochTime.takeIf { it > 0 }?.times(1000) ?: System.currentTimeMillis()
|
||||
serverEpochTimeMilliseconds = response.serverEpochTime
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -51,12 +55,13 @@ class RemoteConfigApi(val authWebSocket: SignalWebSocket.AuthenticatedWebSocket,
|
||||
response.toStatusCodeError()
|
||||
} else {
|
||||
val remoteConfigResponse = JsonUtil.fromJson(response.body, RemoteConfigResponse::class.java)
|
||||
val transformed = remoteConfigResponse.config.associate { it.name to (it.value ?: it.isEnabled) }
|
||||
val transformed = remoteConfigResponse.config.map { it.key to (it.value.lowercase(Locale.getDefault()).toBooleanStrictOrNull() ?: it.value) }.toMap()
|
||||
|
||||
NetworkResult.Success(
|
||||
RemoteConfigResult(
|
||||
config = transformed,
|
||||
serverEpochTimeMilliseconds = response.getHeader(SignalWebSocket.SERVER_DELIVERED_TIMESTAMP_HEADER).toLongOrNull() ?: System.currentTimeMillis()
|
||||
serverEpochTimeMilliseconds = response.getHeader(SignalWebSocket.SERVER_DELIVERED_TIMESTAMP_HEADER).toLongOrNull() ?: System.currentTimeMillis(),
|
||||
eTag = response.headers["etag"]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.signalservice.api.remoteconfig;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
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;
|
||||
|
||||
@JsonProperty
|
||||
private boolean enabled;
|
||||
|
||||
@JsonProperty
|
||||
private String value;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public @Nullable String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.whispersystems.signalservice.api.remoteconfig
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
|
||||
/**
|
||||
* Response class used in /v2/config. [serverEpochTime] should only be used in REST calls.
|
||||
*/
|
||||
data class RemoteConfigResponse(
|
||||
@JsonProperty
|
||||
val config: Map<String, String> = emptyMap(),
|
||||
var serverEpochTime: Long = 0
|
||||
)
|
||||
@@ -7,5 +7,6 @@ package org.whispersystems.signalservice.api.remoteconfig
|
||||
|
||||
data class RemoteConfigResult(
|
||||
val config: Map<String, Any>,
|
||||
val serverEpochTimeMilliseconds: Long
|
||||
val serverEpochTimeMilliseconds: Long,
|
||||
val eTag: String? = ""
|
||||
)
|
||||
|
||||
@@ -138,6 +138,7 @@ import okhttp3.Call;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.Dns;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
@@ -178,6 +179,8 @@ public class PushServiceSocket {
|
||||
private static final String VERIFICATION_SESSION_PATH = "/v1/verification/session";
|
||||
private static final String VERIFICATION_CODE_PATH = "/v1/verification/session/%s/code";
|
||||
|
||||
private static final String REMOTE_CONFIG = "/v2/config";
|
||||
|
||||
private static final String REGISTRATION_PATH = "/v1/registration";
|
||||
|
||||
private static final String BACKUP_AUTH_CHECK_V2 = "/v2/svr/auth/check";
|
||||
@@ -541,8 +544,11 @@ public class PushServiceSocket {
|
||||
}
|
||||
|
||||
public RemoteConfigResponse getRemoteConfig() throws IOException {
|
||||
String response = makeServiceRequest("/v1/config", "GET", null);
|
||||
return JsonUtil.fromJson(response, RemoteConfigResponse.class);
|
||||
try (Response response = makeServiceRequest(REMOTE_CONFIG, "GET", jsonRequestBody(null), NO_HEADERS, NO_HANDLER, SealedSenderAccess.NONE, false)) {
|
||||
RemoteConfigResponse remoteConfigResponse = JsonUtil.fromJson(readBodyString(response), RemoteConfigResponse.class);
|
||||
remoteConfigResponse.setServerEpochTime(response.headers().get("X-Signal-Timestamp") != null ? Long.parseLong(response.headers().get("X-Signal-Timestamp")) : System.currentTimeMillis());
|
||||
return remoteConfigResponse;
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelInFlightRequests() {
|
||||
|
||||
Reference in New Issue
Block a user