github.com/prebid/prebid-server@v0.275.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/v19/openrtb2"
     9  	"github.com/prebid/prebid-server/adapters"
    10  	"github.com/prebid/prebid-server/config"
    11  	"github.com/prebid/prebid-server/errortypes"
    12  	"github.com/prebid/prebid-server/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}, nil
   106  }
   107  
   108  func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) *openrtb2.BidRequest {
   109  	bidRequest := *prebidBidRequest
   110  	bidRequest.Imp = imps
   111  	for idx := range bidRequest.Imp {
   112  		imp := &bidRequest.Imp[idx]
   113  		imp.TagID = params.Tid
   114  		imp.Ext = nil
   115  	}
   116  	return &bidRequest
   117  }
   118  
   119  // MakeBids translates Logicad bid response to prebid-server specific format
   120  func (adapter *LogicadAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   121  	if response.StatusCode == http.StatusNoContent {
   122  		return nil, nil
   123  	}
   124  	if response.StatusCode != http.StatusOK {
   125  		msg := fmt.Sprintf("Unexpected http status code: %d", response.StatusCode)
   126  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   127  
   128  	}
   129  	var bidResp openrtb2.BidResponse
   130  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   131  		msg := fmt.Sprintf("Bad server response: %d", err)
   132  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   133  	}
   134  	if len(bidResp.SeatBid) != 1 {
   135  		msg := fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid))
   136  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   137  	}
   138  
   139  	seatBid := bidResp.SeatBid[0]
   140  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seatBid.Bid))
   141  
   142  	for i := 0; i < len(seatBid.Bid); i++ {
   143  		bid := seatBid.Bid[i]
   144  		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   145  			Bid:     &bid,
   146  			BidType: openrtb_ext.BidTypeBanner,
   147  		})
   148  	}
   149  	if bidResp.Cur != "" {
   150  		bidResponse.Currency = bidResp.Cur
   151  	}
   152  	return bidResponse, nil
   153  }
   154  
   155  // Builder builds a new instance of the Logicad adapter for the given bidder with the given config.
   156  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   157  	bidder := &LogicadAdapter{
   158  		endpoint: config.Endpoint,
   159  	}
   160  	return bidder, nil
   161  }