github.com/prebid/prebid-server@v0.275.0/adapters/xeworks/xeworks.go (about) 1 package xeworks 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "text/template" 8 9 "github.com/prebid/openrtb/v19/openrtb2" 10 "github.com/prebid/prebid-server/adapters" 11 "github.com/prebid/prebid-server/config" 12 "github.com/prebid/prebid-server/errortypes" 13 "github.com/prebid/prebid-server/macros" 14 "github.com/prebid/prebid-server/openrtb_ext" 15 ) 16 17 type bidType struct { 18 Type string `json:"type"` 19 } 20 21 type bidExt struct { 22 Prebid bidType `json:"prebid"` 23 } 24 25 type adapter struct { 26 endpoint *template.Template 27 } 28 29 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 30 tmpl, err := template.New("endpointTemplate").Parse(config.Endpoint) 31 if err != nil { 32 return nil, fmt.Errorf("unable to parse endpoint URL template: %v", err) 33 } 34 35 bidder := &adapter{ 36 endpoint: tmpl, 37 } 38 39 return bidder, nil 40 } 41 42 func (a *adapter) buildEndpointFromRequest(imp *openrtb2.Imp) (string, error) { 43 var impExt adapters.ExtImpBidder 44 if err := json.Unmarshal(imp.Ext, &impExt); err != nil { 45 return "", &errortypes.BadInput{ 46 Message: fmt.Sprintf("Failed to deserialize bidder impression extension: %v", err), 47 } 48 } 49 50 var xeworksExt openrtb_ext.ExtXeworks 51 if err := json.Unmarshal(impExt.Bidder, &xeworksExt); err != nil { 52 return "", &errortypes.BadInput{ 53 Message: fmt.Sprintf("Failed to deserialize Xeworks extension: %v", err), 54 } 55 } 56 57 endpointParams := macros.EndpointTemplateParams{ 58 Host: xeworksExt.Env, 59 SourceId: xeworksExt.Pid, 60 } 61 62 return macros.ResolveMacros(a.endpoint, endpointParams) 63 } 64 65 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 66 var requests []*adapters.RequestData 67 var errs []error 68 69 headers := http.Header{} 70 headers.Add("Content-Type", "application/json;charset=utf-8") 71 headers.Add("Accept", "application/json") 72 73 requestCopy := *request 74 for _, imp := range request.Imp { 75 requestCopy.Imp = []openrtb2.Imp{imp} 76 77 endpoint, err := a.buildEndpointFromRequest(&imp) 78 if err != nil { 79 errs = append(errs, err) 80 continue 81 } 82 83 requestJSON, err := json.Marshal(requestCopy) 84 if err != nil { 85 errs = append(errs, err) 86 continue 87 } 88 89 request := &adapters.RequestData{ 90 Method: http.MethodPost, 91 Body: requestJSON, 92 Uri: endpoint, 93 Headers: headers, 94 } 95 96 requests = append(requests, request) 97 } 98 99 return requests, errs 100 } 101 102 func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (*adapters.BidderResponse, []error) { 103 if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) { 104 return nil, nil 105 } 106 107 if bidderRawResponse.StatusCode == http.StatusServiceUnavailable { 108 return nil, []error{&errortypes.BadInput{ 109 Message: "Bidder Xeworks is unavailable. Please contact the bidder support.", 110 }} 111 } 112 113 if err := adapters.CheckResponseStatusCodeForErrors(bidderRawResponse); err != nil { 114 return nil, []error{err} 115 } 116 117 var bidResp openrtb2.BidResponse 118 if err := json.Unmarshal(bidderRawResponse.Body, &bidResp); err != nil { 119 return nil, []error{err} 120 } 121 122 if len(bidResp.SeatBid) == 0 { 123 return nil, []error{&errortypes.BadServerResponse{ 124 Message: "Array SeatBid cannot be empty", 125 }} 126 } 127 128 return prepareBidResponse(bidResp.SeatBid) 129 } 130 131 func prepareBidResponse(seats []openrtb2.SeatBid) (*adapters.BidderResponse, []error) { 132 errs := []error{} 133 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seats)) 134 135 for _, seatBid := range seats { 136 for bidId, bid := range seatBid.Bid { 137 var bidExt bidExt 138 if err := json.Unmarshal(bid.Ext, &bidExt); err != nil { 139 errs = append(errs, &errortypes.BadServerResponse{ 140 Message: fmt.Sprintf("Failed to parse Bid[%d].Ext: %s", bidId, err.Error()), 141 }) 142 continue 143 } 144 145 bidType, err := openrtb_ext.ParseBidType(bidExt.Prebid.Type) 146 if err != nil { 147 errs = append(errs, &errortypes.BadServerResponse{ 148 Message: fmt.Sprintf("Bid[%d].Ext.Prebid.Type expects one of the following values: 'banner', 'native', 'video', 'audio', got '%s'", bidId, bidExt.Prebid.Type), 149 }) 150 continue 151 } 152 153 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 154 Bid: &seatBid.Bid[bidId], 155 BidType: bidType, 156 }) 157 } 158 } 159 160 return bidResponse, errs 161 }