github.com/prebid/prebid-server/v2@v2.18.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/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/macros"
    14  	"github.com/prebid/prebid-server/v2/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  		ImpIDs:  openrtb_ext.GetImpIDs(openRTBRequest.Imp),
   103  	}}, nil
   104  }
   105  
   106  func (a *adapter) MakeBids(
   107  	openRTBRequest *openrtb2.BidRequest,
   108  	requestToBidder *adapters.RequestData,
   109  	bidderRawResponse *adapters.ResponseData,
   110  ) (
   111  	*adapters.BidderResponse,
   112  	[]error,
   113  ) {
   114  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   115  		return nil, nil
   116  	}
   117  
   118  	if bidderRawResponse.StatusCode == http.StatusBadRequest {
   119  		return nil, []error{&errortypes.BadInput{
   120  			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
   121  		}}
   122  	}
   123  
   124  	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
   125  		return nil, []error{&errortypes.BadInput{
   126  			Message: "Bidder unavailable. Please contact the bidder support.",
   127  		}}
   128  	}
   129  
   130  	if bidderRawResponse.StatusCode != http.StatusOK {
   131  		return nil, []error{&errortypes.BadServerResponse{
   132  			Message: fmt.Sprintf("Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
   133  		}}
   134  	}
   135  
   136  	responseBody := bidderRawResponse.Body
   137  	var bidResp openrtb2.BidResponse
   138  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   139  		return nil, []error{err}
   140  	}
   141  
   142  	if len(bidResp.SeatBid) == 0 {
   143  		return nil, []error{&errortypes.BadServerResponse{
   144  			Message: "Array SeatBid cannot be empty",
   145  		}}
   146  	}
   147  
   148  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   149  
   150  	bids := bidResp.SeatBid[0].Bid
   151  
   152  	if len(bids) == 0 {
   153  		return nil, []error{&errortypes.BadServerResponse{
   154  			Message: "Array SeatBid[0].Bid cannot be empty",
   155  		}}
   156  	}
   157  
   158  	bid := bids[0]
   159  
   160  	var bidExt bidExt
   161  	var bidType openrtb_ext.BidType
   162  
   163  	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
   164  		return nil, []error{&errortypes.BadServerResponse{
   165  			Message: "Field BidExt is required",
   166  		}}
   167  	}
   168  
   169  	bidType, err := getBidType(bidExt)
   170  
   171  	if err != nil {
   172  		return nil, []error{err}
   173  	}
   174  
   175  	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   176  		Bid:     &bid,
   177  		BidType: bidType,
   178  	})
   179  	return bidResponse, nil
   180  }
   181  
   182  func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
   183  	return openrtb_ext.ParseBidType(ext.MediaType)
   184  }