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

     1  package ownadx
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"github.com/prebid/openrtb/v19/openrtb2"
     7  	"github.com/prebid/prebid-server/adapters"
     8  	"github.com/prebid/prebid-server/config"
     9  	"github.com/prebid/prebid-server/errortypes"
    10  	"github.com/prebid/prebid-server/macros"
    11  	"github.com/prebid/prebid-server/openrtb_ext"
    12  	"net/http"
    13  	"text/template"
    14  )
    15  
    16  type adapter struct {
    17  	endpoint *template.Template
    18  }
    19  type bidExt struct {
    20  	MediaType string `json:"mediaType"`
    21  }
    22  
    23  func (adapter *adapter) getRequestData(bidRequest *openrtb2.BidRequest, impExt *openrtb_ext.ExtImpOwnAdx, imps []openrtb2.Imp) (*adapters.RequestData, error) {
    24  	pbidRequest := createBidRequest(bidRequest, imps)
    25  	reqJSON, err := json.Marshal(pbidRequest)
    26  	if err != nil {
    27  		return nil, &errortypes.BadInput{
    28  			Message: "Prebid bidder request not valid or can't be marshalled. Err: " + err.Error(),
    29  		}
    30  	}
    31  	url, err := adapter.buildEndpointURL(impExt)
    32  	if err != nil {
    33  		return nil, &errortypes.BadInput{
    34  			Message: "Error while creating endpoint. Err: " + err.Error(),
    35  		}
    36  	}
    37  
    38  	headers := http.Header{}
    39  	headers.Add("Content-Type", "application/json;charset=utf-8")
    40  	headers.Add("Accept", "application/json")
    41  	headers.Add("x-openrtb-version", "2.5")
    42  
    43  	return &adapters.RequestData{
    44  		Method:  "POST",
    45  		Uri:     url,
    46  		Body:    reqJSON,
    47  		Headers: headers}, nil
    48  
    49  }
    50  func createBidRequest(rtbBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp) *openrtb2.BidRequest {
    51  	bidRequest := *rtbBidRequest
    52  	bidRequest.Imp = imps
    53  	return &bidRequest
    54  }
    55  func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ExtImpOwnAdx) (string, error) {
    56  	endpointParams := macros.EndpointTemplateParams{
    57  		ZoneID:    params.SspId,
    58  		AccountID: params.SeatId,
    59  		SourceId:  params.TokenId,
    60  	}
    61  	return macros.ResolveMacros(adapter.endpoint, endpointParams)
    62  }
    63  
    64  func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpOwnAdx, error) {
    65  	var bidderExt adapters.ExtImpBidder
    66  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    67  		return nil, &errortypes.BadInput{
    68  			Message: "Bidder extension not valid or can't be unmarshalled",
    69  		}
    70  	}
    71  
    72  	var ownAdxExt openrtb_ext.ExtImpOwnAdx
    73  	if err := json.Unmarshal(bidderExt.Bidder, &ownAdxExt); err != nil {
    74  		return nil, &errortypes.BadInput{
    75  			Message: "Error while unmarshaling bidder extension",
    76  		}
    77  	}
    78  
    79  	return &ownAdxExt, nil
    80  }
    81  
    82  func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    83  
    84  	errs := make([]error, 0, len(request.Imp))
    85  	if len(request.Imp) == 0 {
    86  		errs = append(errs, &errortypes.BadInput{
    87  			Message: "No impression in the bid request"},
    88  		)
    89  		return nil, errs
    90  	}
    91  	extImps, errors := groupImpsByExt(request.Imp)
    92  	if len(errors) != 0 {
    93  		errs = append(errs, errors...)
    94  	}
    95  	if len(extImps) == 0 {
    96  		return nil, errs
    97  	}
    98  	reqDetail := make([]*adapters.RequestData, 0, len(extImps))
    99  	for k, imps := range extImps {
   100  		bidRequest, err := adapter.getRequestData(request, &k, imps)
   101  		if err != nil {
   102  			errs = append(errs, err)
   103  		} else {
   104  			reqDetail = append(reqDetail, bidRequest)
   105  		}
   106  	}
   107  	return reqDetail, errs
   108  }
   109  func groupImpsByExt(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp, []error) {
   110  	respExt := make(map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp)
   111  	errors := make([]error, 0, len(imps))
   112  	for _, imp := range imps {
   113  		ownAdxExt, err := getImpressionExt(&(imp))
   114  		if err != nil {
   115  			errors = append(errors, err)
   116  			continue
   117  		}
   118  
   119  		respExt[*ownAdxExt] = append(respExt[*ownAdxExt], imp)
   120  	}
   121  	return respExt, errors
   122  }
   123  
   124  func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   125  	if response.StatusCode == http.StatusNoContent {
   126  		return nil, nil
   127  	}
   128  	if response.StatusCode == http.StatusBadRequest {
   129  		return nil, []error{
   130  			&errortypes.BadServerResponse{
   131  				Message: fmt.Sprintf("Bad request: %d", response.StatusCode),
   132  			},
   133  		}
   134  	}
   135  	if response.StatusCode != http.StatusOK {
   136  		return nil, []error{
   137  			&errortypes.BadServerResponse{
   138  				Message: fmt.Sprintf("Unexpected status code: %d. Run with request.test = 1 for more info.", response.StatusCode),
   139  			},
   140  		}
   141  	}
   142  	var bidResp openrtb2.BidResponse
   143  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   144  		return nil, []error{
   145  			&errortypes.BadServerResponse{
   146  				Message: fmt.Sprintf("Bad server response "),
   147  			},
   148  		}
   149  	}
   150  	if len(bidResp.SeatBid) == 0 {
   151  		return nil, []error{
   152  			&errortypes.BadServerResponse{
   153  				Message: fmt.Sprintf("Array SeatBid cannot be empty "),
   154  			},
   155  		}
   156  	}
   157  
   158  	seatBid := bidResp.SeatBid[0]
   159  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
   160  	if len(seatBid.Bid) == 0 {
   161  		return nil, []error{
   162  			&errortypes.BadServerResponse{
   163  				Message: fmt.Sprintf("Bid cannot be empty "),
   164  			},
   165  		}
   166  	}
   167  	for i := 0; i < len(seatBid.Bid); i++ {
   168  		var bidType openrtb_ext.BidType
   169  		bid := seatBid.Bid[i]
   170  
   171  		bidType, err := getMediaType(bid)
   172  		if err != nil {
   173  			return nil, []error{&errortypes.BadServerResponse{
   174  				Message: "Bid type is invalid",
   175  			}}
   176  		}
   177  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   178  			Bid:     &bid,
   179  			BidType: bidType,
   180  		})
   181  	}
   182  
   183  	return bidResponse, nil
   184  }
   185  
   186  // Builder builds a new instance of the OwnAdx adapter for the given bidder with the given config
   187  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   188  	template, err := template.New("endpointTemplate").Parse(config.Endpoint)
   189  	if err != nil {
   190  		return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
   191  	}
   192  
   193  	bidder := &adapter{
   194  		endpoint: template,
   195  	}
   196  
   197  	return bidder, nil
   198  }
   199  
   200  func getMediaType(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
   201  	switch bid.MType {
   202  	case openrtb2.MarkupBanner:
   203  		return openrtb_ext.BidTypeBanner, nil
   204  	case openrtb2.MarkupVideo:
   205  		return openrtb_ext.BidTypeVideo, nil
   206  	case openrtb2.MarkupAudio:
   207  		return openrtb_ext.BidTypeAudio, nil
   208  	case openrtb2.MarkupNative:
   209  		return openrtb_ext.BidTypeNative, nil
   210  	default:
   211  		return "", fmt.Errorf("invalid BidType: %d", bid.MType)
   212  	}
   213  }