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

     1  package smartyads
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"text/template"
     9  
    10  	"github.com/prebid/openrtb/v19/openrtb2"
    11  	"github.com/prebid/prebid-server/adapters"
    12  	"github.com/prebid/prebid-server/config"
    13  	"github.com/prebid/prebid-server/errortypes"
    14  	"github.com/prebid/prebid-server/macros"
    15  	"github.com/prebid/prebid-server/openrtb_ext"
    16  )
    17  
    18  type SmartyAdsAdapter struct {
    19  	endpoint *template.Template
    20  }
    21  
    22  // Builder builds a new instance of the SmartyAds 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 := &SmartyAdsAdapter{
    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.IPv6) > 0 {
    47  			headers.Add("X-Forwarded-For", request.Device.IPv6)
    48  		}
    49  
    50  		if len(request.Device.IP) > 0 {
    51  			headers.Add("X-Forwarded-For", request.Device.IP)
    52  		}
    53  
    54  		if len(request.Device.Language) > 0 {
    55  			headers.Add("Accept-Language", request.Device.Language)
    56  		}
    57  
    58  		if request.Device.DNT != nil {
    59  			headers.Add("Dnt", strconv.Itoa(int(*request.Device.DNT)))
    60  		}
    61  	}
    62  
    63  	return &headers
    64  }
    65  
    66  func (a *SmartyAdsAdapter) MakeRequests(
    67  	openRTBRequest *openrtb2.BidRequest,
    68  	reqInfo *adapters.ExtraRequestInfo,
    69  ) (
    70  	requestsToBidder []*adapters.RequestData,
    71  	errs []error,
    72  ) {
    73  
    74  	var errors []error
    75  	var smartyadsExt *openrtb_ext.ExtSmartyAds
    76  	var err error
    77  
    78  	for i, imp := range openRTBRequest.Imp {
    79  		smartyadsExt, err = a.getImpressionExt(&imp)
    80  		if err != nil {
    81  			errors = append(errors, err)
    82  			break
    83  		}
    84  		openRTBRequest.Imp[i].Ext = nil
    85  	}
    86  
    87  	if len(errors) > 0 {
    88  		return nil, errors
    89  	}
    90  
    91  	url, err := a.buildEndpointURL(smartyadsExt)
    92  	if err != nil {
    93  		return nil, []error{err}
    94  	}
    95  
    96  	reqJSON, err := json.Marshal(openRTBRequest)
    97  	if err != nil {
    98  		return nil, []error{err}
    99  	}
   100  
   101  	return []*adapters.RequestData{{
   102  		Method:  http.MethodPost,
   103  		Body:    reqJSON,
   104  		Uri:     url,
   105  		Headers: *GetHeaders(openRTBRequest),
   106  	}}, nil
   107  }
   108  
   109  func (a *SmartyAdsAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtSmartyAds, error) {
   110  	var bidderExt adapters.ExtImpBidder
   111  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
   112  		return nil, &errortypes.BadInput{
   113  			Message: "ext.bidder not provided",
   114  		}
   115  	}
   116  	var smartyadsExt openrtb_ext.ExtSmartyAds
   117  	if err := json.Unmarshal(bidderExt.Bidder, &smartyadsExt); err != nil {
   118  		return nil, &errortypes.BadInput{
   119  			Message: "ext.bidder not provided",
   120  		}
   121  	}
   122  	return &smartyadsExt, nil
   123  }
   124  
   125  func (a *SmartyAdsAdapter) buildEndpointURL(params *openrtb_ext.ExtSmartyAds) (string, error) {
   126  	endpointParams := macros.EndpointTemplateParams{Host: params.Host, SourceId: params.SourceID, AccountID: params.AccountID}
   127  	return macros.ResolveMacros(a.endpoint, endpointParams)
   128  }
   129  
   130  func (a *SmartyAdsAdapter) CheckResponseStatusCodes(response *adapters.ResponseData) error {
   131  	if response.StatusCode == http.StatusNoContent {
   132  		return &errortypes.BadInput{Message: "No bid response"}
   133  	}
   134  
   135  	if response.StatusCode == http.StatusBadRequest {
   136  		return &errortypes.BadInput{
   137  			Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
   138  		}
   139  	}
   140  
   141  	if response.StatusCode == http.StatusServiceUnavailable {
   142  		return &errortypes.BadInput{
   143  			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
   144  		}
   145  	}
   146  
   147  	if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices {
   148  		return &errortypes.BadInput{
   149  			Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func (a *SmartyAdsAdapter) MakeBids(
   157  	openRTBRequest *openrtb2.BidRequest,
   158  	requestToBidder *adapters.RequestData,
   159  	bidderRawResponse *adapters.ResponseData,
   160  ) (
   161  	bidderResponse *adapters.BidderResponse,
   162  	errs []error,
   163  ) {
   164  	httpStatusError := a.CheckResponseStatusCodes(bidderRawResponse)
   165  	if httpStatusError != nil {
   166  		return nil, []error{httpStatusError}
   167  	}
   168  
   169  	responseBody := bidderRawResponse.Body
   170  	var bidResp openrtb2.BidResponse
   171  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   172  		return nil, []error{&errortypes.BadServerResponse{
   173  			Message: "Bad Server Response",
   174  		}}
   175  	}
   176  
   177  	if len(bidResp.SeatBid) == 0 {
   178  		return nil, []error{&errortypes.BadServerResponse{
   179  			Message: "Empty SeatBid array",
   180  		}}
   181  	}
   182  
   183  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
   184  	sb := bidResp.SeatBid[0]
   185  
   186  	for _, bid := range sb.Bid {
   187  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   188  			Bid:     &bid,
   189  			BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
   190  		})
   191  	}
   192  	return bidResponse, nil
   193  }
   194  
   195  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
   196  	mediaType := openrtb_ext.BidTypeBanner
   197  	for _, imp := range imps {
   198  		if imp.ID == impId {
   199  			if imp.Video != nil {
   200  				mediaType = openrtb_ext.BidTypeVideo
   201  			} else if imp.Native != nil {
   202  				mediaType = openrtb_ext.BidTypeNative
   203  			}
   204  			return mediaType
   205  		}
   206  	}
   207  	return mediaType
   208  }