All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sportradar.unifiedodds.sdk.impl.apireaders.WhoAmIReader Maven / Gradle / Ivy
/*
* Copyright (C) Sportradar AG. See LICENSE for full license governing this code
*/
package com.sportradar.unifiedodds.sdk.impl.apireaders;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.ibm.icu.util.Calendar;
import com.sportradar.uf.sportsapi.datamodel.BookmakerDetails;
import com.sportradar.uf.sportsapi.datamodel.ResponseCode;
import com.sportradar.unifiedodds.sdk.SDKInternalConfiguration;
import com.sportradar.unifiedodds.sdk.cfg.Environment;
import com.sportradar.unifiedodds.sdk.exceptions.internal.DataProviderException;
import com.sportradar.unifiedodds.sdk.impl.DataProvider;
import com.sportradar.unifiedodds.sdk.impl.DataWrapper;
import com.sportradar.unifiedodds.sdk.impl.UnifiedFeedConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
public class WhoAmIReader {
private final static Logger logger = LoggerFactory.getLogger(WhoAmIReader.class);
private final DataProvider configDataProvider;
private final DataProvider productionDataProvider;
private final DataProvider integrationDataProvider;
private final SDKInternalConfiguration config;
private boolean dataFetched;
private boolean whoAmIValidated;
private Map associatedSdkMdcContextMap;
private com.sportradar.unifiedodds.sdk.entities.BookmakerDetails bookmakerDetails;
private Duration serverTimeDifference;
@Inject
public WhoAmIReader(
SDKInternalConfiguration config,
@Named("ConfigDataProvider") DataProvider configDataProvider,
@Named("ProductionDataProvider") DataProvider productionDataProvider,
@Named("IntegrationDataProvider") DataProvider integrationDataProvider) {
Preconditions.checkNotNull(config);
Preconditions.checkNotNull(productionDataProvider);
Preconditions.checkNotNull(integrationDataProvider);
this.config = config;
this.configDataProvider = configDataProvider;
this.productionDataProvider = productionDataProvider;
this.integrationDataProvider = integrationDataProvider;
this.serverTimeDifference = Duration.ofSeconds(0);
}
public int getBookmakerId() {
retrieveInfo();
return bookmakerDetails.getBookmakerId();
}
public Date getExpiry() {
retrieveInfo();
return bookmakerDetails.getExpireAt();
}
public String getVirtualHost() {
retrieveInfo();
return bookmakerDetails.getVirtualHost();
}
public ResponseCode getResponseCode() {
retrieveInfo();
return bookmakerDetails.getResponseCode();
}
public String getMessage() {
retrieveInfo();
return bookmakerDetails.getMessage();
}
public com.sportradar.unifiedodds.sdk.entities.BookmakerDetails getBookmakerDetails() {
retrieveInfo();
return bookmakerDetails;
}
public String getSdkContextDescription() {
Preconditions.checkState(whoAmIValidated);
return String.format("uf-sdk-%s%s",
bookmakerDetails.getBookmakerId(),
config.getSdkNodeId() == null ? "" : "-" + config.getSdkNodeId());
}
public Map getAssociatedSdkMdcContextMap() {
Preconditions.checkState(whoAmIValidated);
if (associatedSdkMdcContextMap == null) {
associatedSdkMdcContextMap = ImmutableMap.builder()
.put("uf-sdk-tag", getSdkContextDescription())
.build();
}
return associatedSdkMdcContextMap;
}
public void validateBookmakerDetails() {
retrieveInfo();
if (whoAmIValidated) {
return;
}
logger.info("Bookmaker validation initiated");
if (bookmakerDetails.getBookmakerId() != 0) {
logger.info("Client id: " + bookmakerDetails.getBookmakerId());
Date now = new Date();
Calendar cal = Calendar.getInstance();
if (now.after(bookmakerDetails.getExpireAt())) {
String errMsg = "Access token has expired (" + bookmakerDetails.getExpireAt() + ")";
logger.error(errMsg);
throw new IllegalStateException("Access token has expired (" + bookmakerDetails.getExpireAt() + ")");
}
cal.add(Calendar.DATE, 7);
if (cal.getTime().after(bookmakerDetails.getExpireAt())) {
logger.warn("Access token will expire during the next 7 days ({})", bookmakerDetails.getExpireAt());
}
logger.info("Token validation completed successfully, valid until: {}", bookmakerDetails.getExpireAt());
whoAmIValidated = true;
} else {
String errMsg;
if (ResponseCode.NOT_FOUND == bookmakerDetails.getResponseCode()) {
errMsg = String.format("Access token could not be validated. [%s]", bookmakerDetails.getResponseCode());
} else if (ResponseCode.FORBIDDEN == bookmakerDetails.getResponseCode()) {
errMsg = String.format("Looks like the access token has expired (or is invalid) - Access was denied. [msg: %s]", bookmakerDetails.getResponseCode());
} else {
errMsg = "Bookmaker token validation endpoint could not be reached, please verify your connection setup";
}
logger.error(errMsg);
throw new IllegalStateException(errMsg);
}
}
private void retrieveInfo() {
if (dataFetched) {
return;
}
BookmakerDetails bookmakerDetails = config.isReplaySession()
? fetchReplayBookmakerDetails()
: fetchBookmakerDetails();
dataFetched = true;
if (bookmakerDetails == null) {
throw new IllegalStateException("UOF SDK failed to fetch required bookmaker details, check logs for additional information");
}
this.bookmakerDetails = new com.sportradar.unifiedodds.sdk.impl.entities.BookmakerDetailsImpl(bookmakerDetails, serverTimeDifference);
}
private BookmakerDetails fetchBookmakerDetails() {
logger.info("Attempting bookmaker details fetch from the configured environment[{}], API: '{}'", config.getEnvironment(), config.getAPIHost());
BookmakerDetails bookmakerDetails = null;
try {
bookmakerDetails = provideBookmakerDetails(configDataProvider);
} catch (DataProviderException e) {
logger.warn("Bookmaker settings failed to fetch from the configured environment[{}], exc:", config.getEnvironment(), e);
}
if (isBookmakerResponseOk(bookmakerDetails)) {
return bookmakerDetails;
}
logger.warn("Bookmaker details fetch failed from the configured environment, checking token status on other available environments...");
if (!config.getAPIHost().equalsIgnoreCase(UnifiedFeedConstants.INTEGRATION_API_HOST)) {
attemptTokenValidationOn(Environment.Integration, UnifiedFeedConstants.INTEGRATION_API_HOST, integrationDataProvider);
}
if (!config.getAPIHost().equalsIgnoreCase(UnifiedFeedConstants.PRODUCTION_API_HOST)) {
attemptTokenValidationOn(Environment.Production, UnifiedFeedConstants.PRODUCTION_API_HOST, productionDataProvider);
}
logger.info("Bookmaker details fetch failed on all available environments");
return null;
}
private void attemptTokenValidationOn(Environment environment, String environmentApiUrl, DataProvider dataProvider) {
logger.info("Attempting bookmaker details fetch from the '{}' environment, API URL: '{}'", environment, environmentApiUrl);
BookmakerDetails bookmakerDetails = null;
try {
bookmakerDetails = provideBookmakerDetails(dataProvider);
} catch (DataProviderException e) {
logger.warn("Bookmaker settings failed to fetch from the '{}' environment with exc:", environment, e);
}
if (isBookmakerResponseOk(bookmakerDetails)) {
String message = String.format("The provided access token is for the '%s' environment but the SDK is configured to access the '%s' environment", environment, config.getEnvironment());
logger.error(message);
throw new IllegalStateException(message);
}
logger.info("Bookmaker details fetch failed on '{}'", environment);
}
private BookmakerDetails fetchReplayBookmakerDetails() {
logger.info("Fetching 'production' WhoAmI endpoint");
BookmakerDetails bookmakerDetails = null;
try {
bookmakerDetails = provideBookmakerDetails(productionDataProvider);
} catch (DataProviderException e) {
logger.warn("Replay WhoAmI fetch failed on 'production' with exc:", e);
}
if (bookmakerDetails != null && bookmakerDetails.getResponseCode() != ResponseCode.FORBIDDEN) {
return bookmakerDetails;
}
logger.info("Production API request failed, fetching 'integration' WhoAmI endpoint");
try {
bookmakerDetails = provideBookmakerDetails(integrationDataProvider);
} catch (DataProviderException e) {
logger.warn("Replay WhoAmI fetch failed on 'integration' with exc:", e);
}
if (bookmakerDetails != null && bookmakerDetails.getResponseCode() != ResponseCode.FORBIDDEN) {
logger.info("Integration WhoAmI request successful, switching SDK configuration to integration API");
config.updateApiHost(UnifiedFeedConstants.INTEGRATION_API_HOST);
}
return bookmakerDetails;
}
private BookmakerDetails provideBookmakerDetails(DataProvider provider) throws DataProviderException {
Preconditions.checkNotNull(provider);
DataWrapper dataWithAdditionalInfo = provider.getDataWithAdditionalInfo(Locale.ENGLISH);
validateLocalTimeWithServerTime(dataWithAdditionalInfo.getServerResponseTime());
return dataWithAdditionalInfo.getData();
}
private void validateLocalTimeWithServerTime(ZonedDateTime serverResponseTime) {
if (serverResponseTime == null) {
logger.warn("Could not validate local time against server time - SDK time related operations might cause issues");
return;
}
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime localisedServerTime = serverResponseTime.withZoneSameInstant(now.getZone());
long diff = ChronoUnit.SECONDS.between(localisedServerTime, now);
long absDiff = Math.abs(diff);
if (absDiff > 5) {
logger.error("Local time is out of sync for more than 5s({}s), SDK time related operations might cause issues", diff);
} else if (absDiff > 2) {
logger.warn("Local time is out of sync for more than 2s({}s), SDK time related operations might cause issues", diff);
}
serverTimeDifference = Duration.between(localisedServerTime.toInstant(), Instant.now());
}
private static boolean isBookmakerResponseOk(BookmakerDetails bookmakerDetails) {
return bookmakerDetails != null && bookmakerDetails.getResponseCode().equals(ResponseCode.OK);
}
}