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

     1  package trafficgate
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"text/template"
     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/macros"
    14  	"github.com/prebid/prebid-server/openrtb_ext"
    15  )
    16  
    17  type adapter struct {
    18  	EndpointTemplate *template.Template
    19  }
    20  
    21  type BidResponseExt struct {
    22  	Prebid struct {
    23  		Type string
    24  	}
    25  }
    26  
    27  func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    28  
    29  	headers := http.Header{
    30  		"Content-Type": {"application/json"},
    31  		"Accept":       {"application/json"},
    32  	}
    33  
    34  	// Pull the host and source ID info from the bidder params.
    35  	reqImps, err := splitImpressions(request.Imp)
    36  	if err != nil {
    37  		return nil, []error{err}
    38  	}
    39  
    40  	requests := []*adapters.RequestData{}
    41  
    42  	var errs []error
    43  	for reqExt, reqImp := range reqImps {
    44  		request.Imp = reqImp
    45  		reqJson, err := json.Marshal(request)
    46  
    47  		if err != nil {
    48  			errs = append(errs, err)
    49  			continue
    50  		}
    51  
    52  		urlParams := macros.EndpointTemplateParams{Host: reqExt.Host}
    53  		url, err := macros.ResolveMacros(a.EndpointTemplate, urlParams)
    54  
    55  		if err != nil {
    56  			errs = append(errs, err)
    57  			continue
    58  		}
    59  
    60  		request := adapters.RequestData{
    61  			Method:  "POST",
    62  			Uri:     url,
    63  			Body:    reqJson,
    64  			Headers: headers}
    65  
    66  		requests = append(requests, &request)
    67  	}
    68  
    69  	return requests, errs
    70  }
    71  
    72  /*
    73  internal original request in OpenRTB, external = result of us having converted it (what comes out of MakeRequests)
    74  */
    75  func (a *adapter) MakeBids(
    76  	internalRequest *openrtb2.BidRequest,
    77  	externalRequest *adapters.RequestData,
    78  	response *adapters.ResponseData,
    79  ) (*adapters.BidderResponse, []error) {
    80  
    81  	if response.StatusCode == http.StatusNoContent {
    82  		return nil, nil
    83  	}
    84  
    85  	if response.StatusCode != http.StatusOK {
    86  		return nil, []error{&errortypes.BadServerResponse{
    87  			Message: fmt.Sprintf("Error response with status %d", response.StatusCode),
    88  		}}
    89  	}
    90  
    91  	var bidResp openrtb2.BidResponse
    92  
    93  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
    94  		return nil, []error{&errortypes.BadServerResponse{
    95  			Message: err.Error(),
    96  		}}
    97  	}
    98  
    99  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp))
   100  	bidResponse.Currency = bidResp.Cur
   101  
   102  	for _, seatBid := range bidResp.SeatBid {
   103  		for i := range seatBid.Bid {
   104  			var bidExt BidResponseExt
   105  			if err := json.Unmarshal(seatBid.Bid[i].Ext, &bidExt); err != nil {
   106  				return nil, []error{&errortypes.BadServerResponse{
   107  					Message: fmt.Sprintf("Missing response ext"),
   108  				}}
   109  			}
   110  			if len(bidExt.Prebid.Type) < 1 {
   111  				return nil, []error{&errortypes.BadServerResponse{
   112  					Message: fmt.Sprintf("Unable to read bid.ext.prebid.type"),
   113  				}}
   114  			}
   115  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   116  				Bid:     &seatBid.Bid[i],
   117  				BidType: getMediaTypeForImp(bidExt.Prebid.Type),
   118  			})
   119  		}
   120  	}
   121  
   122  	return bidResponse, nil
   123  }
   124  
   125  func splitImpressions(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp, error) {
   126  
   127  	var multipleImps = make(map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp)
   128  
   129  	for _, imp := range imps {
   130  		bidderParams, err := getBidderParams(&imp)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  
   135  		multipleImps[*bidderParams] = append(multipleImps[*bidderParams], imp)
   136  	}
   137  
   138  	return multipleImps, nil
   139  }
   140  
   141  func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTrafficGate, error) {
   142  	var bidderExt adapters.ExtImpBidder
   143  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
   144  		return nil, &errortypes.BadInput{
   145  			Message: fmt.Sprintf("Missing bidder ext"),
   146  		}
   147  	}
   148  	var TrafficGateExt openrtb_ext.ExtImpTrafficGate
   149  	if err := json.Unmarshal(bidderExt.Bidder, &TrafficGateExt); err != nil {
   150  		return nil, &errortypes.BadInput{
   151  			Message: fmt.Sprintf("Bidder parameters required"),
   152  		}
   153  	}
   154  
   155  	return &TrafficGateExt, nil
   156  }
   157  
   158  func getMediaTypeForImp(bidType string) openrtb_ext.BidType {
   159  	switch bidType {
   160  	case "video":
   161  		return openrtb_ext.BidTypeVideo
   162  	case "native":
   163  		return openrtb_ext.BidTypeNative
   164  	case "audio":
   165  		return openrtb_ext.BidTypeAudio
   166  	}
   167  	return openrtb_ext.BidTypeBanner
   168  }
   169  
   170  // Builder builds a new instance of the TrafficGate adapter for the given bidder with the given config.
   171  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   172  	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
   173  	if err != nil {
   174  		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
   175  	}
   176  
   177  	bidder := &adapter{
   178  		EndpointTemplate: template,
   179  	}
   180  	return bidder, nil
   181  }