github.com/prebid/prebid-server/v2@v2.18.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/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 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 ImpIDs: openrtb_ext.GetImpIDs(reqCopy.Imp), 81 }) 82 } 83 84 return reqs, errors 85 86 } 87 88 func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { 89 90 if httpRes.StatusCode == http.StatusNoContent { 91 return nil, nil 92 } 93 94 if httpRes.StatusCode != http.StatusOK { 95 return nil, []error{&errortypes.BadServerResponse{ 96 Message: fmt.Sprintf("Remote server error: %s", httpRes.Body), 97 }} 98 } 99 var bidResp openrtb2.BidResponse 100 if err := json.Unmarshal(httpRes.Body, &bidResp); err != nil { 101 return nil, []error{&errortypes.BadServerResponse{ 102 Message: fmt.Sprintf("error while decoding response, err: %s", err), 103 }} 104 } 105 106 bidResponse := adapters.NewBidderResponse() 107 var errors []error 108 109 for _, sb := range bidResp.SeatBid { 110 for i := 0; i < len(sb.Bid); i++ { 111 112 bid := sb.Bid[i] 113 114 mediaType, impOK := getBidType(bidReq.Imp, bid.ImpID) 115 if !impOK { 116 errors = append(errors, &errortypes.BadServerResponse{ 117 Message: fmt.Sprintf("ignoring bid id=%s, request doesn't contain any impression with id=%s", bid.ID, bid.ImpID), 118 }) 119 continue 120 } 121 122 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 123 Bid: &bid, 124 BidType: mediaType, 125 }) 126 } 127 } 128 129 return bidResponse, errors 130 } 131 132 func getBidType(imps []openrtb2.Imp, impId string) (mediaType openrtb_ext.BidType, ok bool) { 133 mediaType = openrtb_ext.BidTypeBanner 134 for _, imp := range imps { 135 if imp.ID == impId { 136 ok = true 137 138 if imp.Video != nil { 139 mediaType = openrtb_ext.BidTypeVideo 140 } 141 142 break 143 } 144 } 145 146 return 147 } 148 149 func validateImpression(imp *openrtb2.Imp) (int, error) { 150 var bidderExt adapters.ExtImpBidder 151 152 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 153 return 0, &errortypes.BadInput{ 154 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err), 155 } 156 } 157 158 impExt := openrtb_ext.ExtImpOpenWeb{} 159 err := json.Unmarshal(bidderExt.Bidder, &impExt) 160 if err != nil { 161 return 0, &errortypes.BadInput{ 162 Message: fmt.Sprintf("ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err), 163 } 164 } 165 166 var impExtBuffer []byte 167 168 impExtBuffer, err = json.Marshal(&openwebImpExt{ 169 OpenWeb: impExt, 170 }) 171 if err != nil { 172 return 0, &errortypes.BadInput{ 173 Message: fmt.Sprintf("ignoring imp id=%s, error while encoding impExt, err: %s", imp.ID, err), 174 } 175 } 176 177 if impExt.BidFloor > 0 { 178 imp.BidFloor = impExt.BidFloor 179 } 180 181 imp.Ext = impExtBuffer 182 183 return impExt.SourceID, nil 184 } 185 186 // Builder builds a new instance of the OpenWeb adapter for the given bidder with the given config. 187 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 188 bidder := &adapter{ 189 endpoint: config.Endpoint, 190 } 191 return bidder, nil 192 }