github.com/prebid/prebid-server/v2@v2.18.0/adapters/unruly/unruly.go (about) 1 package unruly 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 adapter struct { 16 endPoint string 17 } 18 19 // Builder builds a new instance of the Unruly adapter for the given bidder with the given config. 20 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 21 bidder := &adapter{ 22 endPoint: config.Endpoint, 23 } 24 return bidder, nil 25 } 26 27 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 28 errs := make([]error, 0, len(request.Imp)) 29 30 request, errs = a.preProcess(request, errs) 31 if request != nil { 32 reqJSON, err := json.Marshal(request) 33 if err != nil { 34 errs = append(errs, err) 35 return nil, errs 36 } 37 if a.endPoint != "" { 38 headers := http.Header{} 39 headers.Add("Content-Type", "application/json;charset=utf-8") 40 headers.Add("Accept", "application/json") 41 return []*adapters.RequestData{{ 42 Method: "POST", 43 Uri: a.endPoint, 44 Body: reqJSON, 45 Headers: headers, 46 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 47 }}, errs 48 } 49 } 50 return nil, errs 51 } 52 53 func (a *adapter) preProcess(req *openrtb2.BidRequest, errors []error) (*openrtb2.BidRequest, []error) { 54 numRequests := len(req.Imp) 55 for i := 0; i < numRequests; i++ { 56 imp := req.Imp[i] 57 var bidderExt adapters.ExtImpBidder 58 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 59 err = &errortypes.BadInput{ 60 Message: fmt.Sprintf("ext data not provided in imp id=%s. Abort all Request", imp.ID), 61 } 62 errors = append(errors, err) 63 return nil, errors 64 } 65 var unrulyExt openrtb_ext.ExtImpUnruly 66 if err := json.Unmarshal(bidderExt.Bidder, &unrulyExt); err != nil { 67 err = &errortypes.BadInput{ 68 Message: fmt.Sprintf("siteid not provided in imp id=%s. Abort all Request", imp.ID), 69 } 70 errors = append(errors, err) 71 return nil, errors 72 } 73 unrulyExtCopy, err := json.Marshal(&unrulyExt) 74 if err != nil { 75 errors = append(errors, err) 76 return nil, errors 77 } 78 bidderExtCopy := struct { 79 Bidder json.RawMessage `json:"bidder,omitempty"` 80 }{unrulyExtCopy} 81 impExtCopy, err := json.Marshal(&bidderExtCopy) 82 if err != nil { 83 errors = append(errors, err) 84 return nil, errors 85 } 86 imp.Ext = impExtCopy 87 req.Imp[i] = imp 88 } 89 90 return req, errors 91 } 92 93 func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 94 if response.StatusCode == http.StatusNoContent { 95 return nil, nil 96 } 97 98 if response.StatusCode == http.StatusBadRequest { 99 return nil, []error{&errortypes.BadInput{ 100 Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 101 }} 102 } 103 104 if response.StatusCode != http.StatusOK { 105 return nil, []error{&errortypes.BadServerResponse{ 106 Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 107 }} 108 } 109 var bidResp openrtb2.BidResponse 110 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 111 return nil, []error{&errortypes.BadServerResponse{ 112 Message: fmt.Sprintf("bad server response: %d. ", err), 113 }} 114 } 115 116 bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) 117 118 var errs []error 119 for _, sb := range bidResp.SeatBid { 120 for i := range sb.Bid { 121 var bidType, err = getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) 122 if err != nil { 123 errs = append(errs, err...) 124 } else { 125 bid := adapters.TypedBid{ 126 Bid: &sb.Bid[i], 127 BidType: bidType, 128 } 129 if bidType == openrtb_ext.BidTypeVideo && sb.Bid[i].Dur > 0 { 130 bid.BidVideo = &openrtb_ext.ExtBidPrebidVideo{ 131 Duration: int(sb.Bid[i].Dur), 132 } 133 } 134 bidResponse.Bids = append(bidResponse.Bids, &bid) 135 } 136 } 137 } 138 139 return bidResponse, errs 140 } 141 142 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, []error) { 143 var errs []error 144 var noMatchingImps []string 145 mediaType := openrtb_ext.BidTypeBanner 146 for _, imp := range imps { 147 if imp.ID == impId { 148 if imp.Banner != nil { 149 mediaType = openrtb_ext.BidTypeBanner 150 } else if imp.Video != nil { 151 mediaType = openrtb_ext.BidTypeVideo 152 } else { 153 errs = append(errs, fmt.Errorf("bid responses mediaType didn't match supported mediaTypes")) 154 } 155 return mediaType, errs 156 } else { 157 noMatchingImps = append(noMatchingImps, imp.ID) 158 } 159 } 160 161 errs = append(errs, fmt.Errorf("Bid response imp ID %s not found in bid request containing imps %v\n", impId, noMatchingImps)) 162 163 return mediaType, errs 164 }