Skip to content

Commit 557f6d0

Browse files
committed
Extract InfobipSmsPriceEstimator into its own bean
1 parent 284bef8 commit 557f6d0

2 files changed

Lines changed: 52 additions & 20 deletions

File tree

src/main/java/org/signal/registration/analytics/infobip/InfobipSmsAttemptAnalyzer.java

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@
3030
import org.signal.registration.analytics.AttemptPendingAnalysis;
3131
import org.signal.registration.analytics.AttemptPendingAnalysisRepository;
3232
import org.signal.registration.analytics.Money;
33-
import org.signal.registration.cli.bigtable.BigtableInfobipDefaultSmsPricesRepository;
3433
import org.signal.registration.metrics.MetricsUtil;
3534
import org.signal.registration.sender.infobip.classic.InfobipSmsSender;
3635
import org.slf4j.Logger;
3736
import org.slf4j.LoggerFactory;
3837
import reactor.core.publisher.Flux;
3938
import reactor.core.publisher.Mono;
40-
import reactor.core.scheduler.Schedulers;
4139
import reactor.util.retry.Retry;
4240

4341
@Singleton
@@ -47,10 +45,10 @@ class InfobipSmsAttemptAnalyzer {
4745
private final Clock clock;
4846

4947
private final SmsApi infobipSmsApiClient;
50-
private final BigtableInfobipDefaultSmsPricesRepository defaultSmsPricesRepository;
51-
private final Currency defaultPriceCurrency;
48+
private final InfobipSmsPriceEstimator infobipSmsPriceEstimator;
5249
private final MeterRegistry meterRegistry;
5350
private final int pageSize;
51+
5452
private static final Logger logger = LoggerFactory.getLogger(InfobipSmsAttemptAnalyzer.class);
5553
private static final int MIN_MCC_MNC_LENGTH = 5;
5654
private static final int MAX_RETRIES = 10;
@@ -64,17 +62,15 @@ protected InfobipSmsAttemptAnalyzer(
6462
final ApplicationEventPublisher<AttemptAnalyzedEvent> attemptAnalyzedEventPublisher,
6563
final Clock clock,
6664
final SmsApi infobipSmsApiClient,
67-
final BigtableInfobipDefaultSmsPricesRepository defaultSmsPricesRepository,
68-
@Value("${analytics.infobip.sms.default-price-currency:USD}") final String defaultPriceCurrency,
65+
final InfobipSmsPriceEstimator infobipSmsPriceEstimator,
6966
final MeterRegistry meterRegistry,
7067
@Value("${analytics.infobip.sms.page-size}") final int pageSize) {
7168

7269
this.repository = repository;
7370
this.attemptAnalyzedEventPublisher = attemptAnalyzedEventPublisher;
7471
this.clock = clock;
7572
this.infobipSmsApiClient = infobipSmsApiClient;
76-
this.defaultSmsPricesRepository = defaultSmsPricesRepository;
77-
this.defaultPriceCurrency = Currency.getInstance(defaultPriceCurrency);
73+
this.infobipSmsPriceEstimator = infobipSmsPriceEstimator;
7874
this.meterRegistry = meterRegistry;
7975
this.pageSize = pageSize;
8076
}
@@ -94,17 +90,16 @@ protected void analyzeAttempts() {
9490
if (smsLogsByRemoteId.containsKey(attemptPendingAnalysis.getRemoteId())) {
9591
final SmsLog smsLog = smsLogsByRemoteId.get(attemptPendingAnalysis.getRemoteId());
9692
final MccMnc mccMnc = MccMnc.fromString(smsLog.getMccMnc());
97-
final Optional<Money> maybeEstimatedPriceByMccMnc = estimatePrice(mccMnc.toString());
9893

9994
attemptAnalysis = new AttemptAnalysis(
10095
extractPrice(smsLog),
101-
maybeEstimatedPriceByMccMnc.or(() -> estimatePrice(attemptPendingAnalysis.getRegion())),
96+
infobipSmsPriceEstimator.estimatePrice(attemptPendingAnalysis, mccMnc.mcc(), mccMnc.mnc()),
10297
Optional.ofNullable(mccMnc.mcc),
10398
Optional.ofNullable(mccMnc.mnc));
10499
} else {
105100
attemptAnalysis = new AttemptAnalysis(
106101
Optional.empty(),
107-
estimatePrice(attemptPendingAnalysis.getRegion()),
102+
infobipSmsPriceEstimator.estimatePrice(attemptPendingAnalysis, null, null),
108103
Optional.empty(),
109104
Optional.empty());
110105
}
@@ -161,11 +156,6 @@ private Optional<Money> extractPrice(final SmsLog smsLog) {
161156
: Optional.empty();
162157
}
163158

164-
private Optional<Money> estimatePrice(final String key) {
165-
return defaultSmsPricesRepository.get(key)
166-
.map(price -> new Money(price, defaultPriceCurrency));
167-
}
168-
169159
@VisibleForTesting
170160
record MccMnc(String mcc, String mnc) {
171161
private static final MccMnc EMPTY = new MccMnc(null, null);
@@ -184,9 +174,5 @@ static MccMnc fromString(@Nullable final String mccMnc) {
184174
// Mobile country code is always 3 digits: https://en.wikipedia.org/wiki/Mobile_country_code
185175
return new MccMnc(mccMnc.substring(0, 3), mccMnc.substring(3));
186176
}
187-
188-
public String toString() {
189-
return mcc + mnc;
190-
}
191177
}
192178
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 Signal Messenger, LLC
3+
* SPDX-License-Identifier: AGPL-3.0-only
4+
*/
5+
6+
package org.signal.registration.analytics.infobip;
7+
8+
import io.micronaut.context.annotation.Value;
9+
import jakarta.inject.Singleton;
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.signal.registration.analytics.AttemptPendingAnalysis;
12+
import org.signal.registration.analytics.Money;
13+
import org.signal.registration.analytics.PriceEstimator;
14+
import org.signal.registration.cli.bigtable.BigtableInfobipDefaultSmsPricesRepository;
15+
import javax.annotation.Nullable;
16+
import java.math.BigDecimal;
17+
import java.util.Currency;
18+
import java.util.Optional;
19+
20+
@Singleton
21+
public class InfobipSmsPriceEstimator implements PriceEstimator {
22+
23+
private final BigtableInfobipDefaultSmsPricesRepository defaultSmsPricesRepository;
24+
private final Currency defaultPriceCurrency;
25+
26+
public InfobipSmsPriceEstimator(final BigtableInfobipDefaultSmsPricesRepository defaultSmsPricesRepository,
27+
@Value("${analytics.infobip.sms.default-price-currency:USD}") final String defaultPriceCurrency) {
28+
29+
this.defaultSmsPricesRepository = defaultSmsPricesRepository;
30+
this.defaultPriceCurrency = Currency.getInstance(defaultPriceCurrency);
31+
}
32+
33+
@Override
34+
public Optional<Money> estimatePrice(final AttemptPendingAnalysis attemptPendingAnalysis,
35+
@Nullable final String mcc,
36+
@Nullable final String mnc) {
37+
38+
final Optional<BigDecimal> maybePriceFromMccMnc = StringUtils.isNoneBlank(mcc, mnc)
39+
? defaultSmsPricesRepository.get(mcc + mnc)
40+
: Optional.empty();
41+
42+
return maybePriceFromMccMnc
43+
.or(() -> defaultSmsPricesRepository.get(attemptPendingAnalysis.getRegion()))
44+
.map(price -> new Money(price, defaultPriceCurrency));
45+
}
46+
}

0 commit comments

Comments
 (0)