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

     1  package krushmedia
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"text/template"
     9  
    10  	"github.com/prebid/openrtb/v20/openrtb2"
    11  	"github.com/prebid/prebid-server/v2/adapters"
    12  	"github.com/prebid/prebid-server/v2/config"
    13  	"github.com/prebid/prebid-server/v2/errortypes"
    14  	"github.com/prebid/prebid-server/v2/macros"
    15  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    16  )
    17  
    18  type KrushmediaAdapter struct {
    19  	endpoint *template.Template
    20  }
    21  
    22  // Builder builds a new instance of the KrushmediaA adapter for the given bidder with the given config.
    23  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    24  	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
    25  	if err != nil {
    26  		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
    27  	}
    28  
    29  	bidder := &KrushmediaAdapter{
    30  		endpoint: template,
    31  	}
    32  	return bidder, nil
    33  }
    34  
    35  func getHeaders(request *openrtb2.BidRequest) *http.Header {
    36  	headers := http.Header{}
    37  	headers.Add("Content-Type", "application/json;charset=utf-8")
    38  	headers.Add("Accept", "application/json")
    39  	headers.Add("X-Openrtb-Version", "2.5")
    40  
    41  	if request.Device != nil {
    42  		if len(request.Device.UA) > 0 {
    43  			headers.Add("User-Agent", request.Device.UA)
    44  		}
    45  
    46  		if len(request.Device.IP) > 0 {
    47  			headers.Add("X-Forwarded-For", request.Device.IP)
    48  		}
    49  
    50  		if len(request.Device.Language) > 0 {
    51  			headers.Add("Accept-Language", request.Device.Language)
    52  		}
    53  
    54  		if request.Device.DNT != nil {
    55  			headers.Add("Dnt", strconv.Itoa(int(*request.Device.DNT)))
    56  		}
    57  	}
    58  
    59  	return &headers
    60  }
    61  
    62  func (a *KrushmediaAdapter) MakeRequests(
    63  	openRTBRequest *openrtb2.BidRequest,
    64  	reqInfo *adapters.ExtraRequestInfo,
    65  ) (
    66  	requestsToBidder []*adapters.RequestData,
    67  	errs []error,
    68  ) {
    69  
    70  	request := *openRTBRequest
    71  
    72  	var errors []error
    73  	var krushmediaExt *openrtb_ext.ExtKrushmedia
    74  	var err error
    75  
    76  	if len(request.Imp) > 0 {
    77  		krushmediaExt, err = a.getImpressionExt(&(request.Imp[0]))
    78  		if err != nil {
    79  			errors = append(errors, err)
    80  		}
    81  		request.Imp[0].Ext = nil
    82  	} else {
    83  		errors = append(errors, &errortypes.BadInput{
    84  			Message: "Missing Imp Object",
    85  		})
    86  	}
    87  
    88  	if len(errors) > 0 {
    89  		return nil, errors
    90  	}
    91  
    92  	url, err := a.buildEndpointURL(krushmediaExt)
    93  	if err != nil {
    94  		return nil, []error{err}
    95  	}
    96  
    97  	reqJSON, err := json.Marshal(request)
    98  	if err != nil {
    99  		return nil, []error{err}
   100  	}
   101  
   102  	return []*adapters.RequestData{{
   103  		Method:  http.MethodPost,
   104  		Body:    reqJSON,
   105  		Uri:     url,
   106  		Headers: *getHeaders(&request),
   107  		ImpIDs:  openrtb_ext.GetImpIDs(request.Imp),
   108  	}}, nil
   109  }
   110  
   111  func (a *KrushmediaAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtKrushmedia, error) {
   112  	var bidderExt adapters.ExtImpBidder
   113  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
   114  		return nil, &errortypes.BadInput{
   115  			Message: "Bidder extension not provided or can't be unmarshalled",
   116  		}
   117  	}
   118  	var krushmediaExt openrtb_ext.ExtKrushmedia
   119  	if err := json.Unmarshal(bidderExt.Bidder, &krushmediaExt); err != nil {
   120  		return nil, &errortypes.BadInput{
   121  			Message: "Error while unmarshaling bidder extension",
   122  		}
   123  	}
   124  	return &krushmediaExt, nil
   125  }
   126  
   127  func (a *KrushmediaAdapter) buildEndpointURL(params *openrtb_ext.ExtKrushmedia) (string, error) {
   128  	endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID}
   129  	return macros.ResolveMacros(a.endpoint, endpointParams)
   130  }
   131  
   132  func (a *KrushmediaAdapter) MakeBids(
   133  	openRTBRequest *openrtb2.BidRequest,
   134  	requestToBidder *adapters.RequestData,
   135  	bidderRawResponse *adapters.ResponseData,
   136  ) (
   137  	bidderResponse *adapters.BidderResponse,
   138  	errs []error,
   139  ) {
   140  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   141  		return nil, nil
   142  	}
   143  
   144  	if bidderRawResponse.StatusCode == http.StatusBadRequest {
   145  		return nil, []error{&errortypes.BadInput{
   146  			Message: fmt.Sprintf("Unexpected status code: [ %d ]", bidderRawResponse.StatusCode),
   147  		}}
   148  	}
   149  
   150  	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
   151  		return nil, nil
   152  	}
   153  
   154  	if bidderRawResponse.StatusCode != http.StatusOK {
   155  		return nil, []error{&errortypes.BadServerResponse{
   156  			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", bidderRawResponse.StatusCode),
   157  		}}
   158  	}
   159  
   160  	responseBody := bidderRawResponse.Body
   161  	var bidResp openrtb2.BidResponse
   162  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   163  		return nil, []error{&errortypes.BadServerResponse{
   164  			Message: "Bad Server Response",
   165  		}}
   166  	}
   167  
   168  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
   169  	sb := bidResp.SeatBid[0]
   170  
   171  	for _, bid := range sb.Bid {
   172  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   173  			Bid:     &bid,
   174  			BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
   175  		})
   176  	}
   177  	return bidResponse, nil
   178  }
   179  
   180  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
   181  	mediaType := openrtb_ext.BidTypeBanner
   182  	for _, imp := range imps {
   183  		if imp.ID == impId {
   184  			if imp.Video != nil {
   185  				mediaType = openrtb_ext.BidTypeVideo
   186  			} else if imp.Native != nil {
   187  				mediaType = openrtb_ext.BidTypeNative
   188  			}
   189  			return mediaType
   190  		}
   191  	}
   192  	return mediaType
   193  }