github.com/prebid/prebid-server@v0.275.0/adapters/undertone/undertone.go (about) 1 package undertone 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 9 "github.com/prebid/openrtb/v19/openrtb2" 10 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/openrtb_ext" 15 ) 16 17 const adapterId = 4 18 const adapterVersion = "1.0.0" 19 20 type adapter struct { 21 endpoint string 22 } 23 24 type undertoneParams struct { 25 Id int `json:"id"` 26 Version string `json:"version"` 27 } 28 29 type impExt struct { 30 Bidder *openrtb_ext.ExtImpUndertone `json:"bidder,omitempty"` 31 Gpid string `json:"gpid,omitempty"` 32 } 33 34 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 35 bidder := &adapter{ 36 endpoint: config.Endpoint, 37 } 38 return bidder, nil 39 } 40 41 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 42 imps, publisherId, errs := getImpsAndPublisherId(request) 43 if len(imps) == 0 { 44 return nil, errs 45 } 46 47 reqCopy := *request 48 reqCopy.Imp = imps 49 50 populateSiteApp(&reqCopy, publisherId, request.Site, request.App) 51 e := populateBidReqExt(&reqCopy) 52 if e != nil { 53 errs = append(errs, e) 54 } 55 56 requestJSON, err := json.Marshal(reqCopy) 57 if err != nil { 58 return nil, append(errs, err) 59 } 60 61 requestData := &adapters.RequestData{ 62 Method: "POST", 63 Uri: a.endpoint, 64 Body: requestJSON, 65 } 66 67 return []*adapters.RequestData{requestData}, errs 68 } 69 70 func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 71 if responseData.StatusCode == http.StatusNoContent { 72 return nil, nil 73 } 74 75 if responseData.StatusCode == http.StatusBadRequest { 76 err := &errortypes.BadInput{ 77 Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", 78 } 79 return nil, []error{err} 80 } 81 82 if responseData.StatusCode != http.StatusOK { 83 err := &errortypes.BadServerResponse{ 84 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), 85 } 86 return nil, []error{err} 87 } 88 89 var response openrtb2.BidResponse 90 if err := json.Unmarshal(responseData.Body, &response); err != nil { 91 return nil, []error{err} 92 } 93 94 impIdBidTypeMap := map[string]openrtb_ext.BidType{} 95 for _, imp := range request.Imp { 96 if imp.Banner != nil { 97 impIdBidTypeMap[imp.ID] = openrtb_ext.BidTypeBanner 98 } else if imp.Video != nil { 99 impIdBidTypeMap[imp.ID] = openrtb_ext.BidTypeVideo 100 } 101 } 102 103 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 104 bidResponse.Currency = response.Cur 105 for _, seatBid := range response.SeatBid { 106 for i, bid := range seatBid.Bid { 107 bidType, ok := impIdBidTypeMap[bid.ImpID] 108 if !ok { 109 continue 110 } 111 112 b := &adapters.TypedBid{ 113 Bid: &seatBid.Bid[i], 114 BidType: bidType, 115 } 116 bidResponse.Bids = append(bidResponse.Bids, b) 117 } 118 } 119 return bidResponse, nil 120 } 121 122 func populateBidReqExt(bidRequest *openrtb2.BidRequest) error { 123 undertoneParams := &undertoneParams{ 124 Id: adapterId, 125 Version: adapterVersion, 126 } 127 128 undertoneParamsJSON, err := json.Marshal(undertoneParams) 129 if err != nil { 130 return err 131 } 132 133 bidRequest.Ext = undertoneParamsJSON 134 return nil 135 } 136 137 func populateSiteApp(bidRequest *openrtb2.BidRequest, publisherId int, site *openrtb2.Site, app *openrtb2.App) { 138 pubId := strconv.Itoa(publisherId) 139 if site != nil { 140 siteCopy := *site 141 var publisher openrtb2.Publisher 142 if siteCopy.Publisher != nil { 143 publisher = *siteCopy.Publisher 144 } 145 publisher.ID = pubId 146 bidRequest.Site = &siteCopy 147 bidRequest.Site.Publisher = &publisher 148 } else if app != nil { 149 appCopy := *app 150 var publisher openrtb2.Publisher 151 if appCopy.Publisher != nil { 152 publisher = *appCopy.Publisher 153 } 154 publisher.ID = pubId 155 bidRequest.App = &appCopy 156 bidRequest.App.Publisher = &publisher 157 } 158 } 159 160 func getImpsAndPublisherId(bidRequest *openrtb2.BidRequest) ([]openrtb2.Imp, int, []error) { 161 var errs []error 162 var publisherId int 163 var validImps []openrtb2.Imp 164 165 for _, imp := range bidRequest.Imp { 166 var ext impExt 167 if err := json.Unmarshal(imp.Ext, &ext); err != nil { 168 errs = append(errs, getInvalidImpErr(imp.ID, err)) 169 continue 170 } 171 172 if publisherId == 0 { 173 publisherId = ext.Bidder.PublisherID 174 } 175 176 imp.TagID = strconv.Itoa(ext.Bidder.PlacementID) 177 imp.Ext = nil 178 179 if ext.Gpid != "" { 180 ext.Bidder = nil 181 impExtJson, err := json.Marshal(&ext) 182 if err != nil { 183 errs = append(errs, getInvalidImpErr(imp.ID, err)) 184 continue 185 } 186 imp.Ext = impExtJson 187 } 188 189 validImps = append(validImps, imp) 190 } 191 192 return validImps, publisherId, errs 193 } 194 195 func getInvalidImpErr(impId string, err error) *errortypes.BadInput { 196 return &errortypes.BadInput{ 197 Message: "Invalid impid=" + impId + ": " + err.Error(), 198 } 199 }