github.com/prebid/prebid-server@v0.275.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/v19/openrtb2" 9 "github.com/prebid/prebid-server/adapters" 10 "github.com/prebid/prebid-server/config" 11 "github.com/prebid/prebid-server/errortypes" 12 "github.com/prebid/prebid-server/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 return reqs, errs 95 } 96 97 func getBidCount(bidResponse openrtb2.BidResponse) int { 98 c := 0 99 for _, sb := range bidResponse.SeatBid { 100 c = c + len(sb.Bid) 101 } 102 return c 103 } 104 105 func (a *TripleliftAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 106 if response.StatusCode == http.StatusNoContent { 107 return nil, nil 108 } 109 110 if response.StatusCode == http.StatusBadRequest { 111 return nil, []error{&errortypes.BadInput{ 112 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 113 }} 114 } 115 116 if response.StatusCode != http.StatusOK { 117 return nil, []error{fmt.Errorf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)} 118 } 119 var bidResp openrtb2.BidResponse 120 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 121 return nil, []error{err} 122 } 123 var errs []error 124 count := getBidCount(bidResp) 125 bidResponse := adapters.NewBidderResponseWithBidsCapacity(count) 126 127 for _, sb := range bidResp.SeatBid { 128 for i := 0; i < len(sb.Bid); i++ { 129 bid := sb.Bid[i] 130 var bidExt TripleliftRespExt 131 if err := json.Unmarshal(bid.Ext, &bidExt); err != nil { 132 errs = append(errs, err) 133 } else { 134 bidType := getBidType(bidExt) 135 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 136 Bid: &bid, 137 BidType: bidType, 138 }) 139 } 140 } 141 } 142 return bidResponse, errs 143 } 144 145 // Builder builds a new instance of the Triplelift adapter for the given bidder with the given config. 146 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 147 bidder := &TripleliftAdapter{ 148 endpoint: config.Endpoint, 149 } 150 return bidder, nil 151 }