github.com/prebid/prebid-server@v0.275.0/adapters/sharethrough/sharethrough.go (about) 1 package sharethrough 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 9 "github.com/prebid/openrtb/v19/openrtb2" 10 "github.com/prebid/prebid-server/adapters" 11 "github.com/prebid/prebid-server/config" 12 "github.com/prebid/prebid-server/errortypes" 13 "github.com/prebid/prebid-server/openrtb_ext" 14 "github.com/prebid/prebid-server/version" 15 ) 16 17 var adapterVersion = "10.0" 18 19 type adapter struct { 20 endpoint string 21 } 22 23 // Builder builds a new instance of the Sharethrough adapter for the given bidder with the given config. 24 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 25 bidder := &adapter{ 26 endpoint: config.Endpoint, 27 } 28 return bidder, nil 29 } 30 31 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 32 var requests []*adapters.RequestData 33 var errors []error 34 35 headers := http.Header{} 36 headers.Add("Content-Type", "application/json;charset=utf-8") 37 headers.Add("Accept", "application/json") 38 39 modifiableSource := openrtb2.Source{} 40 if request.Source != nil { 41 modifiableSource = *request.Source 42 } 43 var sourceExt map[string]interface{} 44 if err := json.Unmarshal(modifiableSource.Ext, &sourceExt); err == nil { 45 sourceExt["str"] = adapterVersion 46 sourceExt["version"] = version.Ver 47 } else { 48 sourceExt = map[string]interface{}{"str": adapterVersion, "version": version.Ver} 49 } 50 51 var err error 52 if modifiableSource.Ext, err = json.Marshal(sourceExt); err != nil { 53 errors = append(errors, err) 54 } 55 request.Source = &modifiableSource 56 57 requestCopy := *request 58 for _, imp := range request.Imp { 59 // Extract Sharethrough Params 60 var strImpExt adapters.ExtImpBidder 61 if err := json.Unmarshal(imp.Ext, &strImpExt); err != nil { 62 errors = append(errors, err) 63 continue 64 } 65 var strImpParams openrtb_ext.ExtImpSharethrough 66 if err := json.Unmarshal(strImpExt.Bidder, &strImpParams); err != nil { 67 errors = append(errors, err) 68 continue 69 } 70 71 // Convert Floor into USD 72 if imp.BidFloor > 0 && imp.BidFloorCur != "" && !strings.EqualFold(imp.BidFloorCur, "USD") { 73 convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") 74 if err != nil { 75 return nil, []error{err} 76 } 77 imp.BidFloorCur = "USD" 78 imp.BidFloor = convertedValue 79 } 80 81 // Relocate Custom Params 82 imp.TagID = strImpParams.Pkey 83 requestCopy.BCat = append(requestCopy.BCat, strImpParams.BCat...) 84 requestCopy.BAdv = append(requestCopy.BAdv, strImpParams.BAdv...) 85 86 impressionsByMediaType, err := splitImpressionsByMediaType(&imp) 87 if err != nil { 88 errors = append(errors, err) 89 continue 90 } 91 92 for _, impression := range impressionsByMediaType { 93 requestCopy.Imp = []openrtb2.Imp{impression} 94 95 requestJSON, err := json.Marshal(requestCopy) 96 if err != nil { 97 errors = append(errors, err) 98 continue 99 } 100 101 requestData := &adapters.RequestData{ 102 Method: "POST", 103 Uri: a.endpoint, 104 Body: requestJSON, 105 Headers: headers, 106 } 107 requests = append(requests, requestData) 108 } 109 } 110 111 return requests, errors 112 } 113 114 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 115 if response.StatusCode == http.StatusNoContent { 116 return nil, nil 117 } 118 119 if response.StatusCode == http.StatusBadRequest { 120 return nil, []error{&errortypes.BadInput{ 121 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 122 }} 123 } 124 125 if response.StatusCode != http.StatusOK { 126 return nil, []error{fmt.Errorf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)} 127 } 128 129 var bidReq openrtb2.BidRequest 130 if err := json.Unmarshal(requestData.Body, &bidReq); err != nil { 131 return nil, []error{err} 132 } 133 134 var bidResp openrtb2.BidResponse 135 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 136 return nil, []error{err} 137 } 138 139 bidderResponse := adapters.NewBidderResponse() 140 bidderResponse.Currency = "USD" 141 var errors []error 142 143 for _, seatBid := range bidResp.SeatBid { 144 for i := range seatBid.Bid { 145 bid := &seatBid.Bid[i] 146 bidType, err := getMediaTypeForBid(*bid) 147 if err != nil { 148 errors = append(errors, err) 149 } 150 151 bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ 152 BidType: bidType, 153 Bid: bid, 154 }) 155 } 156 } 157 158 return bidderResponse, errors 159 } 160 161 func splitImpressionsByMediaType(impression *openrtb2.Imp) ([]openrtb2.Imp, error) { 162 if impression.Banner == nil && impression.Video == nil && impression.Native == nil { 163 return nil, &errortypes.BadInput{Message: "Invalid MediaType. Sharethrough only supports Banner, Video and Native."} 164 } 165 166 if impression.Audio != nil { 167 impression.Audio = nil 168 } 169 170 impressions := make([]openrtb2.Imp, 0, 3) 171 172 if impression.Banner != nil { 173 impCopy := *impression 174 impCopy.Video = nil 175 impCopy.Native = nil 176 impressions = append(impressions, impCopy) 177 } 178 179 if impression.Video != nil { 180 impCopy := *impression 181 impCopy.Banner = nil 182 impCopy.Native = nil 183 impressions = append(impressions, impCopy) 184 } 185 186 if impression.Native != nil { 187 impression.Banner = nil 188 impression.Video = nil 189 impressions = append(impressions, *impression) 190 } 191 192 return impressions, nil 193 } 194 195 func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { 196 197 if bid.Ext != nil { 198 var bidExt openrtb_ext.ExtBid 199 err := json.Unmarshal(bid.Ext, &bidExt) 200 if err == nil && bidExt.Prebid != nil { 201 return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) 202 } 203 } 204 205 return "", &errortypes.BadServerResponse{ 206 Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID), 207 } 208 }