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

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