github.com/prebid/prebid-server/v2@v2.18.0/adapters/triplelift/triplelift.go (about) 1 package triplelift 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/prebid/openrtb/v20/openrtb2" 9 "github.com/prebid/prebid-server/v2/adapters" 10 "github.com/prebid/prebid-server/v2/config" 11 "github.com/prebid/prebid-server/v2/errortypes" 12 "github.com/prebid/prebid-server/v2/openrtb_ext" 13 ) 14 15 type TripleliftAdapter struct { 16 endpoint string 17 } 18 19 type TripleliftInnerExt struct { 20 Format int `json:"format"` 21 } 22 23 type TripleliftRespExt struct { 24 Triplelift TripleliftInnerExt `json:"triplelift_pb"` 25 } 26 27 func getBidType(ext TripleliftRespExt) openrtb_ext.BidType { 28 t := ext.Triplelift.Format 29 if t == 11 || t == 12 || t == 17 { 30 return openrtb_ext.BidTypeVideo 31 } 32 return openrtb_ext.BidTypeBanner 33 } 34 35 func processImp(imp *openrtb2.Imp) error { 36 // get the triplelift extension 37 var ext adapters.ExtImpBidder 38 var tlext openrtb_ext.ExtImpTriplelift 39 if err := json.Unmarshal(imp.Ext, &ext); err != nil { 40 return err 41 } 42 if err := json.Unmarshal(ext.Bidder, &tlext); err != nil { 43 return err 44 } 45 if imp.Banner == nil && imp.Video == nil { 46 return fmt.Errorf("neither Banner nor Video object specified") 47 } 48 imp.TagID = tlext.InvCode 49 // floor is optional 50 if tlext.Floor == nil { 51 return nil 52 } else { 53 imp.BidFloor = *tlext.Floor 54 } 55 // no error 56 return nil 57 } 58 59 func (a *TripleliftAdapter) MakeRequests(request *openrtb2.BidRequest, extra *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 60 errs := make([]error, 0, len(request.Imp)+1) 61 reqs := make([]*adapters.RequestData, 0, 1) 62 // copy the request, because we are going to mutate it 63 tlRequest := *request 64 // this will contain all the valid impressions 65 var validImps []openrtb2.Imp 66 // pre-process the imps 67 for _, imp := range tlRequest.Imp { 68 if err := processImp(&imp); err == nil { 69 validImps = append(validImps, imp) 70 } else { 71 errs = append(errs, err) 72 } 73 } 74 if len(validImps) == 0 { 75 err := fmt.Errorf("No valid impressions for triplelift") 76 errs = append(errs, err) 77 return nil, errs 78 } 79 tlRequest.Imp = validImps 80 reqJSON, err := json.Marshal(tlRequest) 81 if err != nil { 82 errs = append(errs, err) 83 return nil, errs 84 } 85 headers := http.Header{} 86 headers.Add("Content-Type", "application/json;charset=utf-8") 87 headers.Add("Accept", "application/json") 88 ad := a.endpoint 89 reqs = append(reqs, &adapters.RequestData{ 90 Method: "POST", 91 Uri: ad, 92 Body: reqJSON, 93 Headers: headers, 94 ImpIDs: openrtb_ext.GetImpIDs(tlRequest.Imp)}) 95 return reqs, errs 96 } 97 98 func getBidCount(bidResponse openrtb2.BidResponse) int { 99 c := 0 100 for _, sb := range bidResponse.SeatBid { 101 c = c + len(sb.Bid) 102 } 103 return c 104 } 105 106 func (a *TripleliftAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 107 if response.StatusCode == http.StatusNoContent { 108 return nil, nil 109 } 110 111 if response.StatusCode == http.StatusBadRequest { 112 return nil, []error{&errortypes.BadInput{ 113 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 114 }} 115 } 116 117 if response.StatusCode != http.StatusOK { 118 return nil, []error{fmt.Errorf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)} 119 } 120 var bidResp openrtb2.BidResponse 121 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 122 return nil, []error{err} 123 } 124 var errs []error 125 count := getBidCount(bidResp) 126 bidResponse := adapters.NewBidderResponseWithBidsCapacity(count) 127 128 for _, sb := range bidResp.SeatBid { 129 for i := 0; i < len(sb.Bid); i++ { 130 bid := sb.Bid[i] 131 var bidExt TripleliftRespExt 132 if err := json.Unmarshal(bid.Ext, &bidExt); err != nil { 133 errs = append(errs, err) 134 } else { 135 bidType := getBidType(bidExt) 136 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 137 Bid: &bid, 138 BidType: bidType, 139 }) 140 } 141 } 142 } 143 return bidResponse, errs 144 } 145 146 // Builder builds a new instance of the Triplelift adapter for the given bidder with the given config. 147 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 148 bidder := &TripleliftAdapter{ 149 endpoint: config.Endpoint, 150 } 151 return bidder, nil 152 }