github.com/prebid/prebid-server/v2@v2.18.0/adapters/marsmedia/marsmedia.go (about) 1 package marsmedia 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 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/openrtb_ext" 14 ) 15 16 type MarsmediaAdapter struct { 17 URI string 18 } 19 20 func (a *MarsmediaAdapter) MakeRequests(requestIn *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 21 22 request := *requestIn 23 24 if len(request.Imp) == 0 { 25 return nil, []error{&errortypes.BadInput{ 26 Message: "No impression in the bid request", 27 }} 28 } 29 30 var bidderExt adapters.ExtImpBidder 31 if err := json.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil { 32 return nil, []error{&errortypes.BadInput{ 33 Message: "ext.bidder not provided", 34 }} 35 } 36 37 var marsmediaExt openrtb_ext.ExtImpMarsmedia 38 if err := json.Unmarshal(bidderExt.Bidder, &marsmediaExt); err != nil { 39 return nil, []error{&errortypes.BadInput{ 40 Message: "ext.bidder.zoneId not provided", 41 }} 42 } 43 44 if marsmediaExt.ZoneID == "" { 45 return nil, []error{&errortypes.BadInput{ 46 Message: "zoneId is empty", 47 }} 48 } 49 50 validImpExists := false 51 for i := 0; i < len(request.Imp); i++ { 52 if request.Imp[i].Banner != nil { 53 bannerCopy := *requestIn.Imp[i].Banner 54 if len(bannerCopy.Format) > 0 { 55 firstFormat := bannerCopy.Format[0] 56 bannerCopy.W = &(firstFormat.W) 57 bannerCopy.H = &(firstFormat.H) 58 request.Imp[i].Banner = &bannerCopy 59 validImpExists = true 60 } else if bannerCopy.W != nil && bannerCopy.H != nil { 61 validImpExists = true 62 } else { 63 return nil, []error{&errortypes.BadInput{ 64 Message: "No valid banner format in the bid request", 65 }} 66 } 67 } else if request.Imp[i].Video != nil { 68 validImpExists = true 69 } 70 } 71 if !validImpExists { 72 return nil, []error{&errortypes.BadInput{ 73 Message: "No valid impression in the bid request", 74 }} 75 } 76 77 request.AT = 1 //Defaulting to first price auction for all prebid requests 78 79 reqJSON, err := json.Marshal(request) 80 if err != nil { 81 return nil, []error{&errortypes.BadInput{ 82 Message: fmt.Sprintf("Json not encoded. err: %s", err), 83 }} 84 } 85 86 uri := a.URI + "&zone=" + marsmediaExt.ZoneID.String() 87 headers := http.Header{} 88 headers.Add("Content-Type", "application/json;charset=utf-8") 89 headers.Add("Accept", "application/json") 90 headers.Add("x-openrtb-version", "2.5") 91 92 if request.Device != nil { 93 addHeaderIfNonEmpty(headers, "User-Agent", request.Device.UA) 94 addHeaderIfNonEmpty(headers, "X-Forwarded-For", request.Device.IP) 95 addHeaderIfNonEmpty(headers, "Accept-Language", request.Device.Language) 96 if request.Device.DNT != nil { 97 addHeaderIfNonEmpty(headers, "DNT", strconv.Itoa(int(*request.Device.DNT))) 98 } 99 } 100 101 return []*adapters.RequestData{{ 102 Method: "POST", 103 Uri: uri, 104 Body: reqJSON, 105 Headers: headers, 106 ImpIDs: openrtb_ext.GetImpIDs(request.Imp), 107 }}, []error{} 108 } 109 110 func (a *MarsmediaAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 111 112 if response.StatusCode == http.StatusNoContent { 113 return nil, nil 114 } 115 116 if response.StatusCode == http.StatusBadRequest { 117 return nil, []error{&errortypes.BadInput{ 118 Message: fmt.Sprintf("Unexpected status code: %d. ", response.StatusCode), 119 }} 120 } 121 122 if response.StatusCode != http.StatusOK { 123 return nil, []error{&errortypes.BadServerResponse{ 124 Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), 125 }} 126 } 127 128 var bidResp openrtb2.BidResponse 129 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 130 return nil, []error{&errortypes.BadServerResponse{ 131 Message: fmt.Sprintf("Bad server response: %d. ", err), 132 }} 133 } 134 135 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) 136 sb := bidResp.SeatBid[0] 137 for i := 0; i < len(sb.Bid); i++ { 138 bid := sb.Bid[i] 139 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 140 Bid: &bid, 141 BidType: getMediaTypeForImp(bid.ImpID, internalRequest.Imp), 142 }) 143 } 144 return bidResponse, nil 145 } 146 147 func addHeaderIfNonEmpty(headers http.Header, headerName string, headerValue string) { 148 if len(headerValue) > 0 { 149 headers.Add(headerName, headerValue) 150 } 151 } 152 153 // getMediaTypeForImp figures out which media type this bid is for. 154 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { 155 mediaType := openrtb_ext.BidTypeBanner //default type 156 for _, imp := range imps { 157 if imp.ID == impId { 158 if imp.Video != nil { 159 mediaType = openrtb_ext.BidTypeVideo 160 } 161 return mediaType 162 } 163 } 164 return mediaType 165 } 166 167 // Builder builds a new instance of the Marsmedia adapter for the given bidder with the given config. 168 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 169 bidder := &MarsmediaAdapter{ 170 URI: config.Endpoint, 171 } 172 return bidder, nil 173 }