github.com/prebid/prebid-server/v2@v2.18.0/adapters/adtrgtme/adtrgtme.go (about) 1 package adtrgtme 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/prebid/openrtb/v20/openrtb2" 9 10 "github.com/prebid/prebid-server/v2/adapters" 11 "github.com/prebid/prebid-server/v2/config" 12 "github.com/prebid/prebid-server/v2/errortypes" 13 "github.com/prebid/prebid-server/v2/openrtb_ext" 14 ) 15 16 type adapter struct { 17 endpoint string 18 } 19 20 // Builder builds a new instance of the Adtrgtme adapter for the given bidder with the given config. 21 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 22 bidder := &adapter{ 23 endpoint: config.Endpoint, 24 } 25 return bidder, nil 26 } 27 28 func (v *adapter) MakeRequests( 29 openRTBRequest *openrtb2.BidRequest, 30 requestInfo *adapters.ExtraRequestInfo, 31 ) ( 32 []*adapters.RequestData, 33 []error, 34 ) { 35 var requests []*adapters.RequestData 36 var errors []error 37 38 requestCopy := *openRTBRequest 39 for _, imp := range openRTBRequest.Imp { 40 siteID, err := getSiteIDFromImp(&imp) 41 if err != nil { 42 errors = append(errors, err) 43 continue 44 } 45 46 imp.Ext = nil 47 requestCopy.Imp = []openrtb2.Imp{imp} 48 49 requestBody, err := json.Marshal(requestCopy) 50 if err != nil { 51 errors = append(errors, err) 52 continue 53 } 54 55 requestData := &adapters.RequestData{ 56 Method: http.MethodPost, 57 Uri: v.buildRequestURI(siteID), 58 Body: requestBody, 59 Headers: makeRequestHeaders(openRTBRequest), 60 ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), 61 } 62 63 requests = append(requests, requestData) 64 } 65 return requests, errors 66 } 67 68 func getSiteIDFromImp(imp *openrtb2.Imp) (uint64, error) { 69 var bidderExt adapters.ExtImpBidder 70 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 71 return 0, &errortypes.BadInput{ 72 Message: "ext.bidder not provided", 73 } 74 } 75 var ext openrtb_ext.ExtImpAdtrgtme 76 if err := json.Unmarshal(bidderExt.Bidder, &ext); err != nil { 77 return 0, &errortypes.BadInput{ 78 Message: "ext.bidder not provided", 79 } 80 } 81 return ext.SiteID, nil 82 } 83 84 func (v *adapter) buildRequestURI(siteID uint64) string { 85 return fmt.Sprintf("%s?s=%d&prebid", v.endpoint, siteID) 86 } 87 88 func makeRequestHeaders(openRTBRequest *openrtb2.BidRequest) http.Header { 89 headers := http.Header{} 90 headers.Add("Content-Type", "application/json;charset=utf-8") 91 headers.Add("Accept", "application/json") 92 headers.Add("X-Openrtb-Version", "2.5") 93 94 if openRTBRequest.Device != nil { 95 if len(openRTBRequest.Device.UA) > 0 { 96 headers.Add("User-Agent", openRTBRequest.Device.UA) 97 } 98 99 if len(openRTBRequest.Device.IPv6) > 0 { 100 headers.Add("X-Forwarded-For", openRTBRequest.Device.IPv6) 101 } 102 103 if len(openRTBRequest.Device.IP) > 0 { 104 headers.Add("X-Forwarded-For", openRTBRequest.Device.IP) 105 } 106 } 107 return headers 108 } 109 110 func (v *adapter) checkResponseStatusCodes(response *adapters.ResponseData) error { 111 if response.StatusCode == http.StatusBadRequest { 112 return &errortypes.BadInput{ 113 Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode), 114 } 115 } 116 117 if response.StatusCode == http.StatusServiceUnavailable { 118 return &errortypes.BadInput{ 119 Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode), 120 } 121 } 122 123 if response.StatusCode != http.StatusOK { 124 return &errortypes.BadInput{ 125 Message: fmt.Sprintf("Unexpected status code: [ %d ]. Run with request.debug = 1 for more info", response.StatusCode), 126 } 127 } 128 129 return nil 130 } 131 132 func (v *adapter) MakeBids( 133 openRTBRequest *openrtb2.BidRequest, 134 requestToBidder *adapters.RequestData, 135 bidderRawResponse *adapters.ResponseData, 136 ) ( 137 *adapters.BidderResponse, 138 []error, 139 ) { 140 if bidderRawResponse.StatusCode == http.StatusNoContent { 141 return nil, nil 142 } 143 144 httpStatusError := v.checkResponseStatusCodes(bidderRawResponse) 145 if httpStatusError != nil { 146 return nil, []error{httpStatusError} 147 } 148 149 var response openrtb2.BidResponse 150 if err := json.Unmarshal(bidderRawResponse.Body, &response); err != nil { 151 return nil, []error{&errortypes.BadServerResponse{ 152 Message: "Bad Server Response", 153 }} 154 } 155 156 if len(response.SeatBid) == 0 { 157 return nil, []error{&errortypes.BadServerResponse{ 158 Message: "Empty SeatBid array", 159 }} 160 } 161 162 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRTBRequest.Imp)) 163 bidResponse.Currency = response.Cur 164 for _, seatBid := range response.SeatBid { 165 for i, bid := range seatBid.Bid { 166 bidType, err := getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp) 167 if err != nil { 168 return nil, []error{err} 169 } 170 171 b := &adapters.TypedBid{ 172 Bid: &seatBid.Bid[i], 173 BidType: bidType, 174 } 175 bidResponse.Bids = append(bidResponse.Bids, b) 176 } 177 } 178 return bidResponse, nil 179 } 180 181 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { 182 for _, imp := range imps { 183 if imp.ID == impId { 184 if imp.Banner != nil { 185 return openrtb_ext.BidTypeBanner, nil 186 } else { 187 return "", &errortypes.BadInput{ 188 Message: fmt.Sprintf("Unsupported bidtype for bid: \"%s\"", impId), 189 } 190 } 191 } 192 } 193 return "", &errortypes.BadInput{ 194 Message: fmt.Sprintf("Failed to find impression: \"%s\"", impId), 195 } 196 }