github.com/prebid/prebid-server@v0.275.0/exchange/targeting.go (about)

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