github.com/prebid/prebid-server@v0.275.0/adservertargeting/respdataprocessor.go (about)

     1  package adservertargeting
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  	"github.com/prebid/openrtb/v19/openrtb2"
    10  	"github.com/prebid/prebid-server/openrtb_ext"
    11  	jsonpatch "gopkg.in/evanphx/json-patch.v4"
    12  )
    13  
    14  const MaxKeyLength = 20
    15  
    16  func processRequestTargetingData(adServerTargetingData *adServerTargetingData, targetingData map[string]string, bidImpId string) {
    17  	for key, val := range adServerTargetingData.RequestTargetingData {
    18  		if len(val.SingleVal) > 0 {
    19  			targetingData[key] = string(val.SingleVal)
    20  		} else if len(val.TargetingValueByImpId) > 0 {
    21  			targetingData[key] = string(val.TargetingValueByImpId[bidImpId])
    22  		}
    23  	}
    24  }
    25  
    26  func processResponseTargetingData(
    27  	adServerTargetingData *adServerTargetingData,
    28  	targetingData map[string]string,
    29  	bidderName string,
    30  	bid openrtb2.Bid,
    31  	bidsHolder bidsCache,
    32  	response *openrtb2.BidResponse,
    33  	seatExt json.RawMessage) []openrtb_ext.ExtBidderMessage {
    34  
    35  	var warnings []openrtb_ext.ExtBidderMessage
    36  
    37  	for _, respTargetingData := range adServerTargetingData.ResponseTargetingData {
    38  		key := resolveKey(respTargetingData, bidderName)
    39  		path := respTargetingData.Path
    40  
    41  		var value string
    42  		var err error
    43  		pathSplit := strings.Split(path, pathDelimiter)
    44  
    45  		switch pathSplit[0] {
    46  
    47  		case "seatbid":
    48  			switch pathSplit[1] {
    49  			case "bid":
    50  				value, err = getValueFromSeatBidBid(path, bidsHolder, bidderName, bid)
    51  			case "ext":
    52  				value, err = getValueFromExt(path, "seatbid.ext.", seatExt)
    53  			}
    54  		case "ext":
    55  			value, err = getValueFromExt(path, "ext.", response.Ext)
    56  		default:
    57  			value, err = getValueFromResp(path, response)
    58  		}
    59  
    60  		if err != nil {
    61  			message := fmt.Sprintf("%s for bidder: %s, bid id: %s", err.Error(), bidderName, bid.ID)
    62  			warnings = append(warnings, createWarning(message))
    63  		} else {
    64  			targetingData[key] = value
    65  		}
    66  	}
    67  	return warnings
    68  }
    69  
    70  func buildBidExt(targetingData map[string]string,
    71  	bid openrtb2.Bid,
    72  	warnings []openrtb_ext.ExtBidderMessage,
    73  	truncateTargetAttribute *int) json.RawMessage {
    74  
    75  	targetingDataTruncated := truncateTargetingKeys(targetingData, truncateTargetAttribute)
    76  
    77  	bidExtTargetingData := openrtb_ext.ExtBid{
    78  		Prebid: &openrtb_ext.ExtBidPrebid{
    79  			Targeting: targetingDataTruncated,
    80  		},
    81  	}
    82  	bidExtTargeting, err := json.Marshal(bidExtTargetingData)
    83  	if err != nil {
    84  		warnings = append(warnings, createWarning(err.Error()))
    85  		return nil
    86  	}
    87  
    88  	newExt, err := jsonpatch.MergePatch(bid.Ext, bidExtTargeting)
    89  	if err != nil {
    90  		warnings = append(warnings, createWarning(err.Error()))
    91  		return nil
    92  	}
    93  	return newExt
    94  }
    95  
    96  func resolveKey(respTargetingData ResponseTargetingData, bidderName string) string {
    97  	key := respTargetingData.Key
    98  	if respTargetingData.HasMacro {
    99  		key = strings.Replace(respTargetingData.Key, bidderMacro, bidderName, -1)
   100  	}
   101  	return key
   102  }
   103  
   104  func truncateTargetingKeys(targetingData map[string]string, truncateTargetAttribute *int) map[string]string {
   105  	maxLength := MaxKeyLength
   106  	if truncateTargetAttribute != nil {
   107  		maxLength = *truncateTargetAttribute
   108  		if maxLength <= 0 {
   109  			maxLength = MaxKeyLength
   110  		}
   111  	}
   112  
   113  	targetingDataTruncated := make(map[string]string)
   114  	for key, value := range targetingData {
   115  		newKey := openrtb_ext.TargetingKey(key).TruncateKey(maxLength)
   116  		targetingDataTruncated[newKey] = value
   117  	}
   118  	return targetingDataTruncated
   119  }
   120  
   121  func getValueFromSeatBidBid(path string, bidsHolder bidsCache, bidderName string, bid openrtb2.Bid) (string, error) {
   122  	bidBytes, err := bidsHolder.GetBid(bidderName, bid.ID, bid)
   123  	if err != nil {
   124  		return "", err
   125  	}
   126  
   127  	bidSplit := strings.Split(path, "seatbid.bid.")
   128  	value, err := splitAndGet(bidSplit[1], bidBytes, pathDelimiter)
   129  	if err != nil {
   130  		return "", err
   131  
   132  	}
   133  	return value, nil
   134  }
   135  
   136  func getValueFromExt(path, separator string, respExt json.RawMessage) (string, error) {
   137  	//path points to resp.ext, means path starts with ext
   138  	extSplit := strings.Split(path, separator)
   139  	value, err := splitAndGet(extSplit[1], respExt, pathDelimiter)
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  
   144  	return value, nil
   145  }
   146  
   147  // getValueFromResp optimizes retrieval of paths for a bid response (not a seat or ext)
   148  func getValueFromResp(path string, response *openrtb2.BidResponse) (string, error) {
   149  	value, err := getRespData(response, path)
   150  	if err != nil {
   151  		return "", err
   152  	}
   153  	return value, nil
   154  }
   155  
   156  func getRespData(bidderResp *openrtb2.BidResponse, field string) (string, error) {
   157  	// this code should be modified if there are changes in OpenRtb format
   158  	// it's up to date with OpenRTB 2.5 and 2.6
   159  	switch field {
   160  	case "id":
   161  		return bidderResp.ID, nil
   162  	case "bidid":
   163  		return bidderResp.BidID, nil
   164  	case "cur":
   165  		return bidderResp.Cur, nil
   166  	case "customdata":
   167  		return bidderResp.CustomData, nil
   168  	case "nbr":
   169  		return fmt.Sprint(bidderResp.NBR.Val()), nil
   170  
   171  	default:
   172  		return "", errors.Errorf("key not found for field in bid response: %s", field)
   173  	}
   174  
   175  }