github.com/prebid/prebid-server/v2@v2.18.0/adapters/impactify/impactify.go (about) 1 package impactify 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 9 "github.com/prebid/openrtb/v20/openrtb2" 10 11 "github.com/prebid/prebid-server/v2/adapters" 12 "github.com/prebid/prebid-server/v2/config" 13 "github.com/prebid/prebid-server/v2/errortypes" 14 "github.com/prebid/prebid-server/v2/openrtb_ext" 15 ) 16 17 type adapter struct { 18 endpoint string 19 } 20 21 type ImpactifyExtBidder struct { 22 Impactify openrtb_ext.ExtImpImpactify `json:"impactify"` 23 } 24 25 type DefaultExtBidder struct { 26 Bidder openrtb_ext.ExtImpImpactify `json:"bidder"` 27 } 28 29 func (a *adapter) MakeRequests(bidRequest *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 30 var adapterRequests []*adapters.RequestData 31 32 for i := 0; i < len(bidRequest.Imp); i++ { 33 // Check if imp comes with bid floor amount defined in a foreign currency 34 if bidRequest.Imp[i].BidFloor > 0 && bidRequest.Imp[i].BidFloorCur != "" && strings.ToUpper(bidRequest.Imp[i].BidFloorCur) != "USD" { 35 // Convert to US dollars 36 convertedValue, err := reqInfo.ConvertCurrency(bidRequest.Imp[i].BidFloor, bidRequest.Imp[i].BidFloorCur, "USD") 37 if err != nil { 38 return nil, []error{err} 39 } 40 bidRequest.Imp[i].BidFloorCur = "USD" 41 bidRequest.Imp[i].BidFloor = convertedValue 42 } 43 44 // Set the CUR of bid to USD after converting all floors 45 bidRequest.Cur = []string{"USD"} 46 47 var impactifyExt ImpactifyExtBidder 48 49 var defaultExt DefaultExtBidder 50 err := json.Unmarshal(bidRequest.Imp[i].Ext, &defaultExt) 51 if err != nil { 52 return nil, []error{&errortypes.BadInput{ 53 Message: fmt.Sprintf("Unable to decode the imp ext : \"%s\"", bidRequest.Imp[i].ID), 54 }} 55 } 56 57 impactifyExt.Impactify = defaultExt.Bidder 58 bidRequest.Imp[i].Ext, err = json.Marshal(impactifyExt) 59 if err != nil { 60 return nil, []error{&errortypes.BadInput{ 61 Message: fmt.Sprintf("Unable to decode the imp ext : \"%s\"", bidRequest.Imp[i].ID), 62 }} 63 } 64 } 65 66 if len(bidRequest.Imp) == 0 { 67 return nil, []error{&errortypes.BadInput{ 68 Message: "No valid impressions in the bid request", 69 }} 70 } 71 72 reqJSON, err := json.Marshal(bidRequest) 73 if err != nil { 74 return nil, []error{err} 75 } 76 77 headers := http.Header{} 78 headers.Add("Content-Type", "application/json;charset=utf-8") 79 headers.Add("Accept", "application/json") 80 headers.Add("x-openrtb-version", "2.5") 81 if bidRequest.Device != nil { 82 if bidRequest.Device.UA != "" { 83 headers.Add("User-Agent", bidRequest.Device.UA) 84 } 85 // Add IPv4 or IPv6 if available 86 if bidRequest.Device.IP != "" { 87 headers.Add("X-Forwarded-For", bidRequest.Device.IP) 88 } else if bidRequest.Device.IPv6 != "" { 89 headers.Add("X-Forwarded-For", bidRequest.Device.IPv6) 90 } 91 } 92 if bidRequest.Site != nil { 93 headers.Add("Referer", bidRequest.Site.Page) 94 } 95 96 // set user's cookie 97 if bidRequest.User != nil && bidRequest.User.BuyerUID != "" { 98 headers.Add("Cookie", "uids="+bidRequest.User.BuyerUID) 99 } 100 101 adapterRequests = append(adapterRequests, &adapters.RequestData{ 102 Method: "POST", 103 Uri: a.endpoint, 104 Body: reqJSON, 105 Headers: headers, 106 ImpIDs: openrtb_ext.GetImpIDs(bidRequest.Imp), 107 }) 108 109 return adapterRequests, nil 110 } 111 112 func (a *adapter) MakeBids( 113 internalRequest *openrtb2.BidRequest, 114 externalRequest *adapters.RequestData, 115 response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 116 117 if response.StatusCode == http.StatusNoContent { 118 return nil, nil 119 } else if response.StatusCode == http.StatusBadRequest { 120 return nil, []error{&errortypes.BadInput{ 121 Message: "Invalid request.", 122 }} 123 } else if response.StatusCode != http.StatusOK { 124 return nil, []error{&errortypes.BadServerResponse{ 125 Message: fmt.Sprintf("Unexpected HTTP status %d.", response.StatusCode), 126 }} 127 } 128 129 var openRtbBidResponse openrtb2.BidResponse 130 131 if err := json.Unmarshal(response.Body, &openRtbBidResponse); err != nil { 132 return nil, []error{&errortypes.BadServerResponse{ 133 Message: "Bad server body response", 134 }} 135 } 136 137 if len(openRtbBidResponse.SeatBid) == 0 { 138 return nil, nil 139 } 140 141 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRtbBidResponse.SeatBid[0].Bid)) 142 bidResponse.Currency = openRtbBidResponse.Cur 143 144 sb := openRtbBidResponse.SeatBid[0] 145 for i := 0; i < len(sb.Bid); i++ { 146 if !(sb.Bid[i].Price > 0) { 147 continue 148 } 149 150 impMediaType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) 151 if err != nil { 152 return nil, []error{err} 153 } 154 155 bid := sb.Bid[i] 156 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 157 Bid: &bid, 158 BidType: impMediaType, 159 }) 160 } 161 return bidResponse, nil 162 } 163 164 func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { 165 for _, imp := range imps { 166 if imp.ID == impID { 167 if imp.Banner != nil { 168 return openrtb_ext.BidTypeBanner, nil 169 } else if imp.Video != nil { 170 return openrtb_ext.BidTypeVideo, nil 171 } 172 } 173 } 174 175 return "", &errortypes.BadInput{ 176 Message: fmt.Sprintf("Failed to find a supported media type impression \"%s\"", impID), 177 } 178 } 179 180 // Builder builds a new instance of the Impactify adapter for the given bidder with the given config. 181 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 182 bidder := &adapter{ 183 endpoint: config.Endpoint, 184 } 185 return bidder, nil 186 }