github.com/prebid/prebid-server/v2@v2.18.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/v20/openrtb2"
    10  	"github.com/prebid/prebid-server/v2/adapters"
    11  	"github.com/prebid/prebid-server/v2/config"
    12  	"github.com/prebid/prebid-server/v2/errortypes"
    13  	"github.com/prebid/prebid-server/v2/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  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
    77  	}, errs
    78  }
    79  
    80  // MakeBids makes the bids
    81  func (a *ColossusAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
    82  	var errs []error
    83  
    84  	if response.StatusCode == http.StatusNoContent {
    85  		return nil, nil
    86  	}
    87  
    88  	if response.StatusCode == http.StatusNotFound {
    89  		return nil, []error{&errortypes.BadServerResponse{
    90  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    91  		}}
    92  	}
    93  
    94  	if response.StatusCode != http.StatusOK {
    95  		return nil, []error{&errortypes.BadServerResponse{
    96  			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
    97  		}}
    98  	}
    99  
   100  	var bidResp openrtb2.BidResponse
   101  
   102  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   103  		return nil, []error{err}
   104  	}
   105  
   106  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   107  
   108  	for _, sb := range bidResp.SeatBid {
   109  		for i := range sb.Bid {
   110  			bidType, err := getMediaTypeForImp(sb.Bid[i], internalRequest.Imp)
   111  			if err != nil {
   112  				errs = append(errs, err)
   113  			} else {
   114  				b := &adapters.TypedBid{
   115  					Bid:     &sb.Bid[i],
   116  					BidType: bidType,
   117  				}
   118  				bidResponse.Bids = append(bidResponse.Bids, b)
   119  			}
   120  		}
   121  	}
   122  	return bidResponse, errs
   123  }
   124  
   125  func getMediaTypeForImp(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
   126  	var bidExt ColossusResponseBidExt
   127  	err := json.Unmarshal(bid.Ext, &bidExt)
   128  	if err == nil {
   129  		switch bidExt.MediaType {
   130  		case "banner":
   131  			return openrtb_ext.BidTypeBanner, nil
   132  		case "native":
   133  			return openrtb_ext.BidTypeNative, nil
   134  		case "video":
   135  			return openrtb_ext.BidTypeVideo, nil
   136  		}
   137  	}
   138  
   139  	for _, imp := range imps {
   140  		if imp.ID == bid.ImpID {
   141  			if imp.Banner != nil {
   142  				return openrtb_ext.BidTypeBanner, nil
   143  			}
   144  			if imp.Video != nil {
   145  				return openrtb_ext.BidTypeVideo, nil
   146  			}
   147  			if imp.Native != nil {
   148  				return openrtb_ext.BidTypeNative, nil
   149  			}
   150  		}
   151  	}
   152  
   153  	// This shouldnt happen. Lets handle it just incase by returning an error.
   154  	return "", &errortypes.BadInput{
   155  		Message: fmt.Sprintf("Failed to find impression \"%s\"", bid.ImpID),
   156  	}
   157  }