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 }