-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Core: Transition PAAPI parameters #3670
base: master
Are you sure you want to change the base?
Changes from all commits
1810e87
abd3104
ebfa6df
e4a45ef
824d279
4b60b51
5bf42c6
81d8c77
5d6d88b
4ca36ba
9e492ba
8333f7c
9292540
b0c7f31
85208f5
3882deb
0841723
032f15f
5163003
7fd613e
bfffd2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
import org.prebid.server.auction.model.CachedDebugLog; | ||
import org.prebid.server.auction.model.CategoryMappingResult; | ||
import org.prebid.server.auction.model.MultiBidConfig; | ||
import org.prebid.server.auction.model.PaaFormat; | ||
import org.prebid.server.auction.model.TargetingInfo; | ||
import org.prebid.server.auction.model.debug.DebugContext; | ||
import org.prebid.server.auction.requestfactory.Ortb2ImplicitParametersResolver; | ||
|
@@ -61,6 +62,9 @@ | |
import org.prebid.server.identity.IdGeneratorType; | ||
import org.prebid.server.json.DecodeException; | ||
import org.prebid.server.json.JacksonMapper; | ||
import org.prebid.server.log.ConditionalLogger; | ||
import org.prebid.server.log.Logger; | ||
import org.prebid.server.log.LoggerFactory; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtImp; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtImpAuctionEnvironment; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid; | ||
|
@@ -82,6 +86,10 @@ | |
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtIgi; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgb; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtResponseDebug; | ||
import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInfrastructure; | ||
|
@@ -118,6 +126,9 @@ | |
|
||
public class BidResponseCreator { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(BidResponseCreator.class); | ||
private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); | ||
|
||
private static final String CACHE = "cache"; | ||
private static final String PREBID_EXT = "prebid"; | ||
private static final Integer DEFAULT_BID_LIMIT_MIN = 1; | ||
|
@@ -127,6 +138,7 @@ public class BidResponseCreator { | |
private static final String TARGETING_ENV_APP_VALUE = "mobile-app"; | ||
private static final String TARGETING_ENV_AMP_VALUE = "amp"; | ||
|
||
private final double logSamplingRate; | ||
private final CoreCacheService coreCacheService; | ||
private final BidderCatalog bidderCatalog; | ||
private final VastModifier vastModifier; | ||
|
@@ -146,7 +158,8 @@ public class BidResponseCreator { | |
private final String cachePath; | ||
private final String cacheAssetUrlTemplate; | ||
|
||
public BidResponseCreator(CoreCacheService coreCacheService, | ||
public BidResponseCreator(double logSamplingRate, | ||
CoreCacheService coreCacheService, | ||
BidderCatalog bidderCatalog, | ||
VastModifier vastModifier, | ||
EventsService eventsService, | ||
|
@@ -176,9 +189,11 @@ public BidResponseCreator(CoreCacheService coreCacheService, | |
this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl); | ||
this.cacheDefaultProperties = Objects.requireNonNull(cacheDefaultProperties); | ||
|
||
this.logSamplingRate = logSamplingRate; | ||
|
||
cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate()); | ||
cacheHost = Objects.requireNonNull(coreCacheService.getEndpointHost()); | ||
cachePath = Objects.requireNonNull(coreCacheService.getEndpointPath()); | ||
cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate()); | ||
} | ||
|
||
private static int validateTruncateAttrChars(int truncateAttrChars) { | ||
|
@@ -418,7 +433,8 @@ private List<BidderResponseInfo> toBidderResponseInfos(CategoryMappingResult cat | |
seatBid.getHttpCalls(), | ||
seatBid.getErrors(), | ||
seatBid.getWarnings(), | ||
seatBid.getFledgeAuctionConfigs()); | ||
seatBid.getFledgeAuctionConfigs(), | ||
seatBid.getIgi()); | ||
|
||
result.add(BidderResponseInfo.of(bidder, bidderSeatBidInfo, bidderResponse.getResponseTime())); | ||
} | ||
|
@@ -778,16 +794,20 @@ private ExtBidResponse toExtBidResponse(List<BidderResponseInfo> bidderResponseI | |
|
||
final Map<String, Integer> responseTimeMillis = toResponseTimes(bidderResponseInfos, cacheResult); | ||
|
||
final ExtBidResponseFledge extBidResponseFledge = toExtBidResponseFledge(bidderResponseInfos, auctionContext); | ||
final PaaResult paaResult = toPaaOutput(bidderResponseInfos, auctionContext); | ||
final List<ExtIgi> igi = paaResult.igis(); | ||
final ExtBidResponseFledge fledge = paaResult.fledge(); | ||
|
||
final ExtBidResponsePrebid prebid = toExtBidResponsePrebid( | ||
auctionTimestamp, auctionContext.getBidRequest(), extBidResponseFledge); | ||
auctionTimestamp, auctionContext.getBidRequest(), fledge); | ||
|
||
return ExtBidResponse.builder() | ||
.debug(extResponseDebug) | ||
.errors(errors) | ||
.warnings(warnings) | ||
.responsetimemillis(responseTimeMillis) | ||
.tmaxrequest(auctionContext.getBidRequest().getTmax()) | ||
.igi(igi) | ||
.prebid(prebid) | ||
.build(); | ||
} | ||
|
@@ -809,17 +829,107 @@ private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, | |
.build(); | ||
} | ||
|
||
private ExtBidResponseFledge toExtBidResponseFledge(List<BidderResponseInfo> bidderResponseInfos, | ||
AuctionContext auctionContext) { | ||
private PaaResult toPaaOutput(List<BidderResponseInfo> bidderResponseInfos, AuctionContext auctionContext) { | ||
final PaaFormat paaFormat = resolvePaaFormat(auctionContext); | ||
final List<ExtIgi> igis = extractIgis(bidderResponseInfos); | ||
final List<ExtIgi> extIgi = paaFormat == PaaFormat.IAB && !igis.isEmpty() ? igis : null; | ||
|
||
final List<FledgeAuctionConfig> fledgeConfigs = paaFormat == PaaFormat.ORIGINAL | ||
? toOriginalFledgeFormat(igis) | ||
: Collections.emptyList(); | ||
|
||
// TODO: Remove after transition period | ||
final List<Imp> imps = auctionContext.getBidRequest().getImp(); | ||
final List<FledgeAuctionConfig> fledgeConfigs = bidderResponseInfos.stream() | ||
.flatMap(bidderResponseInfo -> fledgeConfigsForBidder(bidderResponseInfo, imps)) | ||
final List<FledgeAuctionConfig> deprecatedFledgeConfigs = bidderResponseInfos.stream() | ||
.flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)) | ||
.toList(); | ||
|
||
final List<FledgeAuctionConfig> combinedFledgeConfigs = ListUtils.union(deprecatedFledgeConfigs, fledgeConfigs); | ||
final ExtBidResponseFledge extBidResponseFledge = combinedFledgeConfigs.isEmpty() | ||
? null | ||
: ExtBidResponseFledge.of(combinedFledgeConfigs); | ||
|
||
return new PaaResult(extIgi, extBidResponseFledge); | ||
} | ||
|
||
private List<ExtIgi> extractIgis(List<BidderResponseInfo> bidderResponseInfos) { | ||
return bidderResponseInfos.stream() | ||
.flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() | ||
.map(igi -> prepareExtIgi(igi, responseInfo.getBidder()))) | ||
.filter(Objects::nonNull) | ||
.toList(); | ||
} | ||
|
||
private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { | ||
if (igi == null) { | ||
return null; | ||
} | ||
|
||
final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); | ||
if (shouldDropIgb) { | ||
conditionalLogger.warn("ExtIgi with absent impId from bidder: " + bidder, logSamplingRate); | ||
} | ||
|
||
final List<ExtIgiIgs> updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder); | ||
final List<ExtIgiIgs> preparedIgs = updatedIgs.isEmpty() ? null : updatedIgs; | ||
final List<ExtIgiIgb> preparedIgb = shouldDropIgb ? null : igi.getIgb(); | ||
|
||
return ObjectUtils.anyNotNull(preparedIgs, preparedIgb) | ||
? igi.toBuilder().igs(preparedIgs).igb(preparedIgb).build() | ||
: null; | ||
} | ||
|
||
private List<ExtIgiIgs> prepareExtIgiIgs(List<ExtIgiIgs> igiIgs, String bidder) { | ||
if (igiIgs == null) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
final List<ExtIgiIgs> preparedIgiIgs = new ArrayList<>(); | ||
for (ExtIgiIgs extIgiIgs : igiIgs) { | ||
if (extIgiIgs == null) { | ||
continue; | ||
} | ||
|
||
if (StringUtils.isEmpty(extIgiIgs.getImpId())) { | ||
conditionalLogger.warn("ExtIgiIgs with absent impId from bidder: " + bidder, logSamplingRate); | ||
continue; | ||
} | ||
|
||
if (extIgiIgs.getConfig() == null) { | ||
conditionalLogger.warn("ExtIgiIgs with absent config from bidder: " + bidder, logSamplingRate); | ||
continue; | ||
} | ||
|
||
final ExtIgiIgs preparedExtIgiIgs = extIgiIgs.toBuilder() | ||
.ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I see, |
||
.build(); | ||
|
||
preparedIgiIgs.add(preparedExtIgiIgs); | ||
} | ||
|
||
return preparedIgiIgs; | ||
} | ||
|
||
private List<FledgeAuctionConfig> toOriginalFledgeFormat(List<ExtIgi> igis) { | ||
return igis.stream() | ||
.map(ExtIgi::getIgs) | ||
.flatMap(Collection::stream) | ||
.map(BidResponseCreator::extIgiIgsToFledgeConfig) | ||
.toList(); | ||
return !fledgeConfigs.isEmpty() ? ExtBidResponseFledge.of(fledgeConfigs) : null; | ||
} | ||
|
||
private Stream<FledgeAuctionConfig> fledgeConfigsForBidder(BidderResponseInfo bidderResponseInfo, List<Imp> imps) { | ||
private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs) { | ||
return FledgeAuctionConfig.builder() | ||
.bidder(extIgiIgs.getExt().getBidder()) | ||
.adapter(extIgiIgs.getExt().getAdapter()) | ||
.impId(extIgiIgs.getImpId()) | ||
.config(extIgiIgs.getConfig()) | ||
.build(); | ||
} | ||
|
||
private Stream<FledgeAuctionConfig> toDeprecatedFledgeConfigs(BidderResponseInfo bidderResponseInfo, | ||
List<Imp> imps) { | ||
|
||
return Optional.ofNullable(bidderResponseInfo.getSeatBid().getFledgeAuctionConfigs()) | ||
.stream() | ||
.flatMap(Collection::stream) | ||
|
@@ -836,10 +946,10 @@ private boolean validateFledgeConfig(FledgeAuctionConfig fledgeAuctionConfig, Li | |
return fledgeEnabled == ExtImpAuctionEnvironment.ON_DEVICE_IG_AUCTION_FLEDGE; | ||
} | ||
|
||
private static FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidderName) { | ||
private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidder) { | ||
return fledgeConfig.toBuilder() | ||
.bidder(bidderName) | ||
.adapter(bidderName) | ||
.bidder(bidder) | ||
.adapter(bidderCatalog.resolveBaseBidder(bidder)) | ||
.build(); | ||
} | ||
|
||
|
@@ -1154,6 +1264,17 @@ private static Map<String, Integer> toResponseTimes(Collection<BidderResponseInf | |
return responseTimeMillis; | ||
} | ||
|
||
private static PaaFormat resolvePaaFormat(AuctionContext auctionContext) { | ||
return Optional.of(auctionContext.getBidRequest()) | ||
.map(BidRequest::getExt) | ||
.map(ExtRequest::getPrebid) | ||
.map(ExtRequestPrebid::getPaaFormat) | ||
.or(() -> Optional.ofNullable(auctionContext.getAccount()) | ||
.map(Account::getAuction) | ||
.map(AccountAuctionConfig::getPaaFormat)) | ||
.orElse(PaaFormat.ORIGINAL); | ||
} | ||
|
||
/** | ||
* Returns {@link BidResponse} based on list of {@link BidderResponse}s and {@link CacheServiceResult}. | ||
*/ | ||
|
@@ -1800,4 +1921,7 @@ private <T> T convertValue(JsonNode jsonNode, String key, Class<T> typeClass) { | |
return null; | ||
} | ||
} | ||
|
||
private record PaaResult(List<ExtIgi> igis, ExtBidResponseFledge fledge) { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,26 @@ | ||
package org.prebid.server.auction; | ||
|
||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.node.ArrayNode; | ||
import com.fasterxml.jackson.databind.node.IntNode; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
import com.iab.openrtb.request.Imp; | ||
import org.prebid.server.json.JacksonMapper; | ||
import org.prebid.server.json.JsonMerger; | ||
import org.prebid.server.validation.ImpValidator; | ||
|
||
import java.util.Collection; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.stream.StreamSupport; | ||
|
||
public class ImpAdjuster { | ||
|
||
private static final String IMP_EXT = "ext"; | ||
private static final String EXT_AE = "ae"; | ||
private static final String EXT_IGS = "igs"; | ||
private static final String EXT_PREBID = "prebid"; | ||
private static final String EXT_PREBID_BIDDER = "bidder"; | ||
private static final String EXT_PREBID_IMP = "imp"; | ||
|
@@ -33,6 +39,8 @@ public ImpAdjuster(JacksonMapper jacksonMapper, | |
} | ||
|
||
public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, List<String> debugMessages) { | ||
setAeParams(originalImp.getExt()); | ||
|
||
final JsonNode impExtPrebidImp = bidderParamsFromImpExtPrebidImp(originalImp.getExt()); | ||
if (impExtPrebidImp == null) { | ||
return originalImp; | ||
|
@@ -65,6 +73,29 @@ public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, L | |
} | ||
} | ||
|
||
private void setAeParams(ObjectNode ext) { | ||
final int extAe = Optional.ofNullable(ext) | ||
.map(extNode -> extNode.get(EXT_AE)) | ||
.filter(JsonNode::isInt) | ||
.map(JsonNode::asInt) | ||
.orElse(-1); | ||
|
||
final boolean extIgsAePresent = Optional.ofNullable(ext) | ||
.map(extNode -> extNode.get(EXT_IGS)) | ||
.filter(JsonNode::isArray) | ||
.map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList()) | ||
.stream() | ||
.flatMap(Collection::stream) | ||
.filter(Objects::nonNull) | ||
.anyMatch(igsElementNode -> igsElementNode.has(EXT_AE)); | ||
Comment on lines
+83
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
if (!extIgsAePresent && (extAe == 0 || extAe == 1)) { | ||
final ArrayNode extIgs = jacksonMapper.mapper().createArrayNode(); | ||
extIgs.add(jacksonMapper.mapper().createObjectNode().set(EXT_AE, IntNode.valueOf(extAe))); | ||
ext.set(EXT_IGS, extIgs); | ||
} | ||
} | ||
|
||
private static JsonNode bidderParamsFromImpExtPrebidImp(ObjectNode ext) { | ||
return Optional.ofNullable(ext) | ||
.map(extNode -> extNode.get(EXT_PREBID)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,10 +47,6 @@ public BidRejectionTracker(String bidder, Set<String> involvedImpIds, double log | |
rejectedBids = new HashMap<>(); | ||
} | ||
|
||
/** | ||
* Restores ONLY imps from rejection, rejected bids are preserved for analytics. | ||
* A bid can be rejected only once. | ||
*/ | ||
Comment on lines
-50
to
-53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please keep these comments) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't comment code. Only in super tricky situations, which is not the case. |
||
public void succeed(Collection<BidderBid> bids) { | ||
bids.stream() | ||
.map(BidderBid::getBid) | ||
|
@@ -124,10 +120,6 @@ public void rejectAllImps(BidRejectionReason reason) { | |
involvedImpIds.forEach(impId -> rejectImp(impId, reason)); | ||
} | ||
|
||
/** | ||
* If an impression has at least one valid bid, it's not considered rejected. | ||
* If no valid bids are returned for the impression, only the first one rejected reason will be returned | ||
*/ | ||
public Map<String, BidRejectionReason> getRejectedImps() { | ||
final Map<String, BidRejectionReason> rejectedImpIds = new HashMap<>(); | ||
for (String impId : involvedImpIds) { | ||
|
@@ -144,9 +136,6 @@ public Map<String, BidRejectionReason> getRejectedImps() { | |
return rejectedImpIds; | ||
} | ||
|
||
/** | ||
* Bid is absent for the non-bid code from 0 to 299 | ||
*/ | ||
public Map<String, List<Pair<BidderBid, BidRejectionReason>>> getRejectedBids() { | ||
final Map<String, List<Pair<BidderBid, BidRejectionReason>>> missingImpIds = new HashMap<>(); | ||
for (String impId : involvedImpIds) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.prebid.server.auction.model; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
public enum PaaFormat { | ||
|
||
@JsonProperty("original") | ||
ORIGINAL, | ||
|
||
@JsonProperty("iab") | ||
IAB | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've noticed the requirement to emit warning in debug mode, shouldn't we add the warning messages to the response?