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

     1  package nextmillennium
     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 adapter struct {
    16  	endpoint string
    17  }
    18  
    19  type nmExtPrebidStoredRequest struct {
    20  	ID string `json:"id"`
    21  }
    22  type nmExtPrebid struct {
    23  	StoredRequest nmExtPrebidStoredRequest `json:"storedrequest"`
    24  }
    25  type nextMillJsonExt struct {
    26  	Prebid nmExtPrebid `json:"prebid"`
    27  }
    28  
    29  // MakeRequests prepares request information for prebid-server core
    30  func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
    31  	resImps, err := getImpressionsInfo(request.Imp)
    32  	if len(err) > 0 {
    33  		return nil, err
    34  	}
    35  
    36  	result := make([]*adapters.RequestData, 0, len(resImps))
    37  	for _, imp := range resImps {
    38  		bidRequest, err := adapter.buildAdapterRequest(request, imp)
    39  		if err != nil {
    40  			return nil, []error{err}
    41  		}
    42  		result = append(result, bidRequest)
    43  	}
    44  
    45  	return result, nil
    46  }
    47  
    48  func getImpressionsInfo(imps []openrtb2.Imp) (resImps []*openrtb_ext.ImpExtNextMillennium, errors []error) {
    49  	for _, imp := range imps {
    50  		impExt, err := getImpressionExt(&imp)
    51  		if err != nil {
    52  			errors = append(errors, err)
    53  			continue
    54  		}
    55  
    56  		resImps = append(resImps, impExt)
    57  	}
    58  
    59  	return
    60  }
    61  
    62  func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtNextMillennium, error) {
    63  	var bidderExt adapters.ExtImpBidder
    64  	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
    65  		return nil, &errortypes.BadInput{
    66  			Message: err.Error(),
    67  		}
    68  	}
    69  	var nextMillenniumExt openrtb_ext.ImpExtNextMillennium
    70  	if err := json.Unmarshal(bidderExt.Bidder, &nextMillenniumExt); err != nil {
    71  		return nil, &errortypes.BadInput{
    72  			Message: err.Error(),
    73  		}
    74  	}
    75  
    76  	return &nextMillenniumExt, nil
    77  }
    78  
    79  func (adapter *adapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium) (*adapters.RequestData, error) {
    80  	newBidRequest := createBidRequest(prebidBidRequest, params)
    81  
    82  	reqJSON, err := json.Marshal(newBidRequest)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	headers := http.Header{}
    88  	headers.Add("Content-Type", "application/json;charset=utf-8")
    89  	headers.Add("Accept", "application/json")
    90  	headers.Add("x-openrtb-version", "2.5")
    91  
    92  	return &adapters.RequestData{
    93  		Method:  "POST",
    94  		Uri:     adapter.endpoint,
    95  		Body:    reqJSON,
    96  		Headers: headers}, nil
    97  }
    98  
    99  func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ImpExtNextMillennium) *openrtb2.BidRequest {
   100  	placementID := params.PlacementID
   101  
   102  	if params.GroupID != "" {
   103  		domain := ""
   104  		size := ""
   105  
   106  		if prebidBidRequest.Site != nil {
   107  			domain = prebidBidRequest.Site.Domain
   108  		}
   109  		if prebidBidRequest.App != nil {
   110  			domain = prebidBidRequest.App.Domain
   111  		}
   112  
   113  		if banner := prebidBidRequest.Imp[0].Banner; banner != nil {
   114  			if len(banner.Format) > 0 {
   115  				size = fmt.Sprintf("%dx%d", banner.Format[0].W, banner.Format[0].H)
   116  			} else if banner.W != nil && banner.H != nil {
   117  				size = fmt.Sprintf("%dx%d", *banner.W, *banner.H)
   118  			}
   119  		}
   120  
   121  		placementID = fmt.Sprintf("g%s;%s;%s", params.GroupID, size, domain)
   122  	}
   123  	ext := nextMillJsonExt{}
   124  	ext.Prebid.StoredRequest.ID = placementID
   125  	jsonExt, err := json.Marshal(ext)
   126  	if err != nil {
   127  		return prebidBidRequest
   128  	}
   129  	bidRequest := *prebidBidRequest
   130  	bidRequest.Ext = jsonExt
   131  	bidRequest.Imp[0].Ext = jsonExt
   132  	return &bidRequest
   133  }
   134  
   135  // MakeBids translates NextMillennium bid response to prebid-server specific format
   136  func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
   137  	var msg = ""
   138  	if response.StatusCode == http.StatusNoContent {
   139  		return nil, nil
   140  	}
   141  	if response.StatusCode != http.StatusOK {
   142  		msg = fmt.Sprintf("Unexpected http status code: %d", response.StatusCode)
   143  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   144  
   145  	}
   146  
   147  	var bidResp openrtb2.BidResponse
   148  	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
   149  		msg = fmt.Sprintf("Bad server response: %d", err)
   150  		return nil, []error{&errortypes.BadServerResponse{Message: msg}}
   151  	}
   152  
   153  	if len(bidResp.SeatBid) == 0 {
   154  		return nil, nil
   155  	}
   156  
   157  	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
   158  
   159  	for _, sb := range bidResp.SeatBid {
   160  		for i := range sb.Bid {
   161  			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
   162  				Bid:     &sb.Bid[i],
   163  				BidType: openrtb_ext.BidTypeBanner,
   164  			})
   165  		}
   166  	}
   167  	return bidResponse, nil
   168  }
   169  
   170  // Builder builds a new instance of the NextMillennium adapter for the given bidder with the given config.
   171  func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
   172  	return &adapter{
   173  		endpoint: config.Endpoint,
   174  	}, nil
   175  }