github.com/prebid/prebid-server@v0.275.0/adapters/openweb/openweb.go (about) 1 package openweb 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 adapter struct { 16 endpoint string 17 } 18 19 type openwebImpExt struct { 20 OpenWeb openrtb_ext.ExtImpOpenWeb `json:"openweb"` 21 } 22 23 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 24 totalImps := len(request.Imp) 25 errors := make([]error, 0, totalImps) 26 sourceIdToImpIds := make(map[int][]int) 27 var sourceIds []int 28 29 for i := 0; i < totalImps; i++ { 30 31 sourceId, err := validateImpression(&request.Imp[i]) 32 33 if err != nil { 34 errors = append(errors, err) 35 continue 36 } 37 38 if _, ok := sourceIdToImpIds[sourceId]; !ok { 39 sourceIdToImpIds[sourceId] = make([]int, 0, totalImps-i) 40 sourceIds = append(sourceIds, sourceId) 41 } 42 43 sourceIdToImpIds[sourceId] = append(sourceIdToImpIds[sourceId], i) 44 45 } 46 47 totalReqs := len(sourceIdToImpIds) 48 if totalReqs == 0 { 49 return nil, errors 50 } 51 52 headers := http.Header{} 53 headers.Add("Content-Type", "application/json;charset=utf-8") 54 headers.Add("Accept", "application/json") 55 56 reqs := make([]*adapters.RequestData, 0, totalReqs) 57 58 imps := request.Imp 59 reqCopy := *request 60 reqCopy.Imp = make([]openrtb2.Imp, totalImps) 61 for _, sourceId := range sourceIds { 62 impIds := sourceIdToImpIds[sourceId] 63 reqCopy.Imp = reqCopy.Imp[:0] 64 65 for i := 0; i < len(impIds); i++ { 66 reqCopy.Imp = append(reqCopy.Imp, imps[impIds[i]]) 67 } 68 69 body, err := json.Marshal(reqCopy) 70 if err != nil { 71 errors = append(errors, fmt.Errorf("error while encoding bidRequest, err: %s", err)) 72 return nil, errors 73 } 74 75 reqs = append(reqs, &adapters.RequestData{ 76 Method: "POST", 77 Uri: a.endpoint + fmt.Sprintf("?aid=%d", sourceId), 78 Body: body, 79 Headers: headers, 80 }) 81 } 82 83 return reqs, errors 84 85 } 86 87 func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { 88 89 if httpRes.StatusCode == http.StatusNoContent { 90 return nil, nil 91 } 92 93 if httpRes.StatusCode != http.StatusOK { 94 return nil, []error{&errortypes.BadServerResponse{ 95 Message: fmt.Sprintf("Remote server error: %s", httpRes.Body), 96 }} 97 } 98 var bidResp openrtb2.BidResponse 99 if err := json.Unmarshal(httpRes.Body, &bidResp); err != nil { 100 return nil, []error{&errortypes.BadServerResponse{ 101 Message: fmt.Sprintf("error while decoding response, err: %s", err), 102 }} 103 } 104 105 bidResponse := adapters.NewBidderResponse() 106 var errors []error 107 108 for _, sb := range bidResp.SeatBid { 109 for i := 0; i < len(sb.Bid); i++ { 110 111 bid := sb.Bid[i] 112 113 mediaType, impOK := getBidType(bidReq.Imp, bid.ImpID) 114 if !impOK { 115 errors = append(errors, &errortypes.BadServerResponse{ 116 Message: fmt.Sprintf("ignoring bid id=%s, request doesn't contain any impression with id=%s", bid.ID, bid.ImpID), 117 }) 118 continue 119 } 120 121 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 122 Bid: &bid, 123 BidType: mediaType, 124 }) 125 } 126 } 127 128 return bidResponse, errors 129 } 130 131 func getBidType(imps []openrtb2.Imp, impId string) (mediaType openrtb_ext.BidType, ok bool) { 132 mediaType = openrtb_ext.BidTypeBanner 133 for _, imp := range imps { 134 if imp.ID == impId { 135 ok = true 136 137 if imp.Video != nil { 138 mediaType = openrtb_ext.BidTypeVideo 139 } 140 141 break 142 } 143 } 144 145 return 146 } 147 148 func validateImpression(imp *openrtb2.Imp) (int, error) { 149 var bidderExt adapters.ExtImpBidder 150 151 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 152 return 0, &errortypes.BadInput{ 153 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err), 154 } 155 } 156 157 impExt := openrtb_ext.ExtImpOpenWeb{} 158 err := json.Unmarshal(bidderExt.Bidder, &impExt) 159 if err != nil { 160 return 0, &errortypes.BadInput{ 161 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err), 162 } 163 } 164 165 var impExtBuffer []byte 166 167 impExtBuffer, err = json.Marshal(&openwebImpExt{ 168 OpenWeb: impExt, 169 }) 170 if err != nil { 171 return 0, &errortypes.BadInput{ 172 Message: fmt.Sprintf("ignoring imp id=%s, error while encoding impExt, err: %s", imp.ID, err), 173 } 174 } 175 176 if impExt.BidFloor > 0 { 177 imp.BidFloor = impExt.BidFloor 178 } 179 180 imp.Ext = impExtBuffer 181 182 return impExt.SourceID, nil 183 } 184 185 // Builder builds a new instance of the OpenWeb adapter for the given bidder with the given config. 186 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 187 bidder := &adapter{ 188 endpoint: config.Endpoint, 189 } 190 return bidder, nil 191 }