github.com/prebid/prebid-server/v2@v2.18.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/v20/openrtb2" 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 "github.com/prebid/prebid-server/v2/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 ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), 107 } 108 requests = append(requests, requestData) 109 } 110 } 111 112 return requests, errors 113 } 114 115 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 116 if response.StatusCode == http.StatusNoContent { 117 return nil, nil 118 } 119 120 if response.StatusCode == http.StatusBadRequest { 121 return nil, []error{&errortypes.BadInput{ 122 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 123 }} 124 } 125 126 if response.StatusCode != http.StatusOK { 127 return nil, []error{fmt.Errorf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)} 128 } 129 130 var bidReq openrtb2.BidRequest 131 if err := json.Unmarshal(requestData.Body, &bidReq); err != nil { 132 return nil, []error{err} 133 } 134 135 var bidResp openrtb2.BidResponse 136 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 137 return nil, []error{err} 138 } 139 140 bidderResponse := adapters.NewBidderResponse() 141 bidderResponse.Currency = "USD" 142 var errors []error 143 144 for _, seatBid := range bidResp.SeatBid { 145 for i := range seatBid.Bid { 146 bid := &seatBid.Bid[i] 147 bidType, err := getMediaTypeForBid(*bid) 148 if err != nil { 149 errors = append(errors, err) 150 } 151 152 bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ 153 BidType: bidType, 154 Bid: bid, 155 }) 156 } 157 } 158 159 return bidderResponse, errors 160 } 161 162 func splitImpressionsByMediaType(impression *openrtb2.Imp) ([]openrtb2.Imp, error) { 163 if impression.Banner == nil && impression.Video == nil && impression.Native == nil { 164 return nil, &errortypes.BadInput{Message: "Invalid MediaType. Sharethrough only supports Banner, Video and Native."} 165 } 166 167 if impression.Audio != nil { 168 impression.Audio = nil 169 } 170 171 impressions := make([]openrtb2.Imp, 0, 3) 172 173 if impression.Banner != nil { 174 impCopy := *impression 175 impCopy.Video = nil 176 impCopy.Native = nil 177 impressions = append(impressions, impCopy) 178 } 179 180 if impression.Video != nil { 181 impCopy := *impression 182 impCopy.Banner = nil 183 impCopy.Native = nil 184 impressions = append(impressions, impCopy) 185 } 186 187 if impression.Native != nil { 188 impression.Banner = nil 189 impression.Video = nil 190 impressions = append(impressions, *impression) 191 } 192 193 return impressions, nil 194 } 195 196 func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { 197 198 if bid.Ext != nil { 199 var bidExt openrtb_ext.ExtBid 200 err := json.Unmarshal(bid.Ext, &bidExt) 201 if err == nil && bidExt.Prebid != nil { 202 return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) 203 } 204 } 205 206 return "", &errortypes.BadServerResponse{ 207 Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID), 208 } 209 }