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

     1  package smarthub
     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  const (
    18  	ADAPTER_VER = "1.0.0"
    19  )
    20  
    21  type adapter struct {
    22  	endpoint *template.Template
    23  }
    24  
    25  type bidExt struct {
    26  	MediaType string `json:"mediaType"`
    27  }
    28  
    29  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    30  	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
    31  	if err != nil {
    32  		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
    33  	}
    34  
    35  	bidder := &adapter{
    36  		endpoint: template,
    37  	}
    38  
    39  	return bidder, nil
    40  }
    41  
    42  func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtSmartHub, error) {
    43  	var bidderExt adapters.ExtImpBidder
    44  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    45  		return nil, &errortypes.BadInput{
    46  			Message: "Bidder extension not provided or can't be unmarshalled",
    47  		}
    48  	}
    49  
    50  	var smarthubExt openrtb_ext.ExtSmartHub
    51  	if err := json.Unmarshal(bidderExt.Bidder, &smarthubExt); err != nil {
    52  		return nil, &errortypes.BadInput{
    53  			Message: "Error while unmarshaling bidder extension",
    54  		}
    55  	}
    56  
    57  	return &smarthubExt, nil
    58  }
    59  
    60  func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtSmartHub) (string, error) {
    61  	endpointParams := macros.EndpointTemplateParams{
    62  		Host:      params.PartnerName,
    63  		AccountID: params.Seat,
    64  		SourceId:  params.Token,
    65  	}
    66  	return macros.ResolveMacros(a.endpoint, endpointParams)
    67  }
    68  
    69  func (a *adapter) MakeRequests(
    70  	openRTBRequest *openrtb2.BidRequest,
    71  	reqInfo *adapters.ExtraRequestInfo,
    72  ) (
    73  	[]*adapters.RequestData,
    74  	[]error,
    75  ) {
    76  	var smarthubExt *openrtb_ext.ExtSmartHub
    77  	smarthubExt, err := a.getImpressionExt(&(openRTBRequest.Imp[0]))
    78  	if err != nil {
    79  		return nil, []error{err}
    80  	}
    81  
    82  	url, err := a.buildEndpointURL(smarthubExt)
    83  	if err != nil {
    84  		return nil, []error{err}
    85  	}
    86  
    87  	reqJSON, err := json.Marshal(openRTBRequest)
    88  	if err != nil {
    89  		return nil, []error{err}
    90  	}
    91  
    92  	headers := http.Header{}
    93  	headers.Add("Content-Type", "application/json;charset=utf-8")
    94  	headers.Add("Accept", "application/json")
    95  	headers.Add("Prebid-Adapter-Ver", ADAPTER_VER)
    96  
    97  	return []*adapters.RequestData{{
    98  		Method:  http.MethodPost,
    99  		Body:    reqJSON,
   100  		Uri:     url,
   101  		Headers: headers,
   102  	}}, nil
   103  }
   104  
   105  func (a *adapter) MakeBids(
   106  	openRTBRequest *openrtb2.BidRequest,
   107  	requestToBidder *adapters.RequestData,
   108  	bidderRawResponse *adapters.ResponseData,
   109  ) (
   110  	*adapters.BidderResponse,
   111  	[]error,
   112  ) {
   113  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   114  		return nil, nil
   115  	}
   116  
   117  	if bidderRawResponse.StatusCode == http.StatusBadRequest {
   118  		return nil, []error{&errortypes.BadInput{
   119  			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
   120  		}}
   121  	}
   122  
   123  	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
   124  		return nil, []error{&errortypes.BadInput{
   125  			Message: "Bidder unavailable. Please contact the bidder support.",
   126  		}}
   127  	}
   128  
   129  	if bidderRawResponse.StatusCode != http.StatusOK {
   130  		return nil, []error{&errortypes.BadServerResponse{
   131  			Message: fmt.Sprintf("Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
   132  		}}
   133  	}
   134  
   135  	responseBody := bidderRawResponse.Body
   136  	var bidResp openrtb2.BidResponse
   137  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   138  		return nil, []error{err}
   139  	}
   140  
   141  	if len(bidResp.SeatBid) == 0 {
   142  		return nil, []error{&errortypes.BadServerResponse{
   143  			Message: "Array SeatBid cannot be empty",
   144  		}}
   145  	}
   146  
   147  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   148  
   149  	bids := bidResp.SeatBid[0].Bid
   150  
   151  	if len(bids) == 0 {
   152  		return nil, []error{&errortypes.BadServerResponse{
   153  			Message: "Array SeatBid[0].Bid cannot be empty",
   154  		}}
   155  	}
   156  
   157  	bid := bids[0]
   158  
   159  	var bidExt bidExt
   160  	var bidType openrtb_ext.BidType
   161  
   162  	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
   163  		return nil, []error{&errortypes.BadServerResponse{
   164  			Message: "Field BidExt is required",
   165  		}}
   166  	}
   167  
   168  	bidType, err := getBidType(bidExt)
   169  
   170  	if err != nil {
   171  		return nil, []error{err}
   172  	}
   173  
   174  	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   175  		Bid:     &bid,
   176  		BidType: bidType,
   177  	})
   178  	return bidResponse, nil
   179  }
   180  
   181  func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
   182  	return openrtb_ext.ParseBidType(ext.MediaType)
   183  }