github.com/prebid/prebid-server/v2@v2.18.0/adapters/minutemedia/minutemedia.go (about) 1 package minutemedia 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strings" 10 11 "github.com/prebid/openrtb/v20/openrtb2" 12 13 "github.com/prebid/prebid-server/v2/adapters" 14 "github.com/prebid/prebid-server/v2/config" 15 "github.com/prebid/prebid-server/v2/errortypes" 16 "github.com/prebid/prebid-server/v2/openrtb_ext" 17 ) 18 19 // adapter is a MinuteMedia implementation of the adapters.Bidder interface. 20 type adapter struct { 21 endpointURL string 22 } 23 24 func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) { 25 return &adapter{ 26 endpointURL: config.Endpoint, 27 }, nil 28 } 29 30 // MakeRequests prepares the HTTP requests which should be made to fetch bids. 31 func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) { 32 org, err := extractOrg(openRTBRequest) 33 if err != nil { 34 return nil, append(errs, fmt.Errorf("failed to extract org: %w", err)) 35 } 36 37 openRTBRequestJSON, err := json.Marshal(openRTBRequest) 38 if err != nil { 39 return nil, append(errs, err) 40 } 41 42 headers := http.Header{} 43 headers.Add("Content-Type", "application/json;charset=utf-8") 44 45 return append(requestsToBidder, &adapters.RequestData{ 46 Method: http.MethodPost, 47 Uri: a.endpointURL + "?publisher_id=" + url.QueryEscape(org), 48 Body: openRTBRequestJSON, 49 Headers: headers, 50 ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), 51 }), nil 52 } 53 54 // MakeBids unpacks the server's response into Bids. 55 func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { 56 if adapters.IsResponseStatusCodeNoContent(responseData) { 57 return nil, nil 58 } 59 60 if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { 61 return nil, []error{err} 62 } 63 64 var response openrtb2.BidResponse 65 if err := json.Unmarshal(responseData.Body, &response); err != nil { 66 return nil, []error{err} 67 } 68 69 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) 70 bidResponse.Currency = response.Cur 71 72 var errs []error 73 74 for _, seatBid := range response.SeatBid { 75 for i, bid := range seatBid.Bid { 76 bidType, err := getMediaTypeForBid(bid) 77 if err != nil { 78 errs = append(errs, err) 79 continue 80 } 81 82 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 83 Bid: &seatBid.Bid[i], 84 BidType: bidType, 85 }) 86 } 87 } 88 89 return bidResponse, errs 90 } 91 92 func extractOrg(openRTBRequest *openrtb2.BidRequest) (string, error) { 93 var err error 94 if len(openRTBRequest.Imp) == 0 { 95 return "", errors.New("no imps in bid request") 96 } 97 98 var bidderExt adapters.ExtImpBidder 99 if err = json.Unmarshal(openRTBRequest.Imp[0].Ext, &bidderExt); err != nil { 100 return "", fmt.Errorf("failed to unmarshal bidderExt: %w", err) 101 } 102 103 var impExt openrtb_ext.ImpExtMinuteMedia 104 if err = json.Unmarshal(bidderExt.Bidder, &impExt); err != nil { 105 return "", fmt.Errorf("failed to unmarshal ImpExtMinuteMedia: %w", err) 106 } 107 108 return strings.TrimSpace(impExt.Org), nil 109 } 110 111 func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { 112 switch bid.MType { 113 case openrtb2.MarkupBanner: 114 return openrtb_ext.BidTypeBanner, nil 115 case openrtb2.MarkupVideo: 116 return openrtb_ext.BidTypeVideo, nil 117 default: 118 return "", &errortypes.BadServerResponse{ 119 Message: fmt.Sprintf("unsupported MType %d", bid.MType), 120 } 121 } 122 }