github.com/prebid/prebid-server@v0.275.0/adapters/trafficgate/trafficgate.go (about) 1 package trafficgate 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 adapter struct { 18 EndpointTemplate *template.Template 19 } 20 21 type BidResponseExt struct { 22 Prebid struct { 23 Type string 24 } 25 } 26 27 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 28 29 headers := http.Header{ 30 "Content-Type": {"application/json"}, 31 "Accept": {"application/json"}, 32 } 33 34 // Pull the host and source ID info from the bidder params. 35 reqImps, err := splitImpressions(request.Imp) 36 if err != nil { 37 return nil, []error{err} 38 } 39 40 requests := []*adapters.RequestData{} 41 42 var errs []error 43 for reqExt, reqImp := range reqImps { 44 request.Imp = reqImp 45 reqJson, err := json.Marshal(request) 46 47 if err != nil { 48 errs = append(errs, err) 49 continue 50 } 51 52 urlParams := macros.EndpointTemplateParams{Host: reqExt.Host} 53 url, err := macros.ResolveMacros(a.EndpointTemplate, urlParams) 54 55 if err != nil { 56 errs = append(errs, err) 57 continue 58 } 59 60 request := adapters.RequestData{ 61 Method: "POST", 62 Uri: url, 63 Body: reqJson, 64 Headers: headers} 65 66 requests = append(requests, &request) 67 } 68 69 return requests, errs 70 } 71 72 /* 73 internal original request in OpenRTB, external = result of us having converted it (what comes out of MakeRequests) 74 */ 75 func (a *adapter) MakeBids( 76 internalRequest *openrtb2.BidRequest, 77 externalRequest *adapters.RequestData, 78 response *adapters.ResponseData, 79 ) (*adapters.BidderResponse, []error) { 80 81 if response.StatusCode == http.StatusNoContent { 82 return nil, nil 83 } 84 85 if response.StatusCode != http.StatusOK { 86 return nil, []error{&errortypes.BadServerResponse{ 87 Message: fmt.Sprintf("Error response with status %d", response.StatusCode), 88 }} 89 } 90 91 var bidResp openrtb2.BidResponse 92 93 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 94 return nil, []error{&errortypes.BadServerResponse{ 95 Message: err.Error(), 96 }} 97 } 98 99 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) 100 bidResponse.Currency = bidResp.Cur 101 102 for _, seatBid := range bidResp.SeatBid { 103 for i := range seatBid.Bid { 104 var bidExt BidResponseExt 105 if err := json.Unmarshal(seatBid.Bid[i].Ext, &bidExt); err != nil { 106 return nil, []error{&errortypes.BadServerResponse{ 107 Message: fmt.Sprintf("Missing response ext"), 108 }} 109 } 110 if len(bidExt.Prebid.Type) < 1 { 111 return nil, []error{&errortypes.BadServerResponse{ 112 Message: fmt.Sprintf("Unable to read bid.ext.prebid.type"), 113 }} 114 } 115 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 116 Bid: &seatBid.Bid[i], 117 BidType: getMediaTypeForImp(bidExt.Prebid.Type), 118 }) 119 } 120 } 121 122 return bidResponse, nil 123 } 124 125 func splitImpressions(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp, error) { 126 127 var multipleImps = make(map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp) 128 129 for _, imp := range imps { 130 bidderParams, err := getBidderParams(&imp) 131 if err != nil { 132 return nil, err 133 } 134 135 multipleImps[*bidderParams] = append(multipleImps[*bidderParams], imp) 136 } 137 138 return multipleImps, nil 139 } 140 141 func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTrafficGate, error) { 142 var bidderExt adapters.ExtImpBidder 143 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 144 return nil, &errortypes.BadInput{ 145 Message: fmt.Sprintf("Missing bidder ext"), 146 } 147 } 148 var TrafficGateExt openrtb_ext.ExtImpTrafficGate 149 if err := json.Unmarshal(bidderExt.Bidder, &TrafficGateExt); err != nil { 150 return nil, &errortypes.BadInput{ 151 Message: fmt.Sprintf("Bidder parameters required"), 152 } 153 } 154 155 return &TrafficGateExt, nil 156 } 157 158 func getMediaTypeForImp(bidType string) openrtb_ext.BidType { 159 switch bidType { 160 case "video": 161 return openrtb_ext.BidTypeVideo 162 case "native": 163 return openrtb_ext.BidTypeNative 164 case "audio": 165 return openrtb_ext.BidTypeAudio 166 } 167 return openrtb_ext.BidTypeBanner 168 } 169 170 // Builder builds a new instance of the TrafficGate adapter for the given bidder with the given config. 171 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 172 template, err := template.New("endpointTemplate").Parse(config.Endpoint) 173 if err != nil { 174 return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) 175 } 176 177 bidder := &adapter{ 178 EndpointTemplate: template, 179 } 180 return bidder, nil 181 }