Add tests for WhisperServerService#run

Additionally, `LocalWhisperServerService` may be used for integration testing.
This commit is contained in:
Chris Eager
2024-04-29 11:05:35 -05:00
committed by GitHub
parent b6f8bca361
commit 0e4be0c85a
84 changed files with 2156 additions and 552 deletions

View File

@@ -1,10 +1,14 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.concurrent.ScheduledExecutorService;
import javax.validation.constraints.NotEmpty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
public class AppConfigConfiguration {
@JsonTypeName("default")
public class AppConfigConfiguration implements DynamicConfigurationManagerFactory {
@JsonProperty
@NotEmpty
@@ -29,4 +33,11 @@ public class AppConfigConfiguration {
public String getConfigurationName() {
return configuration;
}
@Override
public <T> DynamicConfigurationManager<T> build(Class<T> klazz, ScheduledExecutorService scheduledExecutorService,
AwsCredentialsProvider awsCredentialsProvider) {
return new DynamicConfigurationManager<>(application, environment, configuration, awsCredentialsProvider, klazz,
scheduledExecutorService);
}
}

View File

@@ -4,12 +4,11 @@
*/
package org.whispersystems.textsecuregcm.configuration;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
public record AwsAttachmentsConfiguration(@NotNull SecretString accessKey,
@NotNull SecretString accessSecret,
public record AwsAttachmentsConfiguration(@NotNull @Valid StaticAwsCredentialsFactory credentials,
@NotBlank String bucket,
@NotBlank String region) {
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = DefaultAwsCredentialsFactory.class)
public interface AwsCredentialsProviderFactory extends Discoverable {
AwsCredentialsProvider build();
}

View File

@@ -32,9 +32,7 @@ public record BraintreeConfiguration(@NotBlank String merchantId,
@NotBlank String graphqlUrl,
@NotEmpty Map<String, String> merchantAccounts,
@NotNull @Valid CircuitBreakerConfiguration circuitBreaker,
@NotBlank String pubSubProject,
@NotBlank String pubSubTopic,
@NotBlank String pubSubCredentialConfiguration) {
@Valid @NotNull PubSubPublisherFactory pubSubPublisher) {
public BraintreeConfiguration {
if (circuitBreaker == null) {

View File

@@ -5,12 +5,11 @@
package org.whispersystems.textsecuregcm.configuration;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
public record CdnConfiguration(@NotNull SecretString accessKey,
@NotNull SecretString accessSecret,
public record CdnConfiguration(@NotNull @Valid StaticAwsCredentialsFactory credentials,
@NotBlank String bucket,
@NotBlank String region) {
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import io.micrometer.statsd.StatsdConfig;
import java.time.Duration;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = DogstatsdConfiguration.class)
public interface DatadogConfiguration extends StatsdConfig, Discoverable {
String getEnvironment();
Duration getShutdownWaitDuration();
}

View File

@@ -0,0 +1,18 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeName;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider;
@JsonTypeName("default")
public record DefaultAwsCredentialsFactory() implements AwsCredentialsProviderFactory {
public AwsCredentialsProvider build() {
return WebIdentityTokenFileCredentialsProvider.create();
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.api.gax.batching.BatchingSettings;
import com.google.api.gax.batching.FlowControlSettings;
import com.google.api.gax.batching.FlowController;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.ExternalAccountCredentials;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.cloud.pubsub.v1.PublisherInterface;
import com.google.pubsub.v1.TopicName;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.validation.constraints.NotBlank;
@JsonTypeName("default")
public record DefaultPubSubPublisherFactory(@NotBlank String project,
@NotBlank String topic,
@NotBlank String credentialConfiguration) implements
PubSubPublisherFactory {
@Override
public PublisherInterface build() throws IOException {
final FlowControlSettings flowControlSettings = FlowControlSettings.newBuilder()
.setLimitExceededBehavior(FlowController.LimitExceededBehavior.ThrowException)
.setMaxOutstandingElementCount(100L)
.setMaxOutstandingRequestBytes(16 * 1024 * 1024L) // 16MB
.build();
final BatchingSettings batchingSettings = BatchingSettings.newBuilder()
.setFlowControlSettings(flowControlSettings)
.setDelayThreshold(org.threeten.bp.Duration.ofMillis(10))
// These thresholds are actually the default, setting them explicitly since creating a custom batchingSettings resets them
.setElementCountThreshold(100L)
.setRequestByteThreshold(5000L)
.build();
try (final ByteArrayInputStream credentialConfigInputStream =
new ByteArrayInputStream(credentialConfiguration.getBytes(StandardCharsets.UTF_8))) {
return Publisher.newBuilder(
TopicName.of(project, topic))
.setCredentialsProvider(
FixedCredentialsProvider.create(ExternalAccountCredentials.fromStream(credentialConfigInputStream)))
.setBatchingSettings(batchingSettings)
.build();
}
}
}

View File

@@ -6,13 +6,14 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.micrometer.statsd.StatsdConfig;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.micrometer.statsd.StatsdFlavor;
import java.time.Duration;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
public class DogstatsdConfiguration implements StatsdConfig {
@JsonTypeName("default")
public class DogstatsdConfiguration implements DatadogConfiguration {
@JsonProperty
@NotNull
@@ -31,6 +32,7 @@ public class DogstatsdConfiguration implements StatsdConfig {
return step;
}
@Override
public String getEnvironment() {
return environment;
}
@@ -50,4 +52,9 @@ public class DogstatsdConfiguration implements StatsdConfig {
public String host() {
return host;
}
@Override
public Duration getShutdownWaitDuration() {
return step().plus(step.dividedBy(2));
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import java.util.concurrent.ScheduledExecutorService;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = AppConfigConfiguration.class)
public interface DynamicConfigurationManagerFactory extends Discoverable {
<T> DynamicConfigurationManager<T> build(Class<T> configurationClass,
ScheduledExecutorService scheduledExecutorService, AwsCredentialsProvider awsCredentialsProvider);
}

View File

@@ -9,11 +9,20 @@ import java.time.Duration;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import com.fasterxml.jackson.annotation.JsonTypeName;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
@JsonTypeName("default")
public record DynamoDbClientConfiguration(@NotBlank String region,
@NotNull Duration clientExecutionTimeout,
@NotNull Duration clientRequestTimeout,
@Positive int maxConnections) {
@Positive int maxConnections) implements DynamoDbClientFactory {
public DynamoDbClientConfiguration {
if (clientExecutionTimeout == null) {
@@ -28,4 +37,32 @@ public record DynamoDbClientConfiguration(@NotBlank String region,
maxConnections = 50;
}
}
@Override
public DynamoDbClient buildSyncClient(final AwsCredentialsProvider credentialsProvider) {
return DynamoDbClient.builder()
.region(Region.of(region()))
.credentialsProvider(credentialsProvider)
.overrideConfiguration(ClientOverrideConfiguration.builder()
.apiCallTimeout(clientExecutionTimeout())
.apiCallAttemptTimeout(clientRequestTimeout())
.build())
.httpClientBuilder(AwsCrtHttpClient.builder()
.maxConcurrency(maxConnections()))
.build();
}
@Override
public DynamoDbAsyncClient buildAsyncClient(final AwsCredentialsProvider credentialsProvider) {
return DynamoDbAsyncClient.builder()
.region(Region.of(region()))
.credentialsProvider(credentialsProvider)
.overrideConfiguration(ClientOverrideConfiguration.builder()
.apiCallTimeout(clientExecutionTimeout())
.apiCallAttemptTimeout(clientRequestTimeout())
.build())
.httpClientBuilder(NettyNioAsyncHttpClient.builder()
.maxConcurrency(maxConnections()))
.build();
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = DynamoDbClientConfiguration.class)
public interface DynamoDbClientFactory extends Discoverable {
DynamoDbClient buildSyncClient(AwsCredentialsProvider awsCredentialsProvider);
DynamoDbAsyncClient buildAsyncClient(AwsCredentialsProvider awsCredentialsProvider);
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import io.lettuce.core.resource.ClientResources;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = RedisClusterConfiguration.class)
public interface FaultTolerantRedisClusterFactory extends Discoverable {
FaultTolerantRedisCluster build(String name, ClientResources.Builder clientResourcesBuilder);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import org.whispersystems.textsecuregcm.captcha.HCaptchaClient;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import java.util.concurrent.ScheduledExecutorService;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = HCaptchaConfiguration.class)
public interface HCaptchaClientFactory extends Discoverable {
HCaptchaClient build(ScheduledExecutorService retryExecutor,
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager);
}

View File

@@ -7,9 +7,15 @@ package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.whispersystems.textsecuregcm.captcha.HCaptchaClient;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import java.util.concurrent.ScheduledExecutorService;
public class HCaptchaConfiguration {
@JsonTypeName("default")
public class HCaptchaConfiguration implements HCaptchaClientFactory {
@JsonProperty
@NotNull
@@ -36,4 +42,14 @@ public class HCaptchaConfiguration {
return retry;
}
@Override
public HCaptchaClient build(final ScheduledExecutorService retryExecutor,
final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager) {
return new HCaptchaClient(
apiKey.value(),
retryExecutor,
circuitBreaker,
retry,
dynamicConfigurationManager);
}
}

View File

@@ -15,12 +15,12 @@ public class MessageCacheConfiguration {
@JsonProperty
@NotNull
@Valid
private RedisClusterConfiguration cluster;
private FaultTolerantRedisClusterFactory cluster;
@JsonProperty
private int persistDelayMinutes = 10;
public RedisClusterConfiguration getRedisClusterConfiguration() {
public FaultTolerantRedisClusterFactory getRedisClusterConfiguration() {
return cluster;
}

View File

@@ -5,18 +5,23 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.whispersystems.textsecuregcm.s3.S3ObjectMonitor;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import javax.validation.constraints.NotBlank;
@JsonTypeName("default")
public record MonitoredS3ObjectConfiguration(
@NotBlank String s3Region,
@NotBlank String s3Bucket,
@NotBlank String objectKey,
Long maxSize,
Duration refreshInterval) {
Duration refreshInterval) implements S3ObjectMonitorFactory {
private static long DEFAULT_MAXSIZE = 16*1024*1024;
private static Duration DEFAULT_REFRESH_INTERVAL = Duration.ofMinutes(5);
private static final long DEFAULT_MAXSIZE = 16 * 1024 * 1024;
private static final Duration DEFAULT_REFRESH_INTERVAL = Duration.ofMinutes(5);
public MonitoredS3ObjectConfiguration {
if (maxSize == null) {
@@ -26,4 +31,12 @@ public record MonitoredS3ObjectConfiguration(
refreshInterval = DEFAULT_REFRESH_INTERVAL;
}
}
@Override
public S3ObjectMonitor build(final AwsCredentialsProvider awsCredentialsProvider,
final ScheduledExecutorService refreshExecutorService) {
return new S3ObjectMonitor(awsCredentialsProvider, s3Region, s3Bucket, objectKey, maxSize, refreshExecutorService,
refreshInterval);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeName;
import java.net.http.HttpClient;
import java.util.Map;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
import org.whispersystems.textsecuregcm.currency.CoinMarketCapClient;
import org.whispersystems.textsecuregcm.currency.FixerClient;
@JsonTypeName("default")
public record PaymentsServiceClientsConfiguration(@NotNull SecretString coinMarketCapApiKey,
@NotNull SecretString fixerApiKey,
@NotEmpty Map<@NotBlank String, Integer> coinMarketCapCurrencyIds) implements
PaymentsServiceClientsFactory {
@Override
public FixerClient buildFixerClient(final HttpClient httpClient) {
return new FixerClient(httpClient, fixerApiKey.value());
}
@Override
public CoinMarketCapClient buildCoinMarketCapClient(final HttpClient httpClient) {
return new CoinMarketCapClient(httpClient, coinMarketCapApiKey.value(), coinMarketCapCurrencyIds);
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import org.whispersystems.textsecuregcm.currency.CoinMarketCapClient;
import org.whispersystems.textsecuregcm.currency.FixerClient;
import java.net.http.HttpClient;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = PaymentsServiceClientsConfiguration.class)
public interface PaymentsServiceClientsFactory extends Discoverable {
FixerClient buildFixerClient(final HttpClient httpClient);
CoinMarketCapClient buildCoinMarketCapClient(HttpClient httpClient);
}

View File

@@ -5,17 +5,15 @@
package org.whispersystems.textsecuregcm.configuration;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotBlank;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretBytes;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
import java.util.List;
public record PaymentsServiceConfiguration(@NotNull SecretBytes userAuthenticationTokenSharedSecret,
@NotNull SecretString coinMarketCapApiKey,
@NotNull SecretString fixerApiKey,
@NotEmpty Map<@NotBlank String, Integer> coinMarketCapCurrencyIds,
@NotEmpty List<String> paymentCurrencies) {
@NotEmpty List<String> paymentCurrencies,
@NotNull @Valid PaymentsServiceClientsFactory externalClients) {
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
public record ProvisioningConfiguration(@Valid @NotNull SingletonRedisClientFactory pubsub,
@Valid @NotNull CircuitBreakerConfiguration circuitBreaker) {
public ProvisioningConfiguration {
if (circuitBreaker == null) {
circuitBreaker = new CircuitBreakerConfiguration();
}
}
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.google.cloud.pubsub.v1.PublisherInterface;
import io.dropwizard.jackson.Discoverable;
import java.io.IOException;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = DefaultPubSubPublisherFactory.class)
public interface PubSubPublisherFactory extends Discoverable {
PublisherInterface build() throws IOException;
}

View File

@@ -6,13 +6,17 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.common.annotations.VisibleForTesting;
import io.lettuce.core.resource.ClientResources;
import java.time.Duration;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.Duration;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
public class RedisClusterConfiguration {
@JsonTypeName("default")
public class RedisClusterConfiguration implements FaultTolerantRedisClusterFactory {
@JsonProperty
@NotEmpty
@@ -32,6 +36,11 @@ public class RedisClusterConfiguration {
@Valid
private RetryConfiguration retry = new RetryConfiguration();
@VisibleForTesting
void setConfigurationUri(final String configurationUri) {
this.configurationUri = configurationUri;
}
public String getConfigurationUri() {
return configurationUri;
}
@@ -47,4 +56,9 @@ public class RedisClusterConfiguration {
public RetryConfiguration getRetryConfiguration() {
return retry;
}
@Override
public FaultTolerantRedisCluster build(final String name, final ClientResources.Builder clientResourcesBuilder) {
return new FaultTolerantRedisCluster(name, this, clientResourcesBuilder);
}
}

View File

@@ -6,13 +6,16 @@ package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.lettuce.core.RedisClient;
import io.lettuce.core.resource.ClientResources;
import java.time.Duration;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.whispersystems.textsecuregcm.redis.RedisUriUtil;
public class RedisConfiguration {
@JsonTypeName("default")
public class RedisConfiguration implements SingletonRedisClientFactory {
@JsonProperty
@NotEmpty
@@ -22,11 +25,6 @@ public class RedisConfiguration {
@NotNull
private Duration timeout = Duration.ofSeconds(1);
@JsonProperty
@NotNull
@Valid
private CircuitBreakerConfiguration circuitBreaker = new CircuitBreakerConfiguration();
public String getUri() {
return uri;
}
@@ -35,7 +33,12 @@ public class RedisConfiguration {
return timeout;
}
public CircuitBreakerConfiguration getCircuitBreakerConfiguration() {
return circuitBreaker;
@Override
public RedisClient build(final ClientResources clientResources) {
final RedisClient redisClient = RedisClient.create(clientResources,
RedisUriUtil.createRedisUriWithTimeout(uri, timeout));
redisClient.setDefaultTimeout(timeout);
return redisClient;
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.core.setup.Environment;
import io.dropwizard.jackson.Discoverable;
import org.whispersystems.textsecuregcm.registration.RegistrationServiceClient;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = RegistrationServiceConfiguration.class)
public interface RegistrationServiceClientFactory extends Discoverable {
RegistrationServiceClient build(Environment environment, Executor callbackExecutor,
ScheduledExecutorService identityRefreshExecutor);
}

View File

@@ -1,10 +1,35 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.dropwizard.core.setup.Environment;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.validation.constraints.NotBlank;
import org.whispersystems.textsecuregcm.registration.IdentityTokenCallCredentials;
import org.whispersystems.textsecuregcm.registration.RegistrationServiceClient;
@JsonTypeName("default")
public record RegistrationServiceConfiguration(@NotBlank String host,
int port,
@NotBlank String credentialConfigurationJson,
@NotBlank String identityTokenAudience,
@NotBlank String registrationCaCertificate) {
@NotBlank String registrationCaCertificate) implements
RegistrationServiceClientFactory {
@Override
public RegistrationServiceClient build(final Environment environment, final Executor callbackExecutor,
final ScheduledExecutorService identityRefreshExecutor) {
try {
final IdentityTokenCallCredentials callCredentials = IdentityTokenCallCredentials.fromCredentialConfig(
credentialConfigurationJson, identityTokenAudience, identityRefreshExecutor);
environment.lifecycle().manage(callCredentials);
return new RegistrationServiceClient(host, port, callCredentials, registrationCaCertificate,
identityRefreshExecutor);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import org.whispersystems.textsecuregcm.s3.S3ObjectMonitor;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import java.util.concurrent.ScheduledExecutorService;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = MonitoredS3ObjectConfiguration.class)
public interface S3ObjectMonitorFactory extends Discoverable {
S3ObjectMonitor build(AwsCredentialsProvider awsCredentialsProvider,
ScheduledExecutorService refreshExecutorService);
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.dropwizard.jackson.Discoverable;
import io.lettuce.core.RedisClient;
import io.lettuce.core.resource.ClientResources;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = RedisConfiguration.class)
public interface SingletonRedisClientFactory extends Discoverable {
RedisClient build(ClientResources clientResources);
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.whispersystems.textsecuregcm.configuration.secrets.SecretString;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import javax.validation.constraints.NotNull;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = StaticAwsCredentialsFactory.class)
@JsonTypeName("static")
public record StaticAwsCredentialsFactory(@NotNull SecretString accessKeyId,
@NotNull SecretString secretAccessKey) implements
AwsCredentialsProviderFactory {
@Override
public AwsCredentialsProvider build() {
return StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKeyId.value(), secretAccessKey.value()));
}
}