Make `DynamicConfigurationManager` generic

This commit is contained in:
Jon Chambers 2021-10-18 16:26:52 -04:00 committed by Jon Chambers
parent c91d5c2fdb
commit 3b764bed7a
19 changed files with 115 additions and 87 deletions

View File

@ -73,6 +73,7 @@ import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
import org.whispersystems.textsecuregcm.auth.WebsocketRefreshApplicationEventListener; import org.whispersystems.textsecuregcm.auth.WebsocketRefreshApplicationEventListener;
import org.whispersystems.textsecuregcm.badges.ConfiguredProfileBadgeConverter; import org.whispersystems.textsecuregcm.badges.ConfiguredProfileBadgeConverter;
import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration; import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.controllers.AccountController; import org.whispersystems.textsecuregcm.controllers.AccountController;
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1; import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2; import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
@ -416,7 +417,12 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret(), config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret(),
true); true);
DynamicConfigurationManager dynamicConfigurationManager = new DynamicConfigurationManager(config.getAppConfig().getApplication(), config.getAppConfig().getEnvironment(), config.getAppConfig().getConfigurationName()); DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
new DynamicConfigurationManager<>(config.getAppConfig().getApplication(),
config.getAppConfig().getEnvironment(),
config.getAppConfig().getConfigurationName(),
DynamicConfiguration.class);
dynamicConfigurationManager.start(); dynamicConfigurationManager.start();
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager); ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager);

View File

@ -50,6 +50,7 @@ import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode; import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
import org.whispersystems.textsecuregcm.auth.TurnToken; import org.whispersystems.textsecuregcm.auth.TurnToken;
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator; import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicSignupCaptchaConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicSignupCaptchaConfiguration;
import org.whispersystems.textsecuregcm.entities.AccountAttributes; import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.AccountCreationResult; import org.whispersystems.textsecuregcm.entities.AccountCreationResult;
@ -115,7 +116,7 @@ public class AccountController {
private final AbusiveHostRules abusiveHostRules; private final AbusiveHostRules abusiveHostRules;
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final SmsSender smsSender; private final SmsSender smsSender;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private final TurnTokenGenerator turnTokenGenerator; private final TurnTokenGenerator turnTokenGenerator;
private final Map<String, Integer> testDevices; private final Map<String, Integer> testDevices;
private final RecaptchaClient recaptchaClient; private final RecaptchaClient recaptchaClient;
@ -131,7 +132,7 @@ public class AccountController {
AbusiveHostRules abusiveHostRules, AbusiveHostRules abusiveHostRules,
RateLimiters rateLimiters, RateLimiters rateLimiters,
SmsSender smsSenderFactory, SmsSender smsSenderFactory,
DynamicConfigurationManager dynamicConfigurationManager, DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
TurnTokenGenerator turnTokenGenerator, TurnTokenGenerator turnTokenGenerator,
Map<String, Integer> testDevices, Map<String, Integer> testDevices,
RecaptchaClient recaptchaClient, RecaptchaClient recaptchaClient,

View File

@ -59,6 +59,7 @@ import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum;
import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter; import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter;
import org.whispersystems.textsecuregcm.configuration.BadgeConfiguration; import org.whispersystems.textsecuregcm.configuration.BadgeConfiguration;
import org.whispersystems.textsecuregcm.configuration.BadgesConfiguration; import org.whispersystems.textsecuregcm.configuration.BadgesConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.entities.CreateProfileRequest; import org.whispersystems.textsecuregcm.entities.CreateProfileRequest;
import org.whispersystems.textsecuregcm.entities.Profile; import org.whispersystems.textsecuregcm.entities.Profile;
import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes; import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes;
@ -90,7 +91,7 @@ public class ProfileController {
private final ProfilesManager profilesManager; private final ProfilesManager profilesManager;
private final AccountsManager accountsManager; private final AccountsManager accountsManager;
private final UsernamesManager usernamesManager; private final UsernamesManager usernamesManager;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private final ProfileBadgeConverter profileBadgeConverter; private final ProfileBadgeConverter profileBadgeConverter;
private final Map<String, BadgeConfiguration> badgeConfigurationMap; private final Map<String, BadgeConfiguration> badgeConfigurationMap;
@ -107,7 +108,7 @@ public class ProfileController {
AccountsManager accountsManager, AccountsManager accountsManager,
ProfilesManager profilesManager, ProfilesManager profilesManager,
UsernamesManager usernamesManager, UsernamesManager usernamesManager,
DynamicConfigurationManager dynamicConfigurationManager, DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
ProfileBadgeConverter profileBadgeConverter, ProfileBadgeConverter profileBadgeConverter,
BadgesConfiguration badgesConfiguration, BadgesConfiguration badgesConfiguration,
S3Client s3client, S3Client s3client,

View File

@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.experiment;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicExperimentEnrollmentConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicExperimentEnrollmentConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicPreRegistrationExperimentEnrollmentConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicPreRegistrationExperimentEnrollmentConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
@ -14,9 +15,9 @@ import org.whispersystems.textsecuregcm.util.Util;
public class ExperimentEnrollmentManager { public class ExperimentEnrollmentManager {
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
public ExperimentEnrollmentManager(final DynamicConfigurationManager dynamicConfigurationManager) { public ExperimentEnrollmentManager(final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.dynamicConfigurationManager = dynamicConfigurationManager; this.dynamicConfigurationManager = dynamicConfigurationManager;
} }

View File

@ -19,6 +19,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicRemoteDeprecationConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicRemoteDeprecationConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform; import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
@ -34,7 +35,7 @@ import org.whispersystems.textsecuregcm.util.ua.UserAgentUtil;
*/ */
public class RemoteDeprecationFilter implements Filter { public class RemoteDeprecationFilter implements Filter {
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private static final String DEPRECATED_CLIENT_COUNTER_NAME = name(RemoteDeprecationFilter.class, "deprecated"); private static final String DEPRECATED_CLIENT_COUNTER_NAME = name(RemoteDeprecationFilter.class, "deprecated");
private static final String PENDING_DEPRECATION_COUNTER_NAME = name(RemoteDeprecationFilter.class, "pendingDeprecation"); private static final String PENDING_DEPRECATION_COUNTER_NAME = name(RemoteDeprecationFilter.class, "pendingDeprecation");
@ -44,7 +45,7 @@ public class RemoteDeprecationFilter implements Filter {
private static final String BLOCKED_CLIENT_REASON = "blocked"; private static final String BLOCKED_CLIENT_REASON = "blocked";
private static final String UNRECOGNIZED_UA_REASON = "unrecognized_user_agent"; private static final String UNRECOGNIZED_UA_REASON = "unrecognized_user_agent";
public RemoteDeprecationFilter(final DynamicConfigurationManager dynamicConfigurationManager) { public RemoteDeprecationFilter(final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.dynamicConfigurationManager = dynamicConfigurationManager; this.dynamicConfigurationManager = dynamicConfigurationManager;
} }

View File

@ -9,6 +9,7 @@ import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.util.Duration; import io.dropwizard.util.Duration;
import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Metrics;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException; import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
@ -28,11 +29,11 @@ public class PreKeyRateLimiter {
private static final long RATE_LIMITED_ACCOUNTS_HLL_TTL_SECONDS = Duration.days(1).toSeconds(); private static final long RATE_LIMITED_ACCOUNTS_HLL_TTL_SECONDS = Duration.days(1).toSeconds();
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private final RateLimitResetMetricsManager metricsManager; private final RateLimitResetMetricsManager metricsManager;
public PreKeyRateLimiter(final RateLimiters rateLimiters, public PreKeyRateLimiter(final RateLimiters rateLimiters,
final DynamicConfigurationManager dynamicConfigurationManager, final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
final RateLimitResetMetricsManager metricsManager) { final RateLimitResetMetricsManager metricsManager) {
this.rateLimiters = rateLimiters; this.rateLimiters = rateLimiters;
this.dynamicConfigurationManager = dynamicConfigurationManager; this.dynamicConfigurationManager = dynamicConfigurationManager;

View File

@ -7,6 +7,7 @@ import io.micrometer.core.instrument.Metrics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException; import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.push.NotPushRegisteredException; import org.whispersystems.textsecuregcm.push.NotPushRegisteredException;
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient; import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
@ -26,7 +27,7 @@ public class RateLimitChallengeManager {
private final UnsealedSenderRateLimiter unsealedSenderRateLimiter; private final UnsealedSenderRateLimiter unsealedSenderRateLimiter;
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
public static final String OPTION_RECAPTCHA = "recaptcha"; public static final String OPTION_RECAPTCHA = "recaptcha";
public static final String OPTION_PUSH_CHALLENGE = "pushChallenge"; public static final String OPTION_PUSH_CHALLENGE = "pushChallenge";
@ -43,7 +44,7 @@ public class RateLimitChallengeManager {
final PreKeyRateLimiter preKeyRateLimiter, final PreKeyRateLimiter preKeyRateLimiter,
final UnsealedSenderRateLimiter unsealedSenderRateLimiter, final UnsealedSenderRateLimiter unsealedSenderRateLimiter,
final RateLimiters rateLimiters, final RateLimiters rateLimiters,
final DynamicConfigurationManager dynamicConfigurationManager) { final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.pushChallengeManager = pushChallengeManager; this.pushChallengeManager = pushChallengeManager;
this.recaptchaClient = recaptchaClient; this.recaptchaClient = recaptchaClient;

View File

@ -10,6 +10,7 @@ import java.util.function.BiFunction;
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration; import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.CardinalityRateLimitConfiguration; import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.CardinalityRateLimitConfiguration;
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.RateLimitConfiguration; import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration.RateLimitConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
@ -48,9 +49,9 @@ public class RateLimiters {
private final AtomicReference<RateLimiter> dailyPreKeysLimiter; private final AtomicReference<RateLimiter> dailyPreKeysLimiter;
private final FaultTolerantRedisCluster cacheCluster; private final FaultTolerantRedisCluster cacheCluster;
private final DynamicConfigurationManager dynamicConfig; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfig;
public RateLimiters(RateLimitsConfiguration config, DynamicConfigurationManager dynamicConfig, FaultTolerantRedisCluster cacheCluster) { public RateLimiters(RateLimitsConfiguration config, DynamicConfigurationManager<DynamicConfiguration> dynamicConfig, FaultTolerantRedisCluster cacheCluster) {
this.cacheCluster = cacheCluster; this.cacheCluster = cacheCluster;
this.dynamicConfig = dynamicConfig; this.dynamicConfig = dynamicConfig;

View File

@ -10,6 +10,7 @@ import static com.codahale.metrics.MetricRegistry.name;
import io.dropwizard.util.Duration; import io.dropwizard.util.Duration;
import io.lettuce.core.SetArgs; import io.lettuce.core.SetArgs;
import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Metrics;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicRateLimitsConfiguration; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicRateLimitsConfiguration;
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException; import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
@ -21,7 +22,7 @@ public class UnsealedSenderRateLimiter {
private final RateLimiters rateLimiters; private final RateLimiters rateLimiters;
private final FaultTolerantRedisCluster rateLimitCluster; private final FaultTolerantRedisCluster rateLimitCluster;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private final RateLimitResetMetricsManager metricsManager; private final RateLimitResetMetricsManager metricsManager;
private static final String RATE_LIMIT_RESET_COUNTER_NAME = name(UnsealedSenderRateLimiter.class, "reset"); private static final String RATE_LIMIT_RESET_COUNTER_NAME = name(UnsealedSenderRateLimiter.class, "reset");
@ -38,7 +39,7 @@ public class UnsealedSenderRateLimiter {
public UnsealedSenderRateLimiter(final RateLimiters rateLimiters, public UnsealedSenderRateLimiter(final RateLimiters rateLimiters,
final FaultTolerantRedisCluster rateLimitCluster, final FaultTolerantRedisCluster rateLimitCluster,
final DynamicConfigurationManager dynamicConfigurationManager, final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
final RateLimitResetMetricsManager metricsManager) { final RateLimitResetMetricsManager metricsManager) {
this.rateLimiters = rateLimiters; this.rateLimiters = rateLimiters;

View File

@ -38,6 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration; import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration;
import org.whispersystems.textsecuregcm.configuration.TwilioVerificationTextConfiguration; import org.whispersystems.textsecuregcm.configuration.TwilioVerificationTextConfiguration;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient; import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
import org.whispersystems.textsecuregcm.http.FormDataBodyPublisher; import org.whispersystems.textsecuregcm.http.FormDataBodyPublisher;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
@ -74,12 +75,16 @@ public class TwilioSmsSender {
private final URI smsUri; private final URI smsUri;
private final URI voxUri; private final URI voxUri;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private final TwilioVerifySender twilioVerifySender; private final TwilioVerifySender twilioVerifySender;
@VisibleForTesting @VisibleForTesting
public TwilioSmsSender(String baseUri, String baseVerifyUri, TwilioConfiguration twilioConfiguration, DynamicConfigurationManager dynamicConfigurationManager) { public TwilioSmsSender(String baseUri,
String baseVerifyUri,
TwilioConfiguration twilioConfiguration,
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
Executor executor = ExecutorUtils.newFixedThreadBoundedQueueExecutor(10, 100); Executor executor = ExecutorUtils.newFixedThreadBoundedQueueExecutor(10, 100);
this.accountId = twilioConfiguration.getAccountId(); this.accountId = twilioConfiguration.getAccountId();

View File

@ -15,6 +15,7 @@ import java.util.function.Function;
import javax.ws.rs.ProcessingException; import javax.ws.rs.ProcessingException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationRequest; import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationRequest;
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse; import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse;
import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse.Status; import org.whispersystems.textsecuregcm.entities.DirectoryReconciliationResponse.Status;
@ -26,10 +27,10 @@ public class DirectoryReconciler extends AccountDatabaseCrawlerListener {
private final String replicationName; private final String replicationName;
private final DirectoryReconciliationClient reconciliationClient; private final DirectoryReconciliationClient reconciliationClient;
private final DynamicConfigurationManager dynamicConfigurationManager; private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
public DirectoryReconciler(String replicationName, DirectoryReconciliationClient reconciliationClient, public DirectoryReconciler(String replicationName, DirectoryReconciliationClient reconciliationClient,
DynamicConfigurationManager dynamicConfigurationManager) { DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
this.reconciliationClient = reconciliationClient; this.reconciliationClient = reconciliationClient;
this.replicationName = replicationName; this.replicationName = replicationName;
this.dynamicConfigurationManager = dynamicConfigurationManager; this.dynamicConfigurationManager = dynamicConfigurationManager;

View File

@ -18,22 +18,23 @@ import javax.validation.Validator;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.services.appconfig.AppConfigClient; import software.amazon.awssdk.services.appconfig.AppConfigClient;
import software.amazon.awssdk.services.appconfig.model.GetConfigurationRequest; import software.amazon.awssdk.services.appconfig.model.GetConfigurationRequest;
import software.amazon.awssdk.services.appconfig.model.GetConfigurationResponse; import software.amazon.awssdk.services.appconfig.model.GetConfigurationResponse;
public class DynamicConfigurationManager { public class DynamicConfigurationManager<T> {
private final String application; private final String application;
private final String environment; private final String environment;
private final String configurationName; private final String configurationName;
private final String clientId; private final String clientId;
private final AppConfigClient appConfigClient; private final AppConfigClient appConfigClient;
private final AtomicReference<DynamicConfiguration> configuration = new AtomicReference<>(); private final Class<T> configurationClass;
private final AtomicReference<T> configuration = new AtomicReference<>();
private GetConfigurationResponse lastConfigResult; private GetConfigurationResponse lastConfigResult;
@ -47,31 +48,32 @@ public class DynamicConfigurationManager {
private static final Logger logger = LoggerFactory.getLogger(DynamicConfigurationManager.class); private static final Logger logger = LoggerFactory.getLogger(DynamicConfigurationManager.class);
public DynamicConfigurationManager(String application, String environment, String configurationName) { public DynamicConfigurationManager(String application, String environment, String configurationName,
Class<T> configurationClass) {
this(AppConfigClient.builder() this(AppConfigClient.builder()
.overrideConfiguration(ClientOverrideConfiguration.builder() .overrideConfiguration(ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofMillis(10000)) .apiCallTimeout(Duration.ofMillis(10000))
.apiCallAttemptTimeout(Duration.ofMillis(10000)).build()) .apiCallAttemptTimeout(Duration.ofMillis(10000)).build())
/* To specify specific credential provider:
https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html
*/
.build(), .build(),
application, environment, configurationName, UUID.randomUUID().toString()); application, environment, configurationName, UUID.randomUUID().toString(), configurationClass);
} }
@VisibleForTesting @VisibleForTesting
public DynamicConfigurationManager(AppConfigClient appConfigClient, String application, String environment, public DynamicConfigurationManager(AppConfigClient appConfigClient, String application, String environment,
String configurationName, String clientId) { String configurationName, String clientId, Class<T> configurationClass) {
this.appConfigClient = appConfigClient; this.appConfigClient = appConfigClient;
this.application = application; this.application = application;
this.environment = environment; this.environment = environment;
this.configurationName = configurationName; this.configurationName = configurationName;
this.clientId = clientId; this.clientId = clientId;
this.configurationClass = configurationClass;
} }
public DynamicConfiguration getConfiguration() { public T getConfiguration() {
synchronized (this) { synchronized (this) {
while (!initialized) Util.wait(this); while (!initialized) {
Util.wait(this);
}
} }
return configuration.get(); return configuration.get();
@ -101,25 +103,26 @@ public class DynamicConfigurationManager {
workerThread.start(); workerThread.start();
} }
private Optional<DynamicConfiguration> retrieveDynamicConfiguration() throws JsonProcessingException { private Optional<T> retrieveDynamicConfiguration() throws JsonProcessingException {
final String previousVersion = lastConfigResult != null ? lastConfigResult.configurationVersion() : null; final String previousVersion = lastConfigResult != null ? lastConfigResult.configurationVersion() : null;
lastConfigResult = appConfigClient.getConfiguration(GetConfigurationRequest.builder() lastConfigResult = appConfigClient.getConfiguration(GetConfigurationRequest.builder()
.application(application) .application(application)
.environment(environment) .environment(environment)
.configuration(configurationName) .configuration(configurationName)
.clientId(clientId) .clientId(clientId)
.clientConfigurationVersion(previousVersion) .clientConfigurationVersion(previousVersion)
.build()); .build());
final Optional<DynamicConfiguration> maybeDynamicConfiguration; final Optional<T> maybeDynamicConfiguration;
if (!StringUtils.equals(lastConfigResult.configurationVersion(), previousVersion)) { if (!StringUtils.equals(lastConfigResult.configurationVersion(), previousVersion)) {
logger.info("Received new config version: {}", lastConfigResult.configurationVersion()); logger.info("Received new config version: {}", lastConfigResult.configurationVersion());
maybeDynamicConfiguration = maybeDynamicConfiguration =
parseConfiguration( parseConfiguration(
StandardCharsets.UTF_8.decode(lastConfigResult.content().asByteBuffer().asReadOnlyBuffer()).toString()); StandardCharsets.UTF_8.decode(lastConfigResult.content().asByteBuffer().asReadOnlyBuffer()).toString(),
configurationClass);
} else { } else {
// No change since last version // No change since last version
maybeDynamicConfiguration = Optional.empty(); maybeDynamicConfiguration = Optional.empty();
@ -129,12 +132,12 @@ public class DynamicConfigurationManager {
} }
@VisibleForTesting @VisibleForTesting
public static Optional<DynamicConfiguration> parseConfiguration(final String configurationYaml) public static <T> Optional<T> parseConfiguration(final String configurationYaml, final Class<T> configurationClass)
throws JsonProcessingException { throws JsonProcessingException {
final DynamicConfiguration configuration = OBJECT_MAPPER.readValue(configurationYaml, DynamicConfiguration.class); final T configuration = OBJECT_MAPPER.readValue(configurationYaml, configurationClass);
final Set<ConstraintViolation<DynamicConfiguration>> violations = VALIDATOR.validate(configuration); final Set<ConstraintViolation<T>> violations = VALIDATOR.validate(configuration);
final Optional<DynamicConfiguration> maybeDynamicConfiguration; final Optional<T> maybeDynamicConfiguration;
if (violations.isEmpty()) { if (violations.isEmpty()) {
maybeDynamicConfiguration = Optional.of(configuration); maybeDynamicConfiguration = Optional.of(configuration);
@ -146,10 +149,10 @@ public class DynamicConfigurationManager {
return maybeDynamicConfiguration; return maybeDynamicConfiguration;
} }
private DynamicConfiguration retrieveInitialDynamicConfiguration() { private T retrieveInitialDynamicConfiguration() {
for (;;) { for (;;) {
try { try {
final Optional<DynamicConfiguration> maybeDynamicConfiguration = retrieveDynamicConfiguration(); final Optional<T> maybeDynamicConfiguration = retrieveDynamicConfiguration();
if (maybeDynamicConfiguration.isPresent()) { if (maybeDynamicConfiguration.isPresent()) {
return maybeDynamicConfiguration.get(); return maybeDynamicConfiguration.get();

View File

@ -21,6 +21,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.entities.MessageProtos; import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.util.Constants; import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
@ -53,7 +54,7 @@ public class MessagePersister implements Managed {
private static final Logger logger = LoggerFactory.getLogger(MessagePersister.class); private static final Logger logger = LoggerFactory.getLogger(MessagePersister.class);
public MessagePersister(final MessagesCache messagesCache, final MessagesManager messagesManager, final AccountsManager accountsManager, final DynamicConfigurationManager dynamicConfigurationManager, final Duration persistDelay) { public MessagePersister(final MessagesCache messagesCache, final MessagesManager messagesManager, final AccountsManager accountsManager, final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager, final Duration persistDelay) {
this.messagesCache = messagesCache; this.messagesCache = messagesCache;
this.messagesManager = messagesManager; this.messagesManager = messagesManager;
this.accountsManager = accountsManager; this.accountsManager = accountsManager;

View File

@ -11,6 +11,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser; import net.sourceforge.argparse4j.inf.Subparser;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
public class CheckDynamicConfigurationCommand extends Command { public class CheckDynamicConfigurationCommand extends Command {
@ -31,7 +32,7 @@ public class CheckDynamicConfigurationCommand extends Command {
public void run(final Bootstrap<?> bootstrap, final Namespace namespace) throws Exception { public void run(final Bootstrap<?> bootstrap, final Namespace namespace) throws Exception {
final Path path = Path.of(namespace.getString("file")); final Path path = Path.of(namespace.getString("file"));
if (DynamicConfigurationManager.parseConfiguration(Files.readString(path)).isPresent()) { if (DynamicConfigurationManager.parseConfiguration(Files.readString(path), DynamicConfiguration.class).isPresent()) {
System.out.println("Dynamic configuration file at " + path + " is valid"); System.out.println("Dynamic configuration file at " + path + " is valid");
} else { } else {
System.err.println("Dynamic configuration file at " + path + " is not valid"); System.err.println("Dynamic configuration file at " + path + " is not valid");

View File

@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.WhisperServerConfiguration; import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator; import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.metrics.PushLatencyManager; import org.whispersystems.textsecuregcm.metrics.PushLatencyManager;
import org.whispersystems.textsecuregcm.push.ClientPresenceManager; import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
@ -127,9 +128,9 @@ public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfigura
configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), new byte[0], configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), new byte[0],
false); false);
DynamicConfigurationManager dynamicConfigurationManager = new DynamicConfigurationManager( DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(), configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
configuration.getAppConfig().getConfigurationName()); configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
dynamicConfigurationManager.start(); dynamicConfigurationManager.start();
DynamoDbClient pendingAccountsDynamoDbClient = DynamoDbFromConfig.client(configuration.getPendingAccountsDynamoDbConfiguration(), DynamoDbClient pendingAccountsDynamoDbClient = DynamoDbFromConfig.client(configuration.getPendingAccountsDynamoDbConfiguration(),

View File

@ -27,6 +27,7 @@ import net.sourceforge.argparse4j.inf.Subparser;
import org.jdbi.v3.core.Jdbi; import org.jdbi.v3.core.Jdbi;
import org.whispersystems.textsecuregcm.WhisperServerConfiguration; import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator; import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.metrics.PushLatencyManager; import org.whispersystems.textsecuregcm.metrics.PushLatencyManager;
import org.whispersystems.textsecuregcm.push.ClientPresenceManager; import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster; import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
@ -131,9 +132,9 @@ public class SetUserDiscoverabilityCommand extends EnvironmentCommand<WhisperSer
configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), new byte[0], configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), new byte[0],
false); false);
DynamicConfigurationManager dynamicConfigurationManager = new DynamicConfigurationManager( DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(), configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
configuration.getAppConfig().getConfigurationName()); configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
dynamicConfigurationManager.start(); dynamicConfigurationManager.start();
DynamoDbClient pendingAccountsDynamoDbClient = DynamoDbFromConfig DynamoDbClient pendingAccountsDynamoDbClient = DynamoDbFromConfig

View File

@ -32,7 +32,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertFalse(emptyConfig.getExperimentEnrollmentConfiguration("test").isPresent()); assertFalse(emptyConfig.getExperimentEnrollmentConfiguration("test").isPresent());
} }
@ -52,7 +52,7 @@ class DynamicConfigurationTest {
" - 71618739-114c-4b1f-bb0d-6478a44eb600"; " - 71618739-114c-4b1f-bb0d-6478a44eb600";
final DynamicConfiguration config = final DynamicConfiguration config =
DynamicConfigurationManager.parseConfiguration(experimentConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(experimentConfigYaml, DynamicConfiguration.class).orElseThrow();
assertFalse(config.getExperimentEnrollmentConfiguration("unconfigured").isPresent()); assertFalse(config.getExperimentEnrollmentConfiguration("unconfigured").isPresent());
@ -80,7 +80,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertFalse(emptyConfig.getPreRegistrationEnrollmentConfiguration("test").isPresent()); assertFalse(emptyConfig.getPreRegistrationEnrollmentConfiguration("test").isPresent());
} }
@ -109,7 +109,7 @@ class DynamicConfigurationTest {
" - 47"; " - 47";
final DynamicConfiguration config = final DynamicConfiguration config =
DynamicConfigurationManager.parseConfiguration(experimentConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(experimentConfigYaml, DynamicConfiguration.class).orElseThrow();
assertFalse(config.getPreRegistrationEnrollmentConfiguration("unconfigured").isPresent()); assertFalse(config.getPreRegistrationEnrollmentConfiguration("unconfigured").isPresent());
@ -161,7 +161,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertNotNull(emptyConfig.getRemoteDeprecationConfiguration()); assertNotNull(emptyConfig.getRemoteDeprecationConfiguration());
} }
@ -181,7 +181,7 @@ class DynamicConfigurationTest {
" - 1.4.0-beta.2"; " - 1.4.0-beta.2";
final DynamicConfiguration config = final DynamicConfiguration config =
DynamicConfigurationManager.parseConfiguration(remoteDeprecationConfig).orElseThrow(); DynamicConfigurationManager.parseConfiguration(remoteDeprecationConfig, DynamicConfiguration.class).orElseThrow();
final DynamicRemoteDeprecationConfiguration remoteDeprecationConfiguration = config final DynamicRemoteDeprecationConfiguration remoteDeprecationConfiguration = config
.getRemoteDeprecationConfiguration(); .getRemoteDeprecationConfiguration();
@ -201,7 +201,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertFalse(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit()); assertFalse(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit());
} }
@ -212,7 +212,7 @@ class DynamicConfigurationTest {
" enforceUnsealedSenderRateLimit: true"; " enforceUnsealedSenderRateLimit: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(messageRateConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(messageRateConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit()); assertTrue(emptyConfig.getMessageRateConfiguration().isEnforceUnsealedSenderRateLimit());
} }
@ -223,7 +223,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getActiveFeatureFlags().isEmpty()); assertTrue(emptyConfig.getActiveFeatureFlags().isEmpty());
} }
@ -234,7 +234,7 @@ class DynamicConfigurationTest {
+ " - testFlag"; + " - testFlag";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(featureFlagYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(featureFlagYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getActiveFeatureFlags().contains("testFlag")); assertTrue(emptyConfig.getActiveFeatureFlags().contains("testFlag"));
} }
@ -245,7 +245,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getTwilioConfiguration().getNumbers().isEmpty()); assertTrue(emptyConfig.getTwilioConfiguration().getNumbers().isEmpty());
} }
@ -258,7 +258,7 @@ class DynamicConfigurationTest {
+ " - 2135551313"; + " - 2135551313";
final DynamicTwilioConfiguration config = final DynamicTwilioConfiguration config =
DynamicConfigurationManager.parseConfiguration(twilioConfigYaml).orElseThrow() DynamicConfigurationManager.parseConfiguration(twilioConfigYaml, DynamicConfiguration.class).orElseThrow()
.getTwilioConfiguration(); .getTwilioConfiguration();
assertEquals(List.of("2135551212", "2135551313"), config.getNumbers()); assertEquals(List.of("2135551212", "2135551313"), config.getNumbers());
@ -270,7 +270,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getPaymentsConfiguration().getAllowedCountryCodes().isEmpty()); assertTrue(emptyConfig.getPaymentsConfiguration().getAllowedCountryCodes().isEmpty());
} }
@ -282,7 +282,7 @@ class DynamicConfigurationTest {
+ " - 44"; + " - 44";
final DynamicPaymentsConfiguration config = final DynamicPaymentsConfiguration config =
DynamicConfigurationManager.parseConfiguration(paymentsConfigYaml).orElseThrow() DynamicConfigurationManager.parseConfiguration(paymentsConfigYaml, DynamicConfiguration.class).orElseThrow()
.getPaymentsConfiguration(); .getPaymentsConfiguration();
assertEquals(Set.of("44"), config.getAllowedCountryCodes()); assertEquals(Set.of("44"), config.getAllowedCountryCodes());
@ -294,7 +294,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertTrue(emptyConfig.getSignupCaptchaConfiguration().getCountryCodes().isEmpty()); assertTrue(emptyConfig.getSignupCaptchaConfiguration().getCountryCodes().isEmpty());
} }
@ -306,7 +306,7 @@ class DynamicConfigurationTest {
+ " - 1"; + " - 1";
final DynamicSignupCaptchaConfiguration config = final DynamicSignupCaptchaConfiguration config =
DynamicConfigurationManager.parseConfiguration(signupCaptchaConfig).orElseThrow() DynamicConfigurationManager.parseConfiguration(signupCaptchaConfig, DynamicConfiguration.class).orElseThrow()
.getSignupCaptchaConfiguration(); .getSignupCaptchaConfiguration();
assertEquals(Set.of("1"), config.getCountryCodes()); assertEquals(Set.of("1"), config.getCountryCodes());
@ -318,7 +318,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertThat(emptyConfig.getLimits().getUnsealedSenderNumber().getMaxCardinality()).isEqualTo(100); assertThat(emptyConfig.getLimits().getUnsealedSenderNumber().getMaxCardinality()).isEqualTo(100);
assertThat(emptyConfig.getLimits().getUnsealedSenderNumber().getTtl()).isEqualTo(Duration.ofDays(1)); assertThat(emptyConfig.getLimits().getUnsealedSenderNumber().getTtl()).isEqualTo(Duration.ofDays(1));
@ -332,7 +332,7 @@ class DynamicConfigurationTest {
+ " ttl: PT23H"; + " ttl: PT23H";
final CardinalityRateLimitConfiguration unsealedSenderNumber = final CardinalityRateLimitConfiguration unsealedSenderNumber =
DynamicConfigurationManager.parseConfiguration(limitsConfig).orElseThrow() DynamicConfigurationManager.parseConfiguration(limitsConfig, DynamicConfiguration.class).orElseThrow()
.getLimits().getUnsealedSenderNumber(); .getLimits().getUnsealedSenderNumber();
assertThat(unsealedSenderNumber.getMaxCardinality()).isEqualTo(99); assertThat(unsealedSenderNumber.getMaxCardinality()).isEqualTo(99);
@ -345,7 +345,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertThat(emptyConfig.getRateLimitChallengeConfiguration().getClientSupportedVersions()).isEmpty(); assertThat(emptyConfig.getRateLimitChallengeConfiguration().getClientSupportedVersions()).isEmpty();
assertThat(emptyConfig.getRateLimitChallengeConfiguration().isPreKeyLimitEnforced()).isFalse(); assertThat(emptyConfig.getRateLimitChallengeConfiguration().isPreKeyLimitEnforced()).isFalse();
@ -362,7 +362,7 @@ class DynamicConfigurationTest {
+ " DESKTOP: 5.0.0"; + " DESKTOP: 5.0.0";
DynamicRateLimitChallengeConfiguration rateLimitChallengeConfiguration = DynamicRateLimitChallengeConfiguration rateLimitChallengeConfiguration =
DynamicConfigurationManager.parseConfiguration(rateLimitChallengeConfig).orElseThrow() DynamicConfigurationManager.parseConfiguration(rateLimitChallengeConfig, DynamicConfiguration.class).orElseThrow()
.getRateLimitChallengeConfiguration(); .getRateLimitChallengeConfiguration();
final Map<ClientPlatform, Semver> clientSupportedVersions = rateLimitChallengeConfiguration.getClientSupportedVersions(); final Map<ClientPlatform, Semver> clientSupportedVersions = rateLimitChallengeConfiguration.getClientSupportedVersions();
@ -380,7 +380,7 @@ class DynamicConfigurationTest {
{ {
final String emptyConfigYaml = "test: true"; final String emptyConfigYaml = "test: true";
final DynamicConfiguration emptyConfig = final DynamicConfiguration emptyConfig =
DynamicConfigurationManager.parseConfiguration(emptyConfigYaml).orElseThrow(); DynamicConfigurationManager.parseConfiguration(emptyConfigYaml, DynamicConfiguration.class).orElseThrow();
assertThat(emptyConfig.getDirectoryReconcilerConfiguration().isEnabled()).isTrue(); assertThat(emptyConfig.getDirectoryReconcilerConfiguration().isEnabled()).isTrue();
} }
@ -391,7 +391,7 @@ class DynamicConfigurationTest {
+ " enabled: false"; + " enabled: false";
DynamicDirectoryReconcilerConfiguration directoryReconcilerConfiguration = DynamicDirectoryReconcilerConfiguration directoryReconcilerConfiguration =
DynamicConfigurationManager.parseConfiguration(directoryReconcilerConfig).orElseThrow() DynamicConfigurationManager.parseConfiguration(directoryReconcilerConfig, DynamicConfiguration.class).orElseThrow()
.getDirectoryReconcilerConfiguration(); .getDirectoryReconcilerConfiguration();
assertThat(directoryReconcilerConfiguration.isEnabled()).isFalse(); assertThat(directoryReconcilerConfiguration.isEnabled()).isFalse();

View File

@ -7,6 +7,7 @@ import static org.mockito.Mockito.when;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.appconfig.AppConfigClient; import software.amazon.awssdk.services.appconfig.AppConfigClient;
import software.amazon.awssdk.services.appconfig.model.GetConfigurationRequest; import software.amazon.awssdk.services.appconfig.model.GetConfigurationRequest;
@ -14,13 +15,13 @@ import software.amazon.awssdk.services.appconfig.model.GetConfigurationResponse;
public class DynamicConfigurationManagerTest { public class DynamicConfigurationManagerTest {
private DynamicConfigurationManager dynamicConfigurationManager; private DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;
private AppConfigClient appConfig; private AppConfigClient appConfig;
@Before @Before
public void setup() { public void setup() {
this.appConfig = mock(AppConfigClient.class); this.appConfig = mock(AppConfigClient.class);
this.dynamicConfigurationManager = new DynamicConfigurationManager(appConfig, "foo", "bar", "baz", "poof"); this.dynamicConfigurationManager = new DynamicConfigurationManager<>(appConfig, "foo", "bar", "baz", "poof", DynamicConfiguration.class);
} }
@Test @Test

View File

@ -21,8 +21,8 @@ import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
class DynamicRateLimitsTest { class DynamicRateLimitsTest {
private DynamicConfigurationManager dynamicConfig; private DynamicConfigurationManager<DynamicConfiguration> dynamicConfig;
private FaultTolerantRedisCluster redisCluster; private FaultTolerantRedisCluster redisCluster;
@BeforeEach @BeforeEach
void setup() { void setup() {