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

     1  package cpmstar
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/prebid/openrtb/v20/openrtb2"
     9  	"github.com/prebid/prebid-server/v2/adapters"
    10  	"github.com/prebid/prebid-server/v2/config"
    11  	"github.com/prebid/prebid-server/v2/errortypes"
    12  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    13  )
    14  
    15  type Adapter struct {
    16  	endpoint string
    17  }
    18  
    19  func (a *Adapter) MakeRequests(request *openrtb2.BidRequest, unused *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    20  	var errs []error
    21  	var adapterRequests []*adapters.RequestData
    22  
    23  	if err := preprocess(request); err != nil {
    24  		errs = append(errs, err)
    25  		return nil, errs
    26  	}
    27  
    28  	adapterReq, err := a.makeRequest(request)
    29  	if err != nil {
    30  		errs = append(errs, err)
    31  		return nil, errs
    32  	}
    33  
    34  	adapterRequests = append(adapterRequests, adapterReq)
    35  
    36  	return adapterRequests, errs
    37  }
    38  
    39  func (a *Adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) {
    40  	var err error
    41  
    42  	jsonBody, err := json.Marshal(request)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	headers := http.Header{}
    48  	headers.Add("Content-Type", "application/json;charset=utf-8")
    49  
    50  	return &adapters.RequestData{
    51  		Method:  "POST",
    52  		Uri:     a.endpoint,
    53  		Body:    jsonBody,
    54  		Headers: headers,
    55  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
    56  	}, nil
    57  }
    58  
    59  func preprocess(request *openrtb2.BidRequest) error {
    60  	if len(request.Imp) == 0 {
    61  		return &errortypes.BadInput{
    62  			Message: "No Imps in Bid Request",
    63  		}
    64  	}
    65  	for i := 0; i < len(request.Imp); i++ {
    66  		var imp = &request.Imp[i]
    67  		var bidderExt adapters.ExtImpBidder
    68  
    69  		if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    70  			return &errortypes.BadInput{
    71  				Message: err.Error(),
    72  			}
    73  		}
    74  
    75  		if err := validateImp(imp); err != nil {
    76  			return err
    77  		}
    78  
    79  		var extImp openrtb_ext.ExtImpCpmstar
    80  		if err := json.Unmarshal(bidderExt.Bidder, &extImp); err != nil {
    81  			return &errortypes.BadInput{
    82  				Message: err.Error(),
    83  			}
    84  		}
    85  
    86  		imp.Ext = bidderExt.Bidder
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func validateImp(imp *openrtb2.Imp) error {
    93  	if imp.Banner == nil && imp.Video == nil {
    94  		return &errortypes.BadInput{
    95  			Message: "Only Banner and Video bid-types are supported at this time",
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  // MakeBids based on cpmstar server response
   102  func (a *Adapter) MakeBids(bidRequest *openrtb2.BidRequest, unused *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   103  	if responseData.StatusCode == http.StatusNoContent {
   104  		return nil, nil
   105  	}
   106  
   107  	if responseData.StatusCode != http.StatusOK {
   108  		return nil, []error{&errortypes.BadServerResponse{
   109  			Message: fmt.Sprintf("Unexpected HTTP status code: %d. Run with request.debug = 1 for more info", responseData.StatusCode),
   110  		}}
   111  	}
   112  
   113  	var bidResponse openrtb2.BidResponse
   114  
   115  	if err := json.Unmarshal(responseData.Body, &bidResponse); err != nil {
   116  		return nil, []error{&errortypes.BadServerResponse{
   117  			Message: err.Error(),
   118  		}}
   119  	}
   120  
   121  	if len(bidResponse.SeatBid) == 0 {
   122  		return nil, nil
   123  	}
   124  
   125  	rv := adapters.NewBidderResponseWithBidsCapacity(len(bidResponse.SeatBid[0].Bid))
   126  	var errors []error
   127  
   128  	for _, seatbid := range bidResponse.SeatBid {
   129  		for i := range seatbid.Bid {
   130  			foundMatchingBid := false
   131  			bidType := openrtb_ext.BidTypeBanner
   132  			for _, imp := range bidRequest.Imp {
   133  				if imp.ID == seatbid.Bid[i].ImpID {
   134  					foundMatchingBid = true
   135  					if imp.Banner != nil {
   136  						bidType = openrtb_ext.BidTypeBanner
   137  					} else if imp.Video != nil {
   138  						bidType = openrtb_ext.BidTypeVideo
   139  					}
   140  					break
   141  				}
   142  			}
   143  
   144  			if foundMatchingBid {
   145  				rv.Bids = append(rv.Bids, &adapters.TypedBid{
   146  					Bid:     &seatbid.Bid[i],
   147  					BidType: bidType,
   148  				})
   149  			} else {
   150  				errors = append(errors, &errortypes.BadServerResponse{
   151  					Message: fmt.Sprintf("bid id='%s' could not find valid impid='%s'", seatbid.Bid[i].ID, seatbid.Bid[i].ImpID),
   152  				})
   153  			}
   154  		}
   155  	}
   156  	return rv, errors
   157  }
   158  
   159  // Builder builds a new instance of the Cpmstar adapter for the given bidder with the given config.
   160  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   161  	bidder := &Adapter{
   162  		endpoint: config.Endpoint,
   163  	}
   164  	return bidder, nil
   165  }