github.com/prebid/prebid-server/v2@v2.18.0/adapters/silvermob/silvermob.go (about) 1 package silvermob 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 SilverMobAdapter struct { 18 endpoint *template.Template 19 } 20 21 func isValidHost(host string) bool { 22 return host == "eu" || host == "us" || host == "apac" 23 } 24 25 // Builder builds a new instance of the SilverMob adapter for the given bidder with the given config. 26 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 27 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 28 if err != nil { 29 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 30 } 31 32 bidder := &SilverMobAdapter{ 33 endpoint: template, 34 } 35 return bidder, nil 36 } 37 38 func GetHeaders(request *openrtb2.BidRequest) *http.Header { 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 if request.Device != nil { 45 if len(request.Device.UA) > 0 { 46 headers.Add("User-Agent", request.Device.UA) 47 } 48 49 if len(request.Device.IPv6) > 0 { 50 headers.Add("X-Forwarded-For", request.Device.IPv6) 51 } 52 53 if len(request.Device.IP) > 0 { 54 headers.Add("X-Forwarded-For", request.Device.IP) 55 } 56 } 57 58 return &headers 59 } 60 61 func (a *SilverMobAdapter) MakeRequests( 62 openRTBRequest *openrtb2.BidRequest, 63 reqInfo *adapters.ExtraRequestInfo, 64 ) ( 65 []*adapters.RequestData, 66 []error, 67 ) { 68 requestCopy := *openRTBRequest 69 impCount := len(openRTBRequest.Imp) 70 requestData := make([]*adapters.RequestData, 0, impCount) 71 errs := []error{} 72 73 var err error 74 75 for _, imp := range openRTBRequest.Imp { 76 var silvermobExt *openrtb_ext.ExtSilverMob 77 78 silvermobExt, err = a.getImpressionExt(&imp) 79 80 if err != nil { 81 errs = append(errs, err) 82 continue 83 } 84 85 url, err := a.buildEndpointURL(silvermobExt) 86 if err != nil { 87 errs = append(errs, err) 88 continue 89 } 90 91 requestCopy.Imp = []openrtb2.Imp{imp} 92 reqJSON, err := json.Marshal(requestCopy) 93 if err != nil { 94 errs = append(errs, err) 95 continue 96 } 97 98 reqData := &adapters.RequestData{ 99 Method: http.MethodPost, 100 Body: reqJSON, 101 Uri: url, 102 Headers: *GetHeaders(&requestCopy), 103 ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), 104 } 105 106 requestData = append(requestData, reqData) 107 } 108 109 return requestData, errs 110 } 111 112 func (a *SilverMobAdapter) getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtSilverMob, error) { 113 var bidderExt adapters.ExtImpBidder 114 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 115 return nil, &errortypes.BadInput{ 116 Message: fmt.Sprintf("error unmarshaling imp.ext: %s", err.Error()), 117 } 118 } 119 var silvermobExt openrtb_ext.ExtSilverMob 120 if err := json.Unmarshal(bidderExt.Bidder, &silvermobExt); err != nil { 121 return nil, &errortypes.BadInput{ 122 Message: fmt.Sprintf("error unmarshaling imp.ext.bidder: %s", err.Error()), 123 } 124 } 125 return &silvermobExt, nil 126 } 127 128 func (a *SilverMobAdapter) buildEndpointURL(params *openrtb_ext.ExtSilverMob) (string, error) { 129 if isValidHost(params.Host) { 130 endpointParams := macros.EndpointTemplateParams{ZoneID: params.ZoneID, Host: params.Host} 131 return macros.ResolveMacros(a.endpoint, endpointParams) 132 } else { 133 return "", &errortypes.BadInput{ 134 Message: fmt.Sprintf("invalid host %s", params.Host), 135 } 136 } 137 } 138 139 func (a *SilverMobAdapter) MakeBids( 140 openRTBRequest *openrtb2.BidRequest, 141 requestToBidder *adapters.RequestData, 142 bidderRawResponse *adapters.ResponseData, 143 ) ( 144 bidderResponse *adapters.BidderResponse, 145 errs []error, 146 ) { 147 148 if bidderRawResponse.StatusCode == http.StatusNoContent { 149 return nil, nil 150 } 151 152 if bidderRawResponse.StatusCode == http.StatusBadRequest { 153 return nil, []error{&errortypes.BadInput{ 154 Message: fmt.Sprintf("Bad Request status code: %d. Run with request.debug = 1 for more info", bidderRawResponse.StatusCode), 155 }} 156 } 157 158 if bidderRawResponse.StatusCode != http.StatusOK { 159 return nil, []error{fmt.Errorf("Unexpected status code: %d. Run with request.debug = 1 for more info", bidderRawResponse.StatusCode)} 160 } 161 162 responseBody := bidderRawResponse.Body 163 var bidResp openrtb2.BidResponse 164 if err := json.Unmarshal(responseBody, &bidResp); err != nil { 165 return nil, []error{&errortypes.BadServerResponse{ 166 Message: fmt.Sprintf("Error unmarshaling server Response: %s", err), 167 }} 168 } 169 170 if len(bidResp.SeatBid) == 0 { 171 return nil, []error{&errortypes.BadServerResponse{ 172 Message: "Empty SeatBid array", 173 }} 174 } 175 176 bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) 177 178 for _, sb := range bidResp.SeatBid { 179 for _, bid := range sb.Bid { 180 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 181 Bid: &bid, 182 BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp), 183 }) 184 } 185 } 186 187 return bidResponse, nil 188 } 189 190 func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType { 191 mediaType := openrtb_ext.BidTypeBanner 192 for _, imp := range imps { 193 if imp.ID == impId { 194 if imp.Video != nil { 195 mediaType = openrtb_ext.BidTypeVideo 196 } else if imp.Native != nil { 197 mediaType = openrtb_ext.BidTypeNative 198 } 199 return mediaType 200 } 201 } 202 return mediaType 203 }