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

     1  package adtrgtme
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/prebid/openrtb/v20/openrtb2"
     9  
    10  	"github.com/prebid/prebid-server/v2/adapters"
    11  	"github.com/prebid/prebid-server/v2/config"
    12  	"github.com/prebid/prebid-server/v2/errortypes"
    13  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    14  )
    15  
    16  type adapter struct {
    17  	endpoint string
    18  }
    19  
    20  // Builder builds a new instance of the Adtrgtme adapter for the given bidder with the given config.
    21  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    22  	bidder := &adapter{
    23  		endpoint: config.Endpoint,
    24  	}
    25  	return bidder, nil
    26  }
    27  
    28  func (v *adapter) MakeRequests(
    29  	openRTBRequest *openrtb2.BidRequest,
    30  	requestInfo *adapters.ExtraRequestInfo,
    31  ) (
    32  	[]*adapters.RequestData,
    33  	[]error,
    34  ) {
    35  	var requests []*adapters.RequestData
    36  	var errors []error
    37  
    38  	requestCopy := *openRTBRequest
    39  	for _, imp := range openRTBRequest.Imp {
    40  		siteID, err := getSiteIDFromImp(&imp)
    41  		if err != nil {
    42  			errors = append(errors, err)
    43  			continue
    44  		}
    45  
    46  		imp.Ext = nil
    47  		requestCopy.Imp = []openrtb2.Imp{imp}
    48  
    49  		requestBody, err := json.Marshal(requestCopy)
    50  		if err != nil {
    51  			errors = append(errors, err)
    52  			continue
    53  		}
    54  
    55  		requestData := &adapters.RequestData{
    56  			Method:  http.MethodPost,
    57  			Uri:     v.buildRequestURI(siteID),
    58  			Body:    requestBody,
    59  			Headers: makeRequestHeaders(openRTBRequest),
    60  			ImpIDs:  openrtb_ext.GetImpIDs(requestCopy.Imp),
    61  		}
    62  
    63  		requests = append(requests, requestData)
    64  	}
    65  	return requests, errors
    66  }
    67  
    68  func getSiteIDFromImp(imp *openrtb2.Imp) (uint64, error) {
    69  	var bidderExt adapters.ExtImpBidder
    70  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    71  		return 0, &errortypes.BadInput{
    72  			Message: "ext.bidder not provided",
    73  		}
    74  	}
    75  	var ext openrtb_ext.ExtImpAdtrgtme
    76  	if err := json.Unmarshal(bidderExt.Bidder, &ext); err != nil {
    77  		return 0, &errortypes.BadInput{
    78  			Message: "ext.bidder not provided",
    79  		}
    80  	}
    81  	return ext.SiteID, nil
    82  }
    83  
    84  func (v *adapter) buildRequestURI(siteID uint64) string {
    85  	return fmt.Sprintf("%s?s=%d&prebid", v.endpoint, siteID)
    86  }
    87  
    88  func makeRequestHeaders(openRTBRequest *openrtb2.BidRequest) http.Header {
    89  	headers := http.Header{}
    90  	headers.Add("Content-Type", "application/json;charset=utf-8")
    91  	headers.Add("Accept", "application/json")
    92  	headers.Add("X-Openrtb-Version", "2.5")
    93  
    94  	if openRTBRequest.Device != nil {
    95  		if len(openRTBRequest.Device.UA) > 0 {
    96  			headers.Add("User-Agent", openRTBRequest.Device.UA)
    97  		}
    98  
    99  		if len(openRTBRequest.Device.IPv6) > 0 {
   100  			headers.Add("X-Forwarded-For", openRTBRequest.Device.IPv6)
   101  		}
   102  
   103  		if len(openRTBRequest.Device.IP) > 0 {
   104  			headers.Add("X-Forwarded-For", openRTBRequest.Device.IP)
   105  		}
   106  	}
   107  	return headers
   108  }
   109  
   110  func (v *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error {
   111  	if response.StatusCode == http.StatusBadRequest {
   112  		return &errortypes.BadInput{
   113  			Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
   114  		}
   115  	}
   116  
   117  	if response.StatusCode == http.StatusServiceUnavailable {
   118  		return &errortypes.BadInput{
   119  			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
   120  		}
   121  	}
   122  
   123  	if response.StatusCode != http.StatusOK {
   124  		return &errortypes.BadInput{
   125  			Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode),
   126  		}
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  func (v *adapter) MakeBids(
   133  	openRTBRequest *openrtb2.BidRequest,
   134  	requestToBidder *adapters.RequestData,
   135  	bidderRawResponse *adapters.ResponseData,
   136  ) (
   137  	*adapters.BidderResponse,
   138  	[]error,
   139  ) {
   140  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   141  		return nil, nil
   142  	}
   143  
   144  	httpStatusError := v.checkResponseStatusCodes(bidderRawResponse)
   145  	if httpStatusError != nil {
   146  		return nil, []error{httpStatusError}
   147  	}
   148  
   149  	var response openrtb2.BidResponse
   150  	if err := json.Unmarshal(bidderRawResponse.Body, &response); err != nil {
   151  		return nil, []error{&errortypes.BadServerResponse{
   152  			Message: "Bad Server Response",
   153  		}}
   154  	}
   155  
   156  	if len(response.SeatBid) == 0 {
   157  		return nil, []error{&errortypes.BadServerResponse{
   158  			Message: "Empty SeatBid array",
   159  		}}
   160  	}
   161  
   162  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRTBRequest.Imp))
   163  	bidResponse.Currency = response.Cur
   164  	for _, seatBid := range response.SeatBid {
   165  		for i, bid := range seatBid.Bid {
   166  			bidType, err := getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp)
   167  			if err != nil {
   168  				return nil, []error{err}
   169  			}
   170  
   171  			b := &adapters.TypedBid{
   172  				Bid:     &seatBid.Bid[i],
   173  				BidType: bidType,
   174  			}
   175  			bidResponse.Bids = append(bidResponse.Bids, b)
   176  		}
   177  	}
   178  	return bidResponse, nil
   179  }
   180  
   181  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
   182  	for _, imp := range imps {
   183  		if imp.ID == impId {
   184  			if imp.Banner != nil {
   185  				return openrtb_ext.BidTypeBanner, nil
   186  			} else {
   187  				return "", &errortypes.BadInput{
   188  					Message: fmt.Sprintf("Unsupported bidtype for bid: \"%s\"", impId),
   189  				}
   190  			}
   191  		}
   192  	}
   193  	return "", &errortypes.BadInput{
   194  		Message: fmt.Sprintf("Failed to find impression: \"%s\"", impId),
   195  	}
   196  }