github.com/prebid/prebid-server@v0.275.0/adapters/rhythmone/rhythmone.go (about)

     1  package rhythmone
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"net/http"
     8  
     9  	"github.com/prebid/openrtb/v19/openrtb2"
    10  	"github.com/prebid/prebid-server/adapters"
    11  	"github.com/prebid/prebid-server/config"
    12  	"github.com/prebid/prebid-server/errortypes"
    13  	"github.com/prebid/prebid-server/openrtb_ext"
    14  )
    15  
    16  type RhythmoneAdapter struct {
    17  	endPoint string
    18  }
    19  
    20  func (a *RhythmoneAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    21  	errs := make([]error, 0, len(request.Imp))
    22  
    23  	var uri string
    24  	request, uri, errs = a.preProcess(request, errs)
    25  	if request != nil {
    26  		reqJSON, err := json.Marshal(request)
    27  		if err != nil {
    28  			errs = append(errs, err)
    29  			return nil, errs
    30  		}
    31  		if uri != "" {
    32  			headers := http.Header{}
    33  			headers.Add("Content-Type", "application/json;charset=utf-8")
    34  			headers.Add("Accept", "application/json")
    35  			return []*adapters.RequestData{{
    36  				Method:  "POST",
    37  				Uri:     uri,
    38  				Body:    reqJSON,
    39  				Headers: headers,
    40  			}}, errs
    41  		}
    42  	}
    43  	return nil, errs
    44  }
    45  
    46  func (a *RhythmoneAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    47  	if response.StatusCode == http.StatusNoContent {
    48  		return nil, nil
    49  	}
    50  
    51  	if response.StatusCode == http.StatusBadRequest {
    52  		return nil, []error{&errortypes.BadInput{
    53  			Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    54  		}}
    55  	}
    56  
    57  	if response.StatusCode != http.StatusOK {
    58  		return nil, []error{&errortypes.BadServerResponse{
    59  			Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    60  		}}
    61  	}
    62  	var bidResp openrtb2.BidResponse
    63  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
    64  		return nil, []error{&errortypes.BadServerResponse{
    65  			Message: fmt.Sprintf("bad server response: %d. ", err),
    66  		}}
    67  	}
    68  
    69  	var errs []error
    70  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)
    71  
    72  	for _, sb := range bidResp.SeatBid {
    73  		for i := range sb.Bid {
    74  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
    75  				Bid:     &sb.Bid[i],
    76  				BidType: getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp),
    77  			})
    78  		}
    79  	}
    80  	return bidResponse, errs
    81  }
    82  
    83  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
    84  	mediaType := openrtb_ext.BidTypeBanner
    85  	for _, imp := range imps {
    86  		if imp.ID == impId {
    87  			if imp.Banner != nil {
    88  				mediaType = openrtb_ext.BidTypeBanner
    89  			} else if imp.Video != nil {
    90  				mediaType = openrtb_ext.BidTypeVideo
    91  			}
    92  			return mediaType
    93  		}
    94  	}
    95  	return mediaType
    96  }
    97  
    98  // Builder builds a new instance of the Rythomone adapter for the given bidder with the given config.
    99  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   100  	bidder := &RhythmoneAdapter{
   101  		endPoint: config.Endpoint,
   102  	}
   103  	return bidder, nil
   104  }
   105  
   106  func (a *RhythmoneAdapter) preProcess(req *openrtb2.BidRequest, errors []error) (*openrtb2.BidRequest, string, []error) {
   107  	numRequests := len(req.Imp)
   108  	var uri string = ""
   109  	for i := 0; i < numRequests; i++ {
   110  		imp := req.Imp[i]
   111  		var bidderExt adapters.ExtImpBidder
   112  		err := json.Unmarshal(imp.Ext, &bidderExt)
   113  		if err != nil {
   114  			err = &errortypes.BadInput{
   115  				Message: fmt.Sprintf("ext data not provided in imp id=%s. Abort all Request", imp.ID),
   116  			}
   117  			errors = append(errors, err)
   118  			return nil, "", errors
   119  		}
   120  		var rhythmoneExt openrtb_ext.ExtImpRhythmone
   121  		err = json.Unmarshal(bidderExt.Bidder, &rhythmoneExt)
   122  		if err != nil {
   123  			err = &errortypes.BadInput{
   124  				Message: fmt.Sprintf("placementId | zone | path not provided in imp id=%s. Abort all Request", imp.ID),
   125  			}
   126  			errors = append(errors, err)
   127  			return nil, "", errors
   128  		}
   129  		rhythmoneExt.S2S = true
   130  		rhythmoneExtCopy, err := json.Marshal(&rhythmoneExt)
   131  		if err != nil {
   132  			errors = append(errors, err)
   133  			return nil, "", errors
   134  		}
   135  		bidderExtCopy := struct {
   136  			Bidder json.RawMessage `json:"bidder,omitempty"`
   137  		}{rhythmoneExtCopy}
   138  		impExtCopy, err := json.Marshal(&bidderExtCopy)
   139  		if err != nil {
   140  			errors = append(errors, err)
   141  			return nil, "", errors
   142  		}
   143  		imp.Ext = impExtCopy
   144  		req.Imp[i] = imp
   145  		if uri == "" {
   146  			uri = fmt.Sprintf("%s/%s/0/%s?z=%s&s2s=%s", a.endPoint, rhythmoneExt.PlacementId, rhythmoneExt.Path, rhythmoneExt.Zone, "true")
   147  		}
   148  	}
   149  	return req, uri, errors
   150  }