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

     1  package consumable
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/prebid/prebid-server/v2/adapters"
     9  	"github.com/prebid/prebid-server/v2/config"
    10  	"github.com/prebid/prebid-server/v2/errortypes"
    11  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    12  
    13  	"github.com/prebid/openrtb/v20/openrtb2"
    14  )
    15  
    16  type adapter struct {
    17  	endpoint string
    18  }
    19  
    20  func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    21  	var errs []error
    22  	headers := http.Header{
    23  		"Content-Type": {"application/json"},
    24  		"Accept":       {"application/json"},
    25  	}
    26  	bodyBytes, err := json.Marshal(request)
    27  	if err != nil {
    28  		return nil, []error{err}
    29  	}
    30  
    31  	if request.Site != nil {
    32  		_, consumableExt, err := extractExtensions(request.Imp[0])
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  		if consumableExt.SiteId == 0 && consumableExt.NetworkId == 0 && consumableExt.UnitId == 0 {
    37  			return nil, []error{&errortypes.FailedToRequestBids{
    38  				Message: "SiteId, NetworkId and UnitId are all required for site requests",
    39  			}}
    40  		}
    41  		requests := []*adapters.RequestData{
    42  			{
    43  				Method:  "POST",
    44  				Uri:     "https://e.serverbid.com/sb/rtb",
    45  				Body:    bodyBytes,
    46  				Headers: headers,
    47  				ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
    48  			},
    49  		}
    50  		return requests, errs
    51  
    52  	} else {
    53  		_, consumableExt, err := extractExtensions(request.Imp[0])
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  
    58  		if consumableExt.PlacementId == "" {
    59  			return nil, []error{&errortypes.FailedToRequestBids{
    60  				Message: "PlacementId is required for non-site requests",
    61  			}}
    62  		}
    63  		requests := []*adapters.RequestData{
    64  			{
    65  				Method:  "POST",
    66  				Uri:     "https://e.serverbid.com/rtb/bid?s=" + consumableExt.PlacementId,
    67  				Body:    bodyBytes,
    68  				Headers: headers,
    69  				ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
    70  			},
    71  		}
    72  		return requests, errs
    73  	}
    74  
    75  }
    76  func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    77  	if adapters.IsResponseStatusCodeNoContent(responseData) {
    78  		return nil, nil
    79  	}
    80  
    81  	if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
    82  		return nil, []error{err}
    83  	}
    84  
    85  	var response openrtb2.BidResponse
    86  	if err := json.Unmarshal(responseData.Body, &response); err != nil {
    87  		return nil, []error{err}
    88  	}
    89  
    90  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
    91  	bidResponse.Currency = response.Cur
    92  	var errors []error
    93  	for _, seatBid := range response.SeatBid {
    94  		for i, bid := range seatBid.Bid {
    95  			bidType, err := getMediaTypeForBid(bid)
    96  			if err != nil {
    97  				errors = append(errors, err)
    98  				continue
    99  			}
   100  			var bidVideo *openrtb_ext.ExtBidPrebidVideo
   101  			if bidType == openrtb_ext.BidTypeVideo {
   102  				bidVideo = &openrtb_ext.ExtBidPrebidVideo{Duration: int(bid.Dur)}
   103  			}
   104  			switch bidType {
   105  			case openrtb_ext.BidTypeAudio:
   106  				seatBid.Bid[i].MType = openrtb2.MarkupAudio
   107  			case openrtb_ext.BidTypeVideo:
   108  				seatBid.Bid[i].MType = openrtb2.MarkupVideo
   109  			case openrtb_ext.BidTypeBanner:
   110  				seatBid.Bid[i].MType = openrtb2.MarkupBanner
   111  			}
   112  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   113  				Bid:      &seatBid.Bid[i],
   114  				BidType:  bidType,
   115  				BidVideo: bidVideo,
   116  			})
   117  		}
   118  	}
   119  	return bidResponse, nil
   120  }
   121  
   122  func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
   123  	if bid.MType != 0 {
   124  		switch bid.MType {
   125  		case openrtb2.MarkupBanner:
   126  			return openrtb_ext.BidTypeBanner, nil
   127  		case openrtb2.MarkupVideo:
   128  			return openrtb_ext.BidTypeVideo, nil
   129  		case openrtb2.MarkupAudio:
   130  			return openrtb_ext.BidTypeAudio, nil
   131  		}
   132  	}
   133  
   134  	return "", &errortypes.BadServerResponse{
   135  		Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID),
   136  	}
   137  }
   138  
   139  // Builder builds a new instance of the Consumable adapter for the given bidder with the given config.
   140  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   141  	bidder := &adapter{
   142  		endpoint: config.Endpoint,
   143  	}
   144  	return bidder, nil
   145  }
   146  
   147  func extractExtensions(impression openrtb2.Imp) (*adapters.ExtImpBidder, *openrtb_ext.ExtImpConsumable, []error) {
   148  	var bidderExt adapters.ExtImpBidder
   149  	if err := json.Unmarshal(impression.Ext, &bidderExt); err != nil {
   150  		return nil, nil, []error{&errortypes.BadInput{
   151  			Message: err.Error(),
   152  		}}
   153  	}
   154  
   155  	var consumableExt openrtb_ext.ExtImpConsumable
   156  	if err := json.Unmarshal(bidderExt.Bidder, &consumableExt); err != nil {
   157  		return nil, nil, []error{&errortypes.BadInput{
   158  			Message: err.Error(),
   159  		}}
   160  	}
   161  
   162  	return &bidderExt, &consumableExt, nil
   163  }