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

     1  package logicad
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"github.com/prebid/openrtb/v20/openrtb2"
     9  	"github.com/prebid/prebid-server/v2/adapters"
    10  	"github.com/prebid/prebid-server/v2/config"
    11  	"github.com/prebid/prebid-server/v2/errortypes"
    12  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    13  )
    14  
    15  type LogicadAdapter struct {
    16  	endpoint string
    17  }
    18  
    19  func (adapter *LogicadAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    20  	if len(request.Imp) == 0 {
    21  		return nil, []error{&errortypes.BadInput{Message: "No impression in the bid request"}}
    22  	}
    23  
    24  	pub2impressions, imps, errs := getImpressionsInfo(request.Imp)
    25  	if len(pub2impressions) == 0 || len(imps) == 0 {
    26  		return nil, errs
    27  	}
    28  
    29  	result := make([]*adapters.RequestData, 0, len(pub2impressions))
    30  	for k, imps := range pub2impressions {
    31  		bidRequest, err := adapter.buildAdapterRequest(request, &k, imps)
    32  		if err != nil {
    33  			errs = append(errs, err)
    34  		} else {
    35  			result = append(result, bidRequest)
    36  		}
    37  	}
    38  	return result, errs
    39  }
    40  
    41  func getImpressionsInfo(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpLogicad][]openrtb2.Imp, []openrtb2.Imp, []error) {
    42  	errors := make([]error, 0, len(imps))
    43  	resImps := make([]openrtb2.Imp, 0, len(imps))
    44  	res := make(map[openrtb_ext.ExtImpLogicad][]openrtb2.Imp)
    45  
    46  	for _, imp := range imps {
    47  		impExt, err := getImpressionExt(&imp)
    48  		if err != nil {
    49  			errors = append(errors, err)
    50  			continue
    51  		}
    52  		if err := validateImpression(&impExt); err != nil {
    53  			errors = append(errors, err)
    54  			continue
    55  		}
    56  
    57  		if res[impExt] == nil {
    58  			res[impExt] = make([]openrtb2.Imp, 0)
    59  		}
    60  		res[impExt] = append(res[impExt], imp)
    61  		resImps = append(resImps, imp)
    62  	}
    63  	return res, resImps, errors
    64  }
    65  
    66  func validateImpression(impExt *openrtb_ext.ExtImpLogicad) error {
    67  	if impExt.Tid == "" {
    68  		return &errortypes.BadInput{Message: "No tid value provided"}
    69  	}
    70  	return nil
    71  }
    72  
    73  func getImpressionExt(imp *openrtb2.Imp) (openrtb_ext.ExtImpLogicad, error) {
    74  	var bidderExt adapters.ExtImpBidder
    75  	var logicadExt openrtb_ext.ExtImpLogicad
    76  
    77  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    78  		return logicadExt, &errortypes.BadInput{
    79  			Message: err.Error(),
    80  		}
    81  	}
    82  	if err := json.Unmarshal(bidderExt.Bidder, &logicadExt); err != nil {
    83  		return logicadExt, &errortypes.BadInput{
    84  			Message: err.Error(),
    85  		}
    86  	}
    87  	return logicadExt, nil
    88  }
    89  
    90  func (adapter *LogicadAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) (*adapters.RequestData, error) {
    91  	newBidRequest := createBidRequest(prebidBidRequest, params, imps)
    92  	reqJSON, err := json.Marshal(newBidRequest)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	headers := http.Header{}
    98  	headers.Add("Content-Type", "application/json;charset=utf-8")
    99  	headers.Add("Accept", "application/json")
   100  
   101  	return &adapters.RequestData{
   102  		Method:  "POST",
   103  		Uri:     adapter.endpoint,
   104  		Body:    reqJSON,
   105  		Headers: headers,
   106  		ImpIDs:  openrtb_ext.GetImpIDs(imps)}, nil
   107  }
   108  
   109  func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) *openrtb2.BidRequest {
   110  	bidRequest := *prebidBidRequest
   111  	bidRequest.Imp = imps
   112  	for idx := range bidRequest.Imp {
   113  		imp := &bidRequest.Imp[idx]
   114  		imp.TagID = params.Tid
   115  		imp.Ext = nil
   116  	}
   117  	return &bidRequest
   118  }
   119  
   120  // MakeBids translates Logicad bid response to prebid-server specific format
   121  func (adapter *LogicadAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   122  	if response.StatusCode == http.StatusNoContent {
   123  		return nil, nil
   124  	}
   125  	if response.StatusCode != http.StatusOK {
   126  		msg := fmt.Sprintf("Unexpected http status code: %d", response.StatusCode)
   127  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   128  
   129  	}
   130  	var bidResp openrtb2.BidResponse
   131  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   132  		msg := fmt.Sprintf("Bad server response: %d", err)
   133  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   134  	}
   135  	if len(bidResp.SeatBid) != 1 {
   136  		msg := fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid))
   137  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   138  	}
   139  
   140  	seatBid := bidResp.SeatBid[0]
   141  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seatBid.Bid))
   142  
   143  	for i := 0; i < len(seatBid.Bid); i++ {
   144  		bid := seatBid.Bid[i]
   145  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   146  			Bid:     &bid,
   147  			BidType: openrtb_ext.BidTypeBanner,
   148  		})
   149  	}
   150  	if bidResp.Cur != "" {
   151  		bidResponse.Currency = bidResp.Cur
   152  	}
   153  	return bidResponse, nil
   154  }
   155  
   156  // Builder builds a new instance of the Logicad adapter for the given bidder with the given config.
   157  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   158  	bidder := &LogicadAdapter{
   159  		endpoint: config.Endpoint,
   160  	}
   161  	return bidder, nil
   162  }