github.com/prebid/prebid-server/v2@v2.18.0/exchange/targeting.go (about) 1 package exchange 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/prebid/openrtb/v20/openrtb2" 8 "github.com/prebid/prebid-server/v2/openrtb_ext" 9 ) 10 11 const MaxKeyLength = 20 12 13 // targetData tracks information about the winning Bid in each Imp. 14 // 15 // All functions on this struct are nil-safe. If the targetData struct is nil, then they behave 16 // like they would if no targeting information is needed. 17 // 18 // All functions on this struct are all nil-safe. 19 // If the value is nil, then no targeting data will be tracked. 20 type targetData struct { 21 priceGranularity openrtb_ext.PriceGranularity 22 mediaTypePriceGranularity openrtb_ext.MediaTypePriceGranularity 23 includeWinners bool 24 includeBidderKeys bool 25 includeCacheBids bool 26 includeCacheVast bool 27 includeFormat bool 28 preferDeals bool 29 alwaysIncludeDeals bool 30 // cacheHost and cachePath exist to supply cache host and path as targeting parameters 31 cacheHost string 32 cachePath string 33 } 34 35 // setTargeting writes all the targeting params into the bids. 36 // If any errors occur when setting the targeting params for a particular bid, then that bid will be ejected from the auction. 37 // 38 // The one exception is the `hb_cache_id` key. Since our APIs explicitly document cache keys to be on a "best effort" basis, 39 // it's ok if those stay in the auction. For now, this method implements a very naive cache strategy. 40 // In the future, we should implement a more clever retry & backoff strategy to balance the success rate & performance. 41 func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMapping map[string]string, truncateTargetAttr *int, multiBidMap map[string]openrtb_ext.ExtMultiBid) { 42 for impId, topBidsPerImp := range auc.allBidsByBidder { 43 overallWinner := auc.winningBids[impId] 44 for originalBidderName, topBidsPerBidder := range topBidsPerImp { 45 targetingBidderCode := originalBidderName 46 bidderCodePrefix, maxBids := getMultiBidMeta(multiBidMap, originalBidderName.String()) 47 48 for i, topBid := range topBidsPerBidder { 49 // Limit targeting keys to maxBids (default 1 bid). 50 // And, do not apply targeting for more than 1 bid if bidderCodePrefix is not defined. 51 if i == maxBids || (i == 1 && bidderCodePrefix == "") { 52 break 53 } 54 55 if i > 0 { // bidderCode is used for first bid, generated bidderCodePrefix for following bids 56 targetingBidderCode = openrtb_ext.BidderName(fmt.Sprintf("%s%d", bidderCodePrefix, i+1)) 57 } 58 59 if maxBids > openrtb_ext.DefaultBidLimit { // add targetingbiddercode only if multibid is set for this bidder 60 topBid.TargetBidderCode = targetingBidderCode.String() 61 } 62 63 isOverallWinner := overallWinner == topBid 64 65 bidHasDeal := len(topBid.Bid.DealID) > 0 66 67 targets := make(map[string]string, 10) 68 if cpm, ok := auc.roundedPrices[topBid]; ok { 69 targData.addKeys(targets, openrtb_ext.HbpbConstantKey, cpm, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 70 } 71 targData.addKeys(targets, openrtb_ext.HbBidderConstantKey, string(targetingBidderCode), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 72 if hbSize := makeHbSize(topBid.Bid); hbSize != "" { 73 targData.addKeys(targets, openrtb_ext.HbSizeConstantKey, hbSize, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 74 } 75 if cacheID, ok := auc.cacheIds[topBid.Bid]; ok { 76 targData.addKeys(targets, openrtb_ext.HbCacheKey, cacheID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 77 } 78 if vastID, ok := auc.vastCacheIds[topBid.Bid]; ok { 79 targData.addKeys(targets, openrtb_ext.HbVastCacheKey, vastID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 80 } 81 if targData.includeFormat { 82 targData.addKeys(targets, openrtb_ext.HbFormatKey, string(topBid.BidType), targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 83 } 84 85 if targData.cacheHost != "" { 86 targData.addKeys(targets, openrtb_ext.HbConstantCacheHostKey, targData.cacheHost, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 87 } 88 if targData.cachePath != "" { 89 targData.addKeys(targets, openrtb_ext.HbConstantCachePathKey, targData.cachePath, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 90 } 91 92 if bidHasDeal { 93 targData.addKeys(targets, openrtb_ext.HbDealIDConstantKey, topBid.Bid.DealID, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 94 } 95 96 if isApp { 97 targData.addKeys(targets, openrtb_ext.HbEnvKey, openrtb_ext.HbEnvKeyApp, targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 98 } 99 if len(categoryMapping) > 0 { 100 targData.addKeys(targets, openrtb_ext.HbCategoryDurationKey, categoryMapping[topBid.Bid.ID], targetingBidderCode, isOverallWinner, truncateTargetAttr, bidHasDeal) 101 } 102 topBid.BidTargets = targets 103 } 104 } 105 } 106 } 107 108 func (targData *targetData) addKeys(keys map[string]string, key openrtb_ext.TargetingKey, value string, bidderName openrtb_ext.BidderName, overallWinner bool, truncateTargetAttr *int, bidHasDeal bool) { 109 var maxLength int 110 if truncateTargetAttr != nil { 111 maxLength = *truncateTargetAttr 112 if maxLength < 0 { 113 maxLength = MaxKeyLength 114 } 115 } else { 116 maxLength = MaxKeyLength 117 } 118 if targData.includeBidderKeys || (targData.alwaysIncludeDeals && bidHasDeal) { 119 keys[key.BidderKey(bidderName, maxLength)] = value 120 } 121 if targData.includeWinners && overallWinner { 122 keys[key.TruncateKey(maxLength)] = value 123 } 124 } 125 126 func makeHbSize(bid *openrtb2.Bid) string { 127 if bid.W != 0 && bid.H != 0 { 128 return strconv.FormatInt(bid.W, 10) + "x" + strconv.FormatInt(bid.H, 10) 129 } 130 return "" 131 } 132 133 func getMultiBidMeta(multiBidMap map[string]openrtb_ext.ExtMultiBid, bidder string) (string, int) { 134 if multiBidMap != nil { 135 if multiBid, ok := multiBidMap[bidder]; ok { 136 return multiBid.TargetBidderCodePrefix, *multiBid.MaxBids 137 } 138 } 139 140 return "", openrtb_ext.DefaultBidLimit 141 }