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

     1  package silvermob
     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  type SilverMobAdapter struct {
    18  	endpoint *template.Template
    19  }
    20  
    21  func isValidHost(host string) bool {
    22  	return host == "eu" || host == "us" || host == "apac"
    23  }
    24  
    25  // Builder builds a new instance of the SilverMob adapter for the given bidder with the given config.
    26  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
    27  	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
    28  	if err != nil {
    29  		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
    30  	}
    31  
    32  	bidder := &SilverMobAdapter{
    33  		endpoint: template,
    34  	}
    35  	return bidder, nil
    36  }
    37  
    38  func GetHeaders(request *openrtb2.BidRequest) *http.Header {
    39  	headers := http.Header{}
    40  	headers.Add("Content-Type", "application/json;charset=utf-8")
    41  	headers.Add("Accept", "application/json")
    42  	headers.Add("X-Openrtb-Version", "2.5")
    43  
    44  	if request.Device != nil {
    45  		if len(request.Device.UA) > 0 {
    46  			headers.Add("User-Agent", request.Device.UA)
    47  		}
    48  
    49  		if len(request.Device.IPv6) > 0 {
    50  			headers.Add("X-Forwarded-For", request.Device.IPv6)
    51  		}
    52  
    53  		if len(request.Device.IP) > 0 {
    54  			headers.Add("X-Forwarded-For", request.Device.IP)
    55  		}
    56  	}
    57  
    58  	return &headers
    59  }
    60  
    61  func (a *SilverMobAdapter) MakeRequests(
    62  	openRTBRequest *openrtb2.BidRequest,
    63  	reqInfo *adapters.ExtraRequestInfo,
    64  ) (
    65  	[]*adapters.RequestData,
    66  	[]error,
    67  ) {
    68  	requestCopy := *openRTBRequest
    69  	impCount := len(openRTBRequest.Imp)
    70  	requestData := make([]*adapters.RequestData, 0, impCount)
    71  	errs := []error{}
    72  
    73  	var err error
    74  
    75  	for _, imp := range openRTBRequest.Imp {
    76  		var silvermobExt *openrtb_ext.ExtSilverMob
    77  
    78  		silvermobExt, err = a.getImpressionExt(&imp)
    79  
    80  		if err != nil {
    81  			errs = append(errs, err)
    82  			continue
    83  		}
    84  
    85  		url, err := a.buildEndpointURL(silvermobExt)
    86  		if err != nil {
    87  			errs = append(errs, err)
    88  			continue
    89  		}
    90  
    91  		requestCopy.Imp = []openrtb2.Imp{imp}
    92  		reqJSON, err := json.Marshal(requestCopy)
    93  		if err != nil {
    94  			errs = append(errs, err)
    95  			continue
    96  		}
    97  
    98  		reqData := &adapters.RequestData{
    99  			Method:  http.MethodPost,
   100  			Body:    reqJSON,
   101  			Uri:     url,
   102  			Headers: *GetHeaders(&requestCopy),
   103  			ImpIDs:  openrtb_ext.GetImpIDs(requestCopy.Imp),
   104  		}
   105  
   106  		requestData = append(requestData, reqData)
   107  	}
   108  
   109  	return requestData, errs
   110  }
   111  
   112  func (a *SilverMobAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtSilverMob, error) {
   113  	var bidderExt adapters.ExtImpBidder
   114  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
   115  		return nil, &errortypes.BadInput{
   116  			Message: fmt.Sprintf("error unmarshaling imp.ext: %s", err.Error()),
   117  		}
   118  	}
   119  	var silvermobExt openrtb_ext.ExtSilverMob
   120  	if err := json.Unmarshal(bidderExt.Bidder, &silvermobExt); err != nil {
   121  		return nil, &errortypes.BadInput{
   122  			Message: fmt.Sprintf("error unmarshaling imp.ext.bidder: %s", err.Error()),
   123  		}
   124  	}
   125  	return &silvermobExt, nil
   126  }
   127  
   128  func (a *SilverMobAdapter) buildEndpointURL(params *openrtb_ext.ExtSilverMob) (string, error) {
   129  	if isValidHost(params.Host) {
   130  		endpointParams := macros.EndpointTemplateParams{ZoneID: params.ZoneID, Host: params.Host}
   131  		return macros.ResolveMacros(a.endpoint, endpointParams)
   132  	} else {
   133  		return "", &errortypes.BadInput{
   134  			Message: fmt.Sprintf("invalid host %s", params.Host),
   135  		}
   136  	}
   137  }
   138  
   139  func (a *SilverMobAdapter) MakeBids(
   140  	openRTBRequest *openrtb2.BidRequest,
   141  	requestToBidder *adapters.RequestData,
   142  	bidderRawResponse *adapters.ResponseData,
   143  ) (
   144  	bidderResponse *adapters.BidderResponse,
   145  	errs []error,
   146  ) {
   147  
   148  	if bidderRawResponse.StatusCode == http.StatusNoContent {
   149  		return nil, nil
   150  	}
   151  
   152  	if bidderRawResponse.StatusCode == http.StatusBadRequest {
   153  		return nil, []error{&errortypes.BadInput{
   154  			Message: fmt.Sprintf("Bad Request status code: %d. Run with request.debug = 1 for more info", bidderRawResponse.StatusCode),
   155  		}}
   156  	}
   157  
   158  	if bidderRawResponse.StatusCode != http.StatusOK {
   159  		return nil, []error{fmt.Errorf("Unexpected status code: %d. Run with request.debug = 1 for more info", bidderRawResponse.StatusCode)}
   160  	}
   161  
   162  	responseBody := bidderRawResponse.Body
   163  	var bidResp openrtb2.BidResponse
   164  	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
   165  		return nil, []error{&errortypes.BadServerResponse{
   166  			Message: fmt.Sprintf("Error unmarshaling server Response: %s", err),
   167  		}}
   168  	}
   169  
   170  	if len(bidResp.SeatBid) == 0 {
   171  		return nil, []error{&errortypes.BadServerResponse{
   172  			Message: "Empty SeatBid array",
   173  		}}
   174  	}
   175  
   176  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   177  
   178  	for _, sb := range bidResp.SeatBid {
   179  		for _, bid := range sb.Bid {
   180  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   181  				Bid:     &bid,
   182  				BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
   183  			})
   184  		}
   185  	}
   186  
   187  	return bidResponse, nil
   188  }
   189  
   190  func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
   191  	mediaType := openrtb_ext.BidTypeBanner
   192  	for _, imp := range imps {
   193  		if imp.ID == impId {
   194  			if imp.Video != nil {
   195  				mediaType = openrtb_ext.BidTypeVideo
   196  			} else if imp.Native != nil {
   197  				mediaType = openrtb_ext.BidTypeNative
   198  			}
   199  			return mediaType
   200  		}
   201  	}
   202  	return mediaType
   203  }