github.com/prebid/prebid-server@v0.275.0/adapters/adot/adot.go (about) 1 package adot 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 "strings" 9 10 "github.com/prebid/openrtb/v19/openrtb2" 11 "github.com/prebid/prebid-server/adapters" 12 "github.com/prebid/prebid-server/config" 13 "github.com/prebid/prebid-server/errortypes" 14 "github.com/prebid/prebid-server/openrtb_ext" 15 ) 16 17 type adapter struct { 18 endpoint string 19 } 20 21 type adotBidExt struct { 22 Adot bidExt `json:"adot"` 23 } 24 25 type bidExt struct { 26 MediaType string `json:"media_type"` 27 } 28 29 // Builder builds a new instance of the Adot adapter for the given bidder with the given config. 30 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 31 bidder := &adapter{ 32 endpoint: config.Endpoint, 33 } 34 return bidder, nil 35 } 36 37 // MakeRequests makes the HTTP requests which should be made to fetch bids. 38 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 39 var reqJSON []byte 40 var publisherPath string 41 var err error 42 43 if reqJSON, err = json.Marshal(request); err != nil { 44 return nil, []error{fmt.Errorf("unable to marshal openrtb request (%v)", err)} 45 } 46 47 headers := http.Header{} 48 headers.Add("Content-Type", "application/json;charset=utf-8") 49 50 if adotExt := getImpAdotExt(&request.Imp[0]); adotExt != nil { 51 publisherPath = adotExt.PublisherPath 52 } else { 53 publisherPath = "" 54 } 55 56 endpoint := strings.Replace(a.endpoint, "{PUBLISHER_PATH}", publisherPath, -1) 57 58 return []*adapters.RequestData{{ 59 Method: "POST", 60 Uri: endpoint, 61 Body: reqJSON, 62 Headers: headers, 63 }}, nil 64 } 65 66 // MakeBids unpacks the server's response into Bids. 67 // The bidder return a status code 204 when it cannot delivery an ad. 68 func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 69 if response.StatusCode == http.StatusNoContent { 70 return nil, nil 71 } 72 73 if response.StatusCode == http.StatusBadRequest { 74 return nil, []error{&errortypes.BadInput{ 75 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 76 }} 77 } 78 79 if response.StatusCode != http.StatusOK { 80 return nil, []error{&errortypes.BadServerResponse{ 81 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 82 }} 83 } 84 85 var bidResp openrtb2.BidResponse 86 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 87 return nil, []error{err} 88 } 89 90 bidsCapacity := 1 91 if len(bidResp.SeatBid) > 0 { 92 bidsCapacity = len(bidResp.SeatBid[0].Bid) 93 } 94 bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidsCapacity) 95 96 for _, sb := range bidResp.SeatBid { 97 for i := range sb.Bid { 98 if bidType, err := getMediaTypeForBid(&sb.Bid[i]); err == nil { 99 resolveMacros(&sb.Bid[i]) 100 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 101 Bid: &sb.Bid[i], 102 BidType: bidType, 103 }) 104 } 105 } 106 } 107 108 return bidResponse, nil 109 } 110 111 // getMediaTypeForBid determines which type of bid. 112 func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { 113 if bid == nil { 114 return "", fmt.Errorf("the bid request object is nil") 115 } 116 117 var impExt adotBidExt 118 if err := json.Unmarshal(bid.Ext, &impExt); err == nil { 119 switch impExt.Adot.MediaType { 120 case string(openrtb_ext.BidTypeBanner): 121 return openrtb_ext.BidTypeBanner, nil 122 case string(openrtb_ext.BidTypeVideo): 123 return openrtb_ext.BidTypeVideo, nil 124 case string(openrtb_ext.BidTypeNative): 125 return openrtb_ext.BidTypeNative, nil 126 } 127 } 128 129 return "", fmt.Errorf("unrecognized bid type in response from adot") 130 } 131 132 // resolveMacros resolves OpenRTB macros in nurl and adm 133 func resolveMacros(bid *openrtb2.Bid) { 134 if bid == nil { 135 return 136 } 137 price := strconv.FormatFloat(bid.Price, 'f', -1, 64) 138 bid.NURL = strings.Replace(bid.NURL, "${AUCTION_PRICE}", price, -1) 139 bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) 140 } 141 142 // getImpAdotExt parses and return first imp ext or nil 143 func getImpAdotExt(imp *openrtb2.Imp) *openrtb_ext.ExtImpAdot { 144 var extImpAdot openrtb_ext.ExtImpAdot 145 var extBidder adapters.ExtImpBidder 146 err := json.Unmarshal(imp.Ext, &extBidder) 147 if err != nil { 148 return nil 149 } 150 err = json.Unmarshal(extBidder.Bidder, &extImpAdot) 151 if err != nil { 152 return nil 153 } 154 return &extImpAdot 155 }