github.com/prebid/prebid-server@v0.275.0/adapters/adview/adview.go (about) 1 package adview 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 "text/template" 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/macros" 15 "github.com/prebid/prebid-server/openrtb_ext" 16 ) 17 18 type adapter struct { 19 endpoint *template.Template 20 } 21 22 // Builder builds a new instance of the adview adapter for the given bidder with the given config. 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 url 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 var bidderExt adapters.ExtImpBidder 37 imp := &request.Imp[0] 38 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 39 return nil, []error{&errortypes.BadInput{ 40 Message: fmt.Sprintf("invalid imp.ext, %s", err.Error()), 41 }} 42 } 43 //use adview 44 var advImpExt openrtb_ext.ExtImpAdView 45 if err := json.Unmarshal(bidderExt.Bidder, &advImpExt); err != nil { 46 return nil, []error{&errortypes.BadInput{ 47 Message: fmt.Sprintf("invalid bidderExt.Bidder, %s", err.Error()), 48 }} 49 } 50 51 imp.TagID = advImpExt.MasterTagID //tagid means posid 52 //for adview bid request 53 if imp.Banner != nil { 54 if len(imp.Banner.Format) != 0 { 55 bannerCopy := *imp.Banner 56 bannerCopy.H = &imp.Banner.Format[0].H 57 bannerCopy.W = &imp.Banner.Format[0].W 58 imp.Banner = &bannerCopy 59 } 60 } 61 62 // Check if imp comes with bid floor amount defined in a foreign currency 63 if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" { 64 // Convert to US dollars 65 convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") 66 if err != nil { 67 return nil, []error{err} 68 } 69 // Update after conversion. All imp elements inside request.Imp are shallow copies 70 // therefore, their non-pointer values are not shared memory and are safe to modify. 71 imp.BidFloorCur = "USD" 72 imp.BidFloor = convertedValue 73 } 74 75 // Set the CUR of bid to USD after converting all floors 76 request.Cur = []string{"USD"} 77 78 url, err := a.buildEndpointURL(&advImpExt) 79 if err != nil { 80 return nil, []error{err} 81 } 82 83 reqJSON, err := json.Marshal(request) 84 if err != nil { 85 return nil, []error{err} 86 } 87 88 return []*adapters.RequestData{{ 89 Method: http.MethodPost, 90 Body: reqJSON, 91 Uri: url, 92 }}, nil 93 } 94 95 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 96 if responseData.StatusCode == http.StatusNoContent { 97 return nil, nil 98 } 99 100 if responseData.StatusCode == http.StatusBadRequest { 101 err := &errortypes.BadInput{ 102 Message: "Unexpected status code: 400. Bad request from publisher.", 103 } 104 return nil, []error{err} 105 } 106 107 if responseData.StatusCode != http.StatusOK { 108 err := &errortypes.BadServerResponse{ 109 Message: fmt.Sprintf("Unexpected status code: %d.", responseData.StatusCode), 110 } 111 return nil, []error{err} 112 } 113 114 var response openrtb2.BidResponse 115 if err := json.Unmarshal(responseData.Body, &response); err != nil { 116 return nil, []error{err} 117 } 118 119 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 120 bidResponse.Currency = "USD" //we just support USD for resp 121 122 var errors []error 123 for _, seatBid := range response.SeatBid { 124 for i, bid := range seatBid.Bid { 125 bidType, err := getMediaTypeForImp(bid.ImpID, request.Imp) 126 if err != nil { 127 errors = append(errors, err) 128 continue 129 } 130 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 131 Bid: &seatBid.Bid[i], 132 BidType: bidType, 133 }) 134 } 135 } 136 137 return bidResponse, errors 138 } 139 140 // Builds endpoint url based on adapter-specific pub settings from imp.ext 141 func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtImpAdView) (string, error) { 142 endpointParams := macros.EndpointTemplateParams{AccountID: params.AccountID} 143 return macros.ResolveMacros(a.endpoint, endpointParams) 144 } 145 146 func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { 147 mediaType := openrtb_ext.BidTypeBanner 148 for _, imp := range imps { 149 if imp.ID == impID { 150 if imp.Video != nil { 151 mediaType = openrtb_ext.BidTypeVideo 152 } else if imp.Native != nil { 153 mediaType = openrtb_ext.BidTypeNative 154 } 155 return mediaType, nil 156 } 157 } 158 return mediaType, nil 159 }