github.com/prebid/prebid-server/v2@v2.18.0/adapters/aso/aso.go (about) 1 package aso 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(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 24 endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) 25 if err != nil { 26 return nil, fmt.Errorf("unable to parse endpoint template: %v", err) 27 } 28 29 bidder := &adapter{ 30 endpoint: endpointTemplate, 31 } 32 return bidder, nil 33 } 34 35 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 36 37 var requests []*adapters.RequestData 38 var errors []error 39 40 requestCopy := *request 41 42 for _, imp := range request.Imp { 43 var bidderExt adapters.ExtImpBidder 44 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 45 errors = append(errors, &errortypes.BadInput{ 46 Message: fmt.Sprintf("invalid imp.ext, %s", err.Error()), 47 }) 48 continue 49 } 50 51 var impExt openrtb_ext.ExtImpAso 52 if err := json.Unmarshal(bidderExt.Bidder, &impExt); err != nil { 53 errors = append(errors, &errortypes.BadInput{ 54 Message: fmt.Sprintf("invalid bidderExt.Bidder, %s", err.Error()), 55 }) 56 continue 57 } 58 59 requestCopy.Imp = []openrtb2.Imp{imp} 60 endpoint, err := a.buildEndpointURL(&impExt) 61 62 if err != nil { 63 errors = append(errors, err) 64 continue 65 } 66 67 reqJSON, err := json.Marshal(requestCopy) 68 if err != nil { 69 errors = append(errors, err) 70 continue 71 } 72 73 headers := http.Header{} 74 headers.Add("Content-Type", "application/json;charset=utf-8") 75 headers.Add("Accept", "application/json") 76 77 requestData := &adapters.RequestData{ 78 Method: http.MethodPost, 79 Uri: endpoint, 80 Body: reqJSON, 81 Headers: headers, 82 ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), 83 } 84 requests = append(requests, requestData) 85 } 86 return requests, errors 87 } 88 89 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 90 if adapters.IsResponseStatusCodeNoContent(responseData) { 91 return nil, nil 92 } 93 94 if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { 95 return nil, []error{err} 96 } 97 98 var response openrtb2.BidResponse 99 if err := json.Unmarshal(responseData.Body, &response); err != nil { 100 return nil, []error{err} 101 } 102 103 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 104 bidResponse.Currency = response.Cur 105 106 var errors []error 107 for _, seatBid := range response.SeatBid { 108 for i, bid := range seatBid.Bid { 109 resolveMacros(&seatBid.Bid[i]) 110 111 bidType, err := getMediaType(bid) 112 if err != nil { 113 errors = append(errors, err) 114 continue 115 } 116 117 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 118 Bid: &seatBid.Bid[i], 119 BidType: bidType, 120 }) 121 } 122 } 123 124 return bidResponse, errors 125 } 126 127 func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpAso) (string, error) { 128 endpointParams := macros.EndpointTemplateParams{ZoneID: strconv.Itoa(params.Zone)} 129 return macros.ResolveMacros(a.endpoint, endpointParams) 130 } 131 132 func getMediaType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { 133 if bid.Ext != nil { 134 var bidExt openrtb_ext.ExtBid 135 err := json.Unmarshal(bid.Ext, &bidExt) 136 if err == nil && bidExt.Prebid != nil { 137 return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) 138 } 139 } 140 141 return "", &errortypes.BadServerResponse{ 142 Message: fmt.Sprintf("Failed to get type of bid \"%s\"", bid.ImpID), 143 } 144 } 145 146 func resolveMacros(bid *openrtb2.Bid) { 147 if bid == nil { 148 return 149 } 150 price := strconv.FormatFloat(bid.Price, 'f', -1, 64) 151 bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1) 152 bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) 153 }