Skip to content

Commit

Permalink
Geo Lookup Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoxaAntoxic committed Mar 14, 2024
1 parent e7fec81 commit 4100bba
Show file tree
Hide file tree
Showing 23 changed files with 664 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.prebid.server.auction;

import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Device;
import com.iab.openrtb.request.Geo;
import io.vertx.core.Future;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.execution.Timeout;
import org.prebid.server.geolocation.GeoLocationService;
import org.prebid.server.geolocation.model.GeoInfo;
import org.prebid.server.metric.Metrics;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountSettings;

import java.util.Objects;
import java.util.Optional;

public class GeoLocationServiceWrapper {

private static final Logger logger = LoggerFactory.getLogger(GeoLocationServiceWrapper.class);

private final GeoLocationService geoLocationService;
private final Metrics metrics;

public GeoLocationServiceWrapper(GeoLocationService geoLocationService, Metrics metrics) {
this.geoLocationService = geoLocationService;
this.metrics = Objects.requireNonNull(metrics);
}

//todo: account settings will work as expected if the default account resolving refactoring is done
public Future<GeoInfo> lookup(AuctionContext auctionContext) {
final Account account = auctionContext.getAccount();
final BidRequest bidRequest = auctionContext.getBidRequest();
final Timeout timeout = auctionContext.getTimeoutContext().getTimeout();

final Boolean isGeoLookupEnabled = Optional.ofNullable(account.getSettings())
.map(AccountSettings::getGeoLookup)
.map(BooleanUtils::isTrue)
.orElse(false);

final Device device = bidRequest.getDevice();

return isGeoLookupEnabled
? doLookup(getIpAddress(device), getCountry(device), timeout).otherwiseEmpty()
: Future.succeededFuture();
}

public Future<GeoInfo> doLookup(String ipAddress, String requestCountry, Timeout timeout) {
if (geoLocationService == null || StringUtils.isNotBlank(requestCountry) || ipAddress == null) {
return Future.failedFuture("Geolocation lookup is skipped");
}
return geoLocationService.lookup(ipAddress, timeout)
.onSuccess(geoInfo -> metrics.updateGeoLocationMetric(true))
.onFailure(this::logError);
}

private String getCountry(Device device) {
return Optional.ofNullable(device)
.map(Device::getGeo)
.map(Geo::getCountry)
.filter(StringUtils::isNotBlank)
.orElse(null);
}

private String getIpAddress(Device device) {
final Optional<Device> optionalDevice = Optional.ofNullable(device);
return optionalDevice.map(Device::getIp)
.filter(StringUtils::isNotBlank)
.or(() -> optionalDevice
.map(Device::getIpv6)
.filter(StringUtils::isNotBlank))
.orElse(null);
}

private void logError(Throwable error) {
final String message = "Geolocation lookup failed: " + error.getMessage();
logger.warn(message);
logger.debug(message, error);

metrics.updateGeoLocationMetric(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class AuctionContext {

ActivityInfrastructure activityInfrastructure;

@JsonIgnore
GeoInfo geoInfo;

HookExecutionContext hookExecutionContext;
Expand Down Expand Up @@ -123,6 +124,12 @@ public AuctionContext with(DebugContext debugContext) {
.build();
}

public AuctionContext with(GeoInfo geoInfo) {
return this.toBuilder()
.geoInfo(geoInfo)
.build();
}

public AuctionContext withRequestRejected() {
return this.toBuilder()
.requestRejected(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ public Future<PrivacyContext> contextFrom(AuctionContext auctionContext) {
final Privacy strippedPrivacy = stripPrivacy(initialPrivacy, auctionContext);
final Device device = bidRequest.getDevice();

//todo: pass geo info here as well
return tcfDefinerService.resolveTcfContext(
strippedPrivacy,
resolveAlpha2CountryCode(device),
resolveIpAddress(device, strippedPrivacy),
accountGdprConfig(account),
requestType,
requestLogInfo(requestType, bidRequest, account.getId()),
auctionContext.getTimeoutContext().getTimeout())
auctionContext.getTimeoutContext().getTimeout(),
auctionContext.getGeoInfo())
.map(tcfContext -> logWarnings(auctionContext.getDebugWarnings(), tcfContext))
.map(tcfContext -> PrivacyContext.of(strippedPrivacy, tcfContext, tcfContext.getIpAddress()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public Future<PrivacyContext> contextFrom(AuctionContext auctionContext) {
accountGdprConfig(account),
requestType,
requestLogInfo(requestType, bidRequest, account.getId()),
auctionContext.getTimeoutContext().getTimeout())
auctionContext.getTimeoutContext().getTimeout(),
auctionContext.getGeoInfo())
.map(tcfContext -> logWarnings(auctionContext.getDebugWarnings(), tcfContext))
.map(tcfContext -> PrivacyContext.of(privacy, tcfContext, tcfContext.getIpAddress()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.DebugResolver;
import org.prebid.server.auction.FpdResolver;
import org.prebid.server.auction.GeoLocationServiceWrapper;
import org.prebid.server.auction.ImplicitParametersExtractor;
import org.prebid.server.auction.OrtbTypesResolver;
import org.prebid.server.auction.PriceGranularity;
Expand Down Expand Up @@ -96,6 +97,7 @@ public class AmpRequestFactory {
private final AmpPrivacyContextFactory ampPrivacyContextFactory;
private final DebugResolver debugResolver;
private final JacksonMapper mapper;
private final GeoLocationServiceWrapper geoLocationServiceWrapper;

public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
StoredRequestProcessor storedRequestProcessor,
Expand All @@ -107,7 +109,8 @@ public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
FpdResolver fpdResolver,
AmpPrivacyContextFactory ampPrivacyContextFactory,
DebugResolver debugResolver,
JacksonMapper mapper) {
JacksonMapper mapper,
GeoLocationServiceWrapper geoLocationServiceWrapper) {

this.ortb2RequestFactory = Objects.requireNonNull(ortb2RequestFactory);
this.storedRequestProcessor = Objects.requireNonNull(storedRequestProcessor);
Expand All @@ -120,6 +123,7 @@ public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
this.debugResolver = Objects.requireNonNull(debugResolver);
this.ampPrivacyContextFactory = Objects.requireNonNull(ampPrivacyContextFactory);
this.mapper = Objects.requireNonNull(mapper);
this.geoLocationServiceWrapper = Objects.requireNonNull(geoLocationServiceWrapper);
}

/**
Expand All @@ -142,6 +146,12 @@ public Future<AuctionContext> fromRequest(RoutingContext routingContext, long st

.map(auctionContext -> auctionContext.with(debugResolver.debugContextFrom(auctionContext)))

.compose(auctionContext -> geoLocationServiceWrapper.lookup(auctionContext)
.map(auctionContext::with))

.map(auctionContext -> auctionContext.with(
ortb2RequestFactory.enrichBidRequestWithGeolocationData(auctionContext)))

.compose(auctionContext -> gppService.contextFrom(auctionContext)
.map(auctionContext::with))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.vertx.core.Future;
import io.vertx.ext.web.RoutingContext;
import org.prebid.server.auction.DebugResolver;
import org.prebid.server.auction.GeoLocationServiceWrapper;
import org.prebid.server.auction.ImplicitParametersExtractor;
import org.prebid.server.auction.InterstitialProcessor;
import org.prebid.server.auction.OrtbTypesResolver;
Expand Down Expand Up @@ -48,6 +49,7 @@ public class AuctionRequestFactory {
private final DebugResolver debugResolver;
private final JacksonMapper mapper;
private final OrtbTypesResolver ortbTypesResolver;
private final GeoLocationServiceWrapper geoLocationServiceWrapper;

private static final String ENDPOINT = Endpoint.openrtb2_auction.value();

Expand All @@ -63,7 +65,8 @@ public AuctionRequestFactory(long maxRequestSize,
OrtbTypesResolver ortbTypesResolver,
AuctionPrivacyContextFactory auctionPrivacyContextFactory,
DebugResolver debugResolver,
JacksonMapper mapper) {
JacksonMapper mapper,
GeoLocationServiceWrapper geoLocationServiceWrapper) {

this.maxRequestSize = maxRequestSize;
this.ortb2RequestFactory = Objects.requireNonNull(ortb2RequestFactory);
Expand All @@ -78,6 +81,7 @@ public AuctionRequestFactory(long maxRequestSize,
this.auctionPrivacyContextFactory = Objects.requireNonNull(auctionPrivacyContextFactory);
this.debugResolver = Objects.requireNonNull(debugResolver);
this.mapper = Objects.requireNonNull(mapper);
this.geoLocationServiceWrapper = Objects.requireNonNull(geoLocationServiceWrapper);
}

/**
Expand Down Expand Up @@ -106,6 +110,12 @@ public Future<AuctionContext> fromRequest(RoutingContext routingContext, long st

.map(auctionContext -> auctionContext.with(debugResolver.debugContextFrom(auctionContext)))

.compose(auctionContext -> geoLocationServiceWrapper.lookup(auctionContext)
.map(auctionContext::with))

.map(auctionContext -> auctionContext.with(
ortb2RequestFactory.enrichBidRequestWithGeolocationData(auctionContext)))

.compose(auctionContext -> gppService.contextFrom(auctionContext)
.map(auctionContext::with))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,33 @@ public Future<BidRequest> validateRequest(BidRequest bidRequest,
: Future.succeededFuture(bidRequest);
}

public BidRequest enrichBidRequestWithGeolocationData(AuctionContext auctionContext) {
final BidRequest bidRequest = auctionContext.getBidRequest();
final Device device = bidRequest.getDevice();
final GeoInfo geoInfo = auctionContext.getGeoInfo();
final Geo geo = ObjectUtil.getIfNotNull(device, Device::getGeo);

final UpdateResult<String> resolvedCountry = resolveCountry(geo, geoInfo);
final UpdateResult<String> resolvedRegion = resolveRegion(geo, geoInfo);

if (resolvedCountry.isUpdated() || resolvedRegion.isUpdated()) {
final Geo updatedGeo = Optional.ofNullable(geo)
.map(Geo::toBuilder)
.orElseGet(Geo::builder)
.country(resolvedCountry.getValue())
.region(resolvedRegion.getValue())
.build();

final Device updatedDevice = ObjectUtil.getIfNotNullOrDefault(device, Device::toBuilder, Device::builder)
.geo(updatedGeo)
.build();

return bidRequest.toBuilder().device(updatedDevice).build();
}

return bidRequest;
}

public BidRequest enrichBidRequestWithAccountAndPrivacyData(AuctionContext auctionContext) {
final BidRequest bidRequest = auctionContext.getBidRequest();
final Account account = auctionContext.getAccount();
Expand Down Expand Up @@ -613,9 +640,10 @@ private Device enrichDevice(Device device, PrivacyContext privacyContext) {
final boolean shouldUpdateIpV6 = ipV6 != null && !Objects.equals(ipV6InRequest, ipV6);

final Geo geo = ObjectUtil.getIfNotNull(device, Device::getGeo);
final GeoInfo geoInfo = privacyContext.getTcfContext().getGeoInfo();

final UpdateResult<String> resolvedCountry = resolveCountry(geo, privacyContext);
final UpdateResult<String> resolvedRegion = resolveRegion(geo, privacyContext);
final UpdateResult<String> resolvedCountry = resolveCountry(geo, geoInfo);
final UpdateResult<String> resolvedRegion = resolveRegion(geo, geoInfo);

if (shouldUpdateIpV4 || shouldUpdateIpV6 || resolvedCountry.isUpdated() || resolvedRegion.isUpdated()) {
final Device.DeviceBuilder deviceBuilder = device != null ? device.toBuilder() : Device.builder();
Expand Down Expand Up @@ -645,10 +673,9 @@ private Device enrichDevice(Device device, PrivacyContext privacyContext) {
return null;
}

private UpdateResult<String> resolveCountry(Geo geo, PrivacyContext privacyContext) {
final String countryInRequest = geo != null ? geo.getCountry() : null;
private UpdateResult<String> resolveCountry(Geo originalGeo, GeoInfo geoInfo) {
final String countryInRequest = originalGeo != null ? originalGeo.getCountry() : null;

final GeoInfo geoInfo = privacyContext.getTcfContext().getGeoInfo();
final String alpha2CountryCode = geoInfo != null ? geoInfo.getCountry() : null;
final String alpha3CountryCode = countryCodeMapper.mapToAlpha3(alpha2CountryCode);

Expand All @@ -657,11 +684,10 @@ private UpdateResult<String> resolveCountry(Geo geo, PrivacyContext privacyConte
: UpdateResult.unaltered(countryInRequest);
}

private static UpdateResult<String> resolveRegion(Geo geo, PrivacyContext privacyContext) {
final String regionInRequest = geo != null ? geo.getRegion() : null;
private static UpdateResult<String> resolveRegion(Geo originalGeo, GeoInfo geoInfo) {
final String regionInRequest = originalGeo != null ? originalGeo.getRegion() : null;
final String upperCasedRegionInRequest = StringUtils.upperCase(regionInRequest);

final GeoInfo geoInfo = privacyContext.getTcfContext().getGeoInfo();
final String region = geoInfo != null ? geoInfo.getRegion() : null;
final String upperCasedRegion = StringUtils.upperCase(region);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.DebugResolver;
import org.prebid.server.auction.GeoLocationServiceWrapper;
import org.prebid.server.auction.VideoStoredRequestProcessor;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.CachedDebugLog;
Expand Down Expand Up @@ -60,6 +61,7 @@ public class VideoRequestFactory {
private final AuctionPrivacyContextFactory auctionPrivacyContextFactory;
private final DebugResolver debugResolver;
private final JacksonMapper mapper;
private final GeoLocationServiceWrapper geoLocationServiceWrapper;

public VideoRequestFactory(int maxRequestSize,
boolean enforceStoredRequest,
Expand All @@ -70,7 +72,8 @@ public VideoRequestFactory(int maxRequestSize,
Ortb2ImplicitParametersResolver paramsResolver,
AuctionPrivacyContextFactory auctionPrivacyContextFactory,
DebugResolver debugResolver,
JacksonMapper mapper) {
JacksonMapper mapper,
GeoLocationServiceWrapper geoLocationServiceWrapper) {

this.enforceStoredRequest = enforceStoredRequest;
this.maxRequestSize = maxRequestSize;
Expand All @@ -81,6 +84,7 @@ public VideoRequestFactory(int maxRequestSize,
this.auctionPrivacyContextFactory = Objects.requireNonNull(auctionPrivacyContextFactory);
this.debugResolver = Objects.requireNonNull(debugResolver);
this.mapper = Objects.requireNonNull(mapper);
this.geoLocationServiceWrapper = Objects.requireNonNull(geoLocationServiceWrapper);

this.escapeLogCacheRegexPattern = StringUtils.isNotBlank(escapeLogCacheRegex)
? Pattern.compile(escapeLogCacheRegex)
Expand Down Expand Up @@ -123,6 +127,12 @@ public Future<WithPodErrors<AuctionContext>> fromRequest(RoutingContext routingC

.map(auctionContext -> auctionContext.with(debugResolver.debugContextFrom(auctionContext)))

.compose(auctionContext -> geoLocationServiceWrapper.lookup(auctionContext)
.map(auctionContext::with))

.map(auctionContext -> auctionContext.with(
ortb2RequestFactory.enrichBidRequestWithGeolocationData(auctionContext)))

.compose(auctionContext -> ortb2RequestFactory.activityInfrastructureFrom(auctionContext)
.map(auctionContext::with))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ private Future<DeviceInfo> lookupDeviceInfo(Device device) {
: Future.failedFuture("Device info is disabled by configuration");
}

//todo: to be removed
private Future<GeoInfo> lookupGeoInfo(Device device, Timeout timeout) {
return geoLocationService != null
? geoLocationService.lookup(ObjectUtils.defaultIfNull(device.getIp(), device.getIpv6()), timeout)
Expand Down
Loading

0 comments on commit 4100bba

Please sign in to comment.