github.com/prebid/prebid-server/v2@v2.18.0/adapters/ownadx/ownadx.go (about) 1 package ownadx 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "text/template" 8 9 "github.com/prebid/openrtb/v20/openrtb2" 10 "github.com/prebid/prebid-server/v2/adapters" 11 "github.com/prebid/prebid-server/v2/config" 12 "github.com/prebid/prebid-server/v2/errortypes" 13 "github.com/prebid/prebid-server/v2/macros" 14 "github.com/prebid/prebid-server/v2/openrtb_ext" 15 ) 16 17 type adapter struct { 18 endpoint *template.Template 19 } 20 type bidExt struct { 21 MediaType string `json:"mediaType"` 22 } 23 24 func (adapter *adapter) getRequestData(bidRequest *openrtb2.BidRequest, impExt *openrtb_ext.ExtImpOwnAdx, imps []openrtb2.Imp) (*adapters.RequestData, error) { 25 pbidRequest := createBidRequest(bidRequest, imps) 26 reqJSON, err := json.Marshal(pbidRequest) 27 if err != nil { 28 return nil, &errortypes.BadInput{ 29 Message: "Prebid bidder request not valid or can't be marshalled. Err: " + err.Error(), 30 } 31 } 32 url, err := adapter.buildEndpointURL(impExt) 33 if err != nil { 34 return nil, &errortypes.BadInput{ 35 Message: "Error while creating endpoint. Err: " + err.Error(), 36 } 37 } 38 39 headers := http.Header{} 40 headers.Add("Content-Type", "application/json;charset=utf-8") 41 headers.Add("Accept", "application/json") 42 headers.Add("x-openrtb-version", "2.5") 43 44 return &adapters.RequestData{ 45 Method: "POST", 46 Uri: url, 47 Body: reqJSON, 48 Headers: headers, 49 ImpIDs: openrtb_ext.GetImpIDs(pbidRequest.Imp)}, nil 50 51 } 52 func createBidRequest(rtbBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp) *openrtb2.BidRequest { 53 bidRequest := *rtbBidRequest 54 bidRequest.Imp = imps 55 return &bidRequest 56 } 57 func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ExtImpOwnAdx) (string, error) { 58 endpointParams := macros.EndpointTemplateParams{ 59 ZoneID: params.SspId, 60 AccountID: params.SeatId, 61 SourceId: params.TokenId, 62 } 63 return macros.ResolveMacros(adapter.endpoint, endpointParams) 64 } 65 66 func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpOwnAdx, error) { 67 var bidderExt adapters.ExtImpBidder 68 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 69 return nil, &errortypes.BadInput{ 70 Message: "Bidder extension not valid or can't be unmarshalled", 71 } 72 } 73 74 var ownAdxExt openrtb_ext.ExtImpOwnAdx 75 if err := json.Unmarshal(bidderExt.Bidder, &ownAdxExt); err != nil { 76 return nil, &errortypes.BadInput{ 77 Message: "Error while unmarshaling bidder extension", 78 } 79 } 80 81 return &ownAdxExt, nil 82 } 83 84 func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 85 86 errs := make([]error, 0, len(request.Imp)) 87 if len(request.Imp) == 0 { 88 errs = append(errs, &errortypes.BadInput{ 89 Message: "No impression in the bid request"}, 90 ) 91 return nil, errs 92 } 93 extImps, errors := groupImpsByExt(request.Imp) 94 if len(errors) != 0 { 95 errs = append(errs, errors...) 96 } 97 if len(extImps) == 0 { 98 return nil, errs 99 } 100 reqDetail := make([]*adapters.RequestData, 0, len(extImps)) 101 for k, imps := range extImps { 102 bidRequest, err := adapter.getRequestData(request, &k, imps) 103 if err != nil { 104 errs = append(errs, err) 105 } else { 106 reqDetail = append(reqDetail, bidRequest) 107 } 108 } 109 return reqDetail, errs 110 } 111 func groupImpsByExt(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp, []error) { 112 respExt := make(map[openrtb_ext.ExtImpOwnAdx][]openrtb2.Imp) 113 errors := make([]error, 0, len(imps)) 114 for _, imp := range imps { 115 ownAdxExt, err := getImpressionExt(&(imp)) 116 if err != nil { 117 errors = append(errors, err) 118 continue 119 } 120 121 respExt[*ownAdxExt] = append(respExt[*ownAdxExt], imp) 122 } 123 return respExt, errors 124 } 125 126 func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 127 if response.StatusCode == http.StatusNoContent { 128 return nil, nil 129 } 130 if response.StatusCode == http.StatusBadRequest { 131 return nil, []error{ 132 &errortypes.BadServerResponse{ 133 Message: fmt.Sprintf("Bad request: %d", response.StatusCode), 134 }, 135 } 136 } 137 if response.StatusCode != http.StatusOK { 138 return nil, []error{ 139 &errortypes.BadServerResponse{ 140 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.test = 1 for more info.", response.StatusCode), 141 }, 142 } 143 } 144 var bidResp openrtb2.BidResponse 145 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 146 return nil, []error{ 147 &errortypes.BadServerResponse{ 148 Message: fmt.Sprintf("Bad server response "), 149 }, 150 } 151 } 152 if len(bidResp.SeatBid) == 0 { 153 return nil, []error{ 154 &errortypes.BadServerResponse{ 155 Message: fmt.Sprintf("Array SeatBid cannot be empty "), 156 }, 157 } 158 } 159 160 seatBid := bidResp.SeatBid[0] 161 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) 162 if len(seatBid.Bid) == 0 { 163 return nil, []error{ 164 &errortypes.BadServerResponse{ 165 Message: fmt.Sprintf("Bid cannot be empty "), 166 }, 167 } 168 } 169 for i := 0; i < len(seatBid.Bid); i++ { 170 var bidType openrtb_ext.BidType 171 bid := seatBid.Bid[i] 172 173 bidType, err := getMediaType(bid) 174 if err != nil { 175 return nil, []error{&errortypes.BadServerResponse{ 176 Message: "Bid type is invalid", 177 }} 178 } 179 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 180 Bid: &bid, 181 BidType: bidType, 182 }) 183 } 184 185 return bidResponse, nil 186 } 187 188 // Builder builds a new instance of the OwnAdx adapter for the given bidder with the given config 189 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 190 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 191 if err != nil { 192 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 193 } 194 195 bidder := &adapter{ 196 endpoint: template, 197 } 198 199 return bidder, nil 200 } 201 202 func getMediaType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { 203 switch bid.MType { 204 case openrtb2.MarkupBanner: 205 return openrtb_ext.BidTypeBanner, nil 206 case openrtb2.MarkupVideo: 207 return openrtb_ext.BidTypeVideo, nil 208 case openrtb2.MarkupAudio: 209 return openrtb_ext.BidTypeAudio, nil 210 case openrtb2.MarkupNative: 211 return openrtb_ext.BidTypeNative, nil 212 default: 213 return "", fmt.Errorf("invalid BidType: %d", bid.MType) 214 } 215 }