github.com/prebid/prebid-server/v2@v2.18.0/adapters/seedingAlliance/seedingAlliance.go (about) 1 package seedingAlliance 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 "strings" 9 "text/template" 10 11 "github.com/prebid/openrtb/v20/openrtb2" 12 "github.com/prebid/prebid-server/v2/adapters" 13 "github.com/prebid/prebid-server/v2/config" 14 "github.com/prebid/prebid-server/v2/errortypes" 15 "github.com/prebid/prebid-server/v2/macros" 16 "github.com/prebid/prebid-server/v2/openrtb_ext" 17 ) 18 19 type adapter struct { 20 endpoint *template.Template 21 } 22 23 func Builder(_ openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 24 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 25 if err != nil { 26 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 27 } 28 29 bidder := &adapter{ 30 endpoint: template, 31 } 32 return bidder, nil 33 } 34 35 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, extraRequestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 36 var accountId string 37 var err error 38 39 for i := range request.Imp { 40 if accountId, err = getExtInfo(&request.Imp[i]); err != nil { 41 return nil, []error{err} 42 } 43 } 44 45 if !curExists(request.Cur, "EUR") { 46 request.Cur = append(request.Cur, "EUR") 47 } 48 49 requestJSON, err := json.Marshal(request) 50 if err != nil { 51 return nil, []error{err} 52 } 53 54 url, err := macros.ResolveMacros(a.endpoint, macros.EndpointTemplateParams{AccountID: accountId}) 55 if err != nil { 56 return nil, []error{err} 57 } 58 59 requestData := &adapters.RequestData{ 60 Method: http.MethodPost, 61 Uri: url, 62 Body: requestJSON, 63 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 64 } 65 66 return []*adapters.RequestData{requestData}, nil 67 } 68 69 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 70 if responseData.StatusCode == http.StatusNoContent { 71 return nil, nil 72 } 73 74 if responseData.StatusCode == http.StatusBadRequest { 75 err := &errortypes.BadInput{ 76 Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", 77 } 78 return nil, []error{err} 79 } 80 81 if responseData.StatusCode != http.StatusOK { 82 err := &errortypes.BadServerResponse{ 83 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), 84 } 85 return nil, []error{err} 86 } 87 88 var response openrtb2.BidResponse 89 if err := json.Unmarshal(responseData.Body, &response); err != nil { 90 return nil, []error{err} 91 } 92 93 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 94 bidResponse.Currency = response.Cur 95 96 var errs []error 97 98 for _, seatBid := range response.SeatBid { 99 for i := range seatBid.Bid { 100 resolvePriceMacro(&seatBid.Bid[i]) 101 102 bidType, err := getMediaTypeForBid(seatBid.Bid[i].Ext) 103 if err != nil { 104 errs = append(errs, err) 105 continue 106 } 107 108 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 109 Bid: &seatBid.Bid[i], 110 BidType: bidType, 111 }) 112 } 113 } 114 115 return bidResponse, errs 116 } 117 118 func resolvePriceMacro(bid *openrtb2.Bid) { 119 price := strconv.FormatFloat(bid.Price, 'f', -1, 64) 120 bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) 121 } 122 123 func getMediaTypeForBid(ext json.RawMessage) (openrtb_ext.BidType, error) { 124 var bidExt openrtb_ext.ExtBid 125 126 if err := json.Unmarshal(ext, &bidExt); err != nil { 127 return "", fmt.Errorf("could not unmarshal openrtb_ext.ExtBid: %w", err) 128 } 129 130 if bidExt.Prebid == nil { 131 return "", fmt.Errorf("bid.Ext.Prebid is empty") 132 } 133 134 return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) 135 } 136 137 func curExists(allowedCurrencies []string, newCurrency string) bool { 138 for i := range allowedCurrencies { 139 if allowedCurrencies[i] == newCurrency { 140 return true 141 } 142 } 143 return false 144 } 145 146 func getExtInfo(imp *openrtb2.Imp) (string, error) { 147 var ext adapters.ExtImpBidder 148 var extSA openrtb_ext.ImpExtSeedingAlliance 149 150 accountId := "pbs" 151 152 if err := json.Unmarshal(imp.Ext, &ext); err != nil { 153 return "", fmt.Errorf("could not unmarshal adapters.ExtImpBidder: %w", err) 154 } 155 156 if err := json.Unmarshal(ext.Bidder, &extSA); err != nil { 157 return "", fmt.Errorf("could not unmarshal openrtb_ext.ImpExtSeedingAlliance: %w", err) 158 } 159 160 imp.TagID = extSA.AdUnitID 161 162 if extSA.SeatID != "" { 163 accountId = extSA.SeatID 164 } 165 166 if extSA.AccountID != "" { 167 accountId = extSA.AccountID 168 } 169 170 return accountId, nil 171 }