github.com/prebid/prebid-server/v2@v2.18.0/adapters/smarthub/smarthub.go (about) 1 package smarthub 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 const ( 18 ADAPTER_VER = "1.0.0" 19 ) 20 21 type adapter struct { 22 endpoint *template.Template 23 } 24 25 type bidExt struct { 26 MediaType string `json:"mediaType"` 27 } 28 29 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 30 template, 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: template, 37 } 38 39 return bidder, nil 40 } 41 42 func (a *adapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtSmartHub, error) { 43 var bidderExt adapters.ExtImpBidder 44 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 45 return nil, &errortypes.BadInput{ 46 Message: "Bidder extension not provided or can't be unmarshalled", 47 } 48 } 49 50 var smarthubExt openrtb_ext.ExtSmartHub 51 if err := json.Unmarshal(bidderExt.Bidder, &smarthubExt); err != nil { 52 return nil, &errortypes.BadInput{ 53 Message: "Error while unmarshaling bidder extension", 54 } 55 } 56 57 return &smarthubExt, nil 58 } 59 60 func (a *adapter) buildEndpointURL(params *openrtb_ext.ExtSmartHub) (string, error) { 61 endpointParams := macros.EndpointTemplateParams{ 62 Host: params.PartnerName, 63 AccountID: params.Seat, 64 SourceId: params.Token, 65 } 66 return macros.ResolveMacros(a.endpoint, endpointParams) 67 } 68 69 func (a *adapter) MakeRequests( 70 openRTBRequest *openrtb2.BidRequest, 71 reqInfo *adapters.ExtraRequestInfo, 72 ) ( 73 []*adapters.RequestData, 74 []error, 75 ) { 76 var smarthubExt *openrtb_ext.ExtSmartHub 77 smarthubExt, err := a.getImpressionExt(&(openRTBRequest.Imp[0])) 78 if err != nil { 79 return nil, []error{err} 80 } 81 82 url, err := a.buildEndpointURL(smarthubExt) 83 if err != nil { 84 return nil, []error{err} 85 } 86 87 reqJSON, err := json.Marshal(openRTBRequest) 88 if err != nil { 89 return nil, []error{err} 90 } 91 92 headers := http.Header{} 93 headers.Add("Content-Type", "application/json;charset=utf-8") 94 headers.Add("Accept", "application/json") 95 headers.Add("Prebid-Adapter-Ver", ADAPTER_VER) 96 97 return []*adapters.RequestData{{ 98 Method: http.MethodPost, 99 Body: reqJSON, 100 Uri: url, 101 Headers: headers, 102 ImpIDs: openrtb_ext.GetImpIDs(openRTBRequest.Imp), 103 }}, nil 104 } 105 106 func (a *adapter) MakeBids( 107 openRTBRequest *openrtb2.BidRequest, 108 requestToBidder *adapters.RequestData, 109 bidderRawResponse *adapters.ResponseData, 110 ) ( 111 *adapters.BidderResponse, 112 []error, 113 ) { 114 if bidderRawResponse.StatusCode == http.StatusNoContent { 115 return nil, nil 116 } 117 118 if bidderRawResponse.StatusCode == http.StatusBadRequest { 119 return nil, []error{&errortypes.BadInput{ 120 Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)), 121 }} 122 } 123 124 if bidderRawResponse.StatusCode == http.StatusServiceUnavailable { 125 return nil, []error{&errortypes.BadInput{ 126 Message: "Bidder unavailable. Please contact the bidder support.", 127 }} 128 } 129 130 if bidderRawResponse.StatusCode != http.StatusOK { 131 return nil, []error{&errortypes.BadServerResponse{ 132 Message: fmt.Sprintf("Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)), 133 }} 134 } 135 136 responseBody := bidderRawResponse.Body 137 var bidResp openrtb2.BidResponse 138 if err := json.Unmarshal(responseBody, &bidResp); err != nil { 139 return nil, []error{err} 140 } 141 142 if len(bidResp.SeatBid) == 0 { 143 return nil, []error{&errortypes.BadServerResponse{ 144 Message: "Array SeatBid cannot be empty", 145 }} 146 } 147 148 bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) 149 150 bids := bidResp.SeatBid[0].Bid 151 152 if len(bids) == 0 { 153 return nil, []error{&errortypes.BadServerResponse{ 154 Message: "Array SeatBid[0].Bid cannot be empty", 155 }} 156 } 157 158 bid := bids[0] 159 160 var bidExt bidExt 161 var bidType openrtb_ext.BidType 162 163 if err := json.Unmarshal(bid.Ext, &bidExt); err != nil { 164 return nil, []error{&errortypes.BadServerResponse{ 165 Message: "Field BidExt is required", 166 }} 167 } 168 169 bidType, err := getBidType(bidExt) 170 171 if err != nil { 172 return nil, []error{err} 173 } 174 175 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 176 Bid: &bid, 177 BidType: bidType, 178 }) 179 return bidResponse, nil 180 } 181 182 func getBidType(ext bidExt) (openrtb_ext.BidType, error) { 183 return openrtb_ext.ParseBidType(ext.MediaType) 184 }