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

     1  package colossus
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/buger/jsonparser"
     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 ColossusAdapter struct {
    17  	URI string
    18  }
    19  
    20  type ColossusResponseBidExt struct {
    21  	MediaType string `json:"mediaType"`
    22  }
    23  
    24  // Builder builds a new instance of the Colossus adapter for the given bidder with the given config.
    25  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    26  	bidder := &ColossusAdapter{
    27  		URI: config.Endpoint,
    28  	}
    29  	return bidder, nil
    30  }
    31  
    32  // MakeRequests create bid request for colossus demand
    33  func (a *ColossusAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    34  	var errs []error
    35  	var adapterRequests []*adapters.RequestData
    36  
    37  	reqCopy := *request
    38  	for _, imp := range request.Imp {
    39  		reqCopy.Imp = []openrtb2.Imp{imp}
    40  
    41  		if tagID, err := jsonparser.GetString(reqCopy.Imp[0].Ext, "bidder", "TagID"); err == nil {
    42  			reqCopy.Imp[0].TagID = tagID
    43  		} else if err != jsonparser.KeyPathNotFoundError {
    44  			errs = append(errs, err)
    45  			continue
    46  		}
    47  
    48  		adapterReq, errors := a.makeRequest(&reqCopy)
    49  		if adapterReq != nil {
    50  			adapterRequests = append(adapterRequests, adapterReq)
    51  		}
    52  		errs = append(errs, errors...)
    53  	}
    54  	return adapterRequests, errs
    55  }
    56  
    57  func (a *ColossusAdapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, []error) {
    58  
    59  	var errs []error
    60  
    61  	reqJSON, err := json.Marshal(request)
    62  
    63  	if err != nil {
    64  		errs = append(errs, err)
    65  		return nil, errs
    66  	}
    67  
    68  	headers := http.Header{}
    69  	headers.Add("Content-Type", "application/json;charset=utf-8")
    70  	headers.Add("Accept", "application/json")
    71  	return &adapters.RequestData{
    72  		Method:  "POST",
    73  		Uri:     a.URI,
    74  		Body:    reqJSON,
    75  		Headers: headers,
    76  	}, errs
    77  }
    78  
    79  // MakeBids makes the bids
    80  func (a *ColossusAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    81  	var errs []error
    82  
    83  	if response.StatusCode == http.StatusNoContent {
    84  		return nil, nil
    85  	}
    86  
    87  	if response.StatusCode == http.StatusNotFound {
    88  		return nil, []error{&errortypes.BadServerResponse{
    89  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    90  		}}
    91  	}
    92  
    93  	if response.StatusCode != http.StatusOK {
    94  		return nil, []error{&errortypes.BadServerResponse{
    95  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    96  		}}
    97  	}
    98  
    99  	var bidResp openrtb2.BidResponse
   100  
   101  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   102  		return nil, []error{err}
   103  	}
   104  
   105  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   106  
   107  	for _, sb := range bidResp.SeatBid {
   108  		for i := range sb.Bid {
   109  			bidType, err := getMediaTypeForImp(sb.Bid[i], internalRequest.Imp)
   110  			if err != nil {
   111  				errs = append(errs, err)
   112  			} else {
   113  				b := &adapters.TypedBid{
   114  					Bid:     &sb.Bid[i],
   115  					BidType: bidType,
   116  				}
   117  				bidResponse.Bids = append(bidResponse.Bids, b)
   118  			}
   119  		}
   120  	}
   121  	return bidResponse, errs
   122  }
   123  
   124  func getMediaTypeForImp(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
   125  	var bidExt ColossusResponseBidExt
   126  	err := json.Unmarshal(bid.Ext, &bidExt)
   127  	if err == nil {
   128  		switch bidExt.MediaType {
   129  		case "banner":
   130  			return openrtb_ext.BidTypeBanner, nil
   131  		case "native":
   132  			return openrtb_ext.BidTypeNative, nil
   133  		case "video":
   134  			return openrtb_ext.BidTypeVideo, nil
   135  		}
   136  	}
   137  
   138  	for _, imp := range imps {
   139  		if imp.ID == bid.ImpID {
   140  			if imp.Banner != nil {
   141  				return openrtb_ext.BidTypeBanner, nil
   142  			}
   143  			if imp.Video != nil {
   144  				return openrtb_ext.BidTypeVideo, nil
   145  			}
   146  			if imp.Native != nil {
   147  				return openrtb_ext.BidTypeNative, nil
   148  			}
   149  		}
   150  	}
   151  
   152  	// This shouldnt happen. Lets handle it just incase by returning an error.
   153  	return "", &errortypes.BadInput{
   154  		Message: fmt.Sprintf("Failed to find impression \"%s\"", bid.ImpID),
   155  	}
   156  }