github.com/prebid/prebid-server/v2@v2.18.0/adapters/readpeak/readpeak.go (about)

     1  package readpeak
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/prebid/openrtb/v20/openrtb2"
    11  	"github.com/prebid/prebid-server/v2/adapters"
    12  	"github.com/prebid/prebid-server/v2/config"
    13  	"github.com/prebid/prebid-server/v2/errortypes"
    14  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    15  )
    16  
    17  type adapter struct {
    18  	endpoint string
    19  }
    20  
    21  // Builder builds a new instance of the Readpeak adapter for the given bidder with the given config.
    22  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    23  	return &adapter{
    24  		endpoint: config.Endpoint,
    25  	}, nil
    26  }
    27  
    28  func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    29  	var errors []error
    30  
    31  	requestCopy := *request
    32  	var rpExt openrtb_ext.ImpExtReadpeak
    33  	var imps []openrtb2.Imp
    34  	for i := 0; i < len(requestCopy.Imp); i++ {
    35  		var impExt adapters.ExtImpBidder
    36  		if err := json.Unmarshal(requestCopy.Imp[i].Ext, &impExt); err != nil {
    37  			errors = append(errors, err)
    38  			continue
    39  		}
    40  		if err := json.Unmarshal(impExt.Bidder, &rpExt); err != nil {
    41  			errors = append(errors, err)
    42  			continue
    43  		}
    44  		imp := requestCopy.Imp[i]
    45  		if rpExt.TagId != "" {
    46  			imp.TagID = rpExt.TagId
    47  		}
    48  		if rpExt.Bidfloor != 0 {
    49  			imp.BidFloor = rpExt.Bidfloor
    50  		}
    51  		imps = append(imps, imp)
    52  	}
    53  
    54  	if len(imps) == 0 {
    55  		err := &errortypes.BadInput{
    56  			Message: fmt.Sprintf("Failed to find compatible impressions for request %s", requestCopy.ID),
    57  		}
    58  		return nil, []error{err}
    59  	}
    60  	requestCopy.Imp = imps
    61  	publisher := &openrtb2.Publisher{
    62  		ID: rpExt.PublisherId,
    63  	}
    64  
    65  	if requestCopy.Site != nil {
    66  		siteCopy := *request.Site
    67  		if rpExt.SiteId != "" {
    68  			siteCopy.ID = rpExt.SiteId
    69  		}
    70  		siteCopy.Publisher = publisher
    71  		requestCopy.Site = &siteCopy
    72  	} else if requestCopy.App != nil {
    73  		appCopy := *request.App
    74  		if rpExt.SiteId != "" {
    75  			appCopy.ID = rpExt.SiteId
    76  		}
    77  		appCopy.Publisher = publisher
    78  		requestCopy.App = &appCopy
    79  	}
    80  
    81  	requestJSON, err := json.Marshal(requestCopy)
    82  	if err != nil {
    83  		return nil, []error{err}
    84  	}
    85  
    86  	headers := http.Header{}
    87  	headers.Add("Content-Type", "application/json;charset=utf-8")
    88  	headers.Add("Accept", "application/json")
    89  
    90  	requestData := &adapters.RequestData{
    91  		Method:  "POST",
    92  		Uri:     a.endpoint,
    93  		Body:    requestJSON,
    94  		Headers: headers,
    95  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
    96  	}
    97  
    98  	return []*adapters.RequestData{requestData}, errors
    99  }
   100  
   101  func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   102  	if adapters.IsResponseStatusCodeNoContent(responseData) {
   103  		return nil, nil
   104  	}
   105  
   106  	if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
   107  		return nil, []error{err}
   108  	}
   109  
   110  	var response openrtb2.BidResponse
   111  	if err := json.Unmarshal(responseData.Body, &response); err != nil {
   112  		return nil, []error{err}
   113  	}
   114  
   115  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
   116  	if len(response.Cur) != 0 {
   117  		bidResponse.Currency = response.Cur
   118  	}
   119  	var errors []error
   120  	for _, seatBid := range response.SeatBid {
   121  		for i := range seatBid.Bid {
   122  			bidType, err := getMediaTypeForBid(seatBid.Bid[i])
   123  			if err != nil {
   124  				errors = append(errors, err)
   125  				continue
   126  			}
   127  			resolveMacros(&seatBid.Bid[i])
   128  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   129  				Bid:     &seatBid.Bid[i],
   130  				BidType: bidType,
   131  				BidMeta: getBidMeta(&seatBid.Bid[i]),
   132  			})
   133  		}
   134  	}
   135  	return bidResponse, errors
   136  }
   137  
   138  func resolveMacros(bid *openrtb2.Bid) {
   139  	if bid != nil {
   140  		price := strconv.FormatFloat(bid.Price, 'f', -1, 64)
   141  		bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1)
   142  		bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1)
   143  		bid.BURL = strings.Replace(bid.BURL, "${AUCTION_PRICE}", price, -1)
   144  	}
   145  }
   146  func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
   147  	switch bid.MType {
   148  	case openrtb2.MarkupBanner:
   149  		return openrtb_ext.BidTypeBanner, nil
   150  	case openrtb2.MarkupNative:
   151  		return openrtb_ext.BidTypeNative, nil
   152  	default:
   153  		return "", fmt.Errorf("Failed to find impression type \"%s\"", bid.ImpID)
   154  	}
   155  }
   156  
   157  func getBidMeta(bid *openrtb2.Bid) *openrtb_ext.ExtBidPrebidMeta {
   158  	return &openrtb_ext.ExtBidPrebidMeta{
   159  		AdvertiserDomains: bid.ADomain,
   160  	}
   161  }