github.com/prebid/prebid-server/v2@v2.18.0/adapters/deepintent/deepintent.go (about) 1 package deepintent 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 const displayManager string = "di_prebid" 16 const displayManagerVer string = "2.0.0" 17 18 // DeepintentAdapter struct 19 type DeepintentAdapter struct { 20 URI string 21 } 22 23 // Builder builds a new instance of the Deepintent adapter for the given bidder with the given config. 24 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 25 bidder := &DeepintentAdapter{ 26 URI: config.Endpoint, 27 } 28 return bidder, nil 29 } 30 31 // MakeRequests which creates request object for Deepintent DSP 32 func (d *DeepintentAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 33 var errs []error 34 var deepintentExt openrtb_ext.ExtImpDeepintent 35 var err error 36 37 var adapterRequests []*adapters.RequestData 38 39 reqCopy := *request 40 for _, imp := range request.Imp { 41 reqCopy.Imp = []openrtb2.Imp{imp} 42 43 var bidderExt adapters.ExtImpBidder 44 if err = json.Unmarshal(reqCopy.Imp[0].Ext, &bidderExt); err != nil { 45 errs = append(errs, &errortypes.BadInput{ 46 Message: fmt.Sprintf("Impression id=%s has an Error: %s", imp.ID, err.Error()), 47 }) 48 continue 49 } 50 51 if err = json.Unmarshal(bidderExt.Bidder, &deepintentExt); err != nil { 52 errs = append(errs, &errortypes.BadInput{ 53 Message: fmt.Sprintf("Impression id=%s, has invalid Ext", imp.ID), 54 }) 55 continue 56 } 57 58 reqCopy.Imp[0].TagID = deepintentExt.TagID 59 reqCopy.Imp[0].DisplayManager = displayManager 60 reqCopy.Imp[0].DisplayManagerVer = displayManagerVer 61 62 adapterReq, errors := d.preprocess(reqCopy) 63 if errors != nil { 64 errs = append(errs, errors...) 65 } 66 if adapterReq != nil { 67 adapterRequests = append(adapterRequests, adapterReq) 68 } 69 70 } 71 return adapterRequests, errs 72 } 73 74 // MakeBids makes the bids 75 func (d *DeepintentAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 76 var errs []error 77 78 if response.StatusCode == http.StatusNoContent { 79 return nil, nil 80 } 81 82 if response.StatusCode != http.StatusOK { 83 return nil, []error{&errortypes.BadServerResponse{ 84 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 85 }} 86 } 87 88 var bidResp openrtb2.BidResponse 89 90 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 91 return nil, []error{err} 92 } 93 94 bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) 95 96 for _, sb := range bidResp.SeatBid { 97 for i := range sb.Bid { 98 bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) 99 if err != nil { 100 errs = append(errs, err) 101 } else { 102 b := &adapters.TypedBid{ 103 Bid: &sb.Bid[i], 104 BidType: bidType, 105 } 106 bidResponse.Bids = append(bidResponse.Bids, b) 107 } 108 } 109 } 110 return bidResponse, errs 111 } 112 113 func (d *DeepintentAdapter) preprocess(request openrtb2.BidRequest) (*adapters.RequestData, []error) { 114 115 var errs []error 116 impsCount := len(request.Imp) 117 resImps := make([]openrtb2.Imp, 0, impsCount) 118 119 for _, imp := range request.Imp { 120 121 if err := buildImpBanner(&imp); err != nil { 122 errs = append(errs, err) 123 continue 124 } 125 resImps = append(resImps, imp) 126 } 127 request.Imp = resImps 128 if errs != nil { 129 return nil, errs 130 } 131 reqJSON, err := json.Marshal(request) 132 133 if err != nil { 134 errs = append(errs, err) 135 return nil, errs 136 } 137 138 headers := http.Header{} 139 headers.Add("Content-Type", "application/json;charset=utf-8") 140 headers.Add("Accept", "application/json") 141 return &adapters.RequestData{ 142 Method: "POST", 143 Uri: d.URI, 144 Body: reqJSON, 145 Headers: headers, 146 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 147 }, errs 148 } 149 150 func buildImpBanner(imp *openrtb2.Imp) error { 151 152 if imp.Banner == nil { 153 return &errortypes.BadInput{ 154 Message: fmt.Sprintf("We need a Banner Object in the request"), 155 } 156 } 157 158 if imp.Banner.W == nil && imp.Banner.H == nil { 159 bannerCopy := *imp.Banner 160 banner := &bannerCopy 161 162 if len(banner.Format) == 0 { 163 return &errortypes.BadInput{ 164 Message: fmt.Sprintf("At least one size is required"), 165 } 166 } 167 format := banner.Format[0] 168 banner.W = &format.W 169 banner.H = &format.H 170 imp.Banner = banner 171 } 172 173 return nil 174 } 175 176 func getMediaTypeForImp(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { 177 mediaType := openrtb_ext.BidTypeBanner 178 for _, imp := range imps { 179 if imp.ID == impID { 180 return mediaType, nil 181 } 182 } 183 184 // This shouldnt happen. Lets handle it just incase by returning an error. 185 return "", &errortypes.BadInput{ 186 Message: fmt.Sprintf("Failed to find impression %s ", impID), 187 } 188 }