github.com/prebid/prebid-server@v0.275.0/adapters/logicad/logicad.go (about) 1 package logicad 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/prebid/openrtb/v19/openrtb2" 9 "github.com/prebid/prebid-server/adapters" 10 "github.com/prebid/prebid-server/config" 11 "github.com/prebid/prebid-server/errortypes" 12 "github.com/prebid/prebid-server/openrtb_ext" 13 ) 14 15 type LogicadAdapter struct { 16 endpoint string 17 } 18 19 func (adapter *LogicadAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 20 if len(request.Imp) == 0 { 21 return nil, []error{&errortypes.BadInput{Message: "No impression in the bid request"}} 22 } 23 24 pub2impressions, imps, errs := getImpressionsInfo(request.Imp) 25 if len(pub2impressions) == 0 || len(imps) == 0 { 26 return nil, errs 27 } 28 29 result := make([]*adapters.RequestData, 0, len(pub2impressions)) 30 for k, imps := range pub2impressions { 31 bidRequest, err := adapter.buildAdapterRequest(request, &k, imps) 32 if err != nil { 33 errs = append(errs, err) 34 } else { 35 result = append(result, bidRequest) 36 } 37 } 38 return result, errs 39 } 40 41 func getImpressionsInfo(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpLogicad][]openrtb2.Imp, []openrtb2.Imp, []error) { 42 errors := make([]error, 0, len(imps)) 43 resImps := make([]openrtb2.Imp, 0, len(imps)) 44 res := make(map[openrtb_ext.ExtImpLogicad][]openrtb2.Imp) 45 46 for _, imp := range imps { 47 impExt, err := getImpressionExt(&imp) 48 if err != nil { 49 errors = append(errors, err) 50 continue 51 } 52 if err := validateImpression(&impExt); err != nil { 53 errors = append(errors, err) 54 continue 55 } 56 57 if res[impExt] == nil { 58 res[impExt] = make([]openrtb2.Imp, 0) 59 } 60 res[impExt] = append(res[impExt], imp) 61 resImps = append(resImps, imp) 62 } 63 return res, resImps, errors 64 } 65 66 func validateImpression(impExt *openrtb_ext.ExtImpLogicad) error { 67 if impExt.Tid == "" { 68 return &errortypes.BadInput{Message: "No tid value provided"} 69 } 70 return nil 71 } 72 73 func getImpressionExt(imp *openrtb2.Imp) (openrtb_ext.ExtImpLogicad, error) { 74 var bidderExt adapters.ExtImpBidder 75 var logicadExt openrtb_ext.ExtImpLogicad 76 77 if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { 78 return logicadExt, &errortypes.BadInput{ 79 Message: err.Error(), 80 } 81 } 82 if err := json.Unmarshal(bidderExt.Bidder, &logicadExt); err != nil { 83 return logicadExt, &errortypes.BadInput{ 84 Message: err.Error(), 85 } 86 } 87 return logicadExt, nil 88 } 89 90 func (adapter *LogicadAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) (*adapters.RequestData, error) { 91 newBidRequest := createBidRequest(prebidBidRequest, params, imps) 92 reqJSON, err := json.Marshal(newBidRequest) 93 if err != nil { 94 return nil, err 95 } 96 97 headers := http.Header{} 98 headers.Add("Content-Type", "application/json;charset=utf-8") 99 headers.Add("Accept", "application/json") 100 101 return &adapters.RequestData{ 102 Method: "POST", 103 Uri: adapter.endpoint, 104 Body: reqJSON, 105 Headers: headers}, nil 106 } 107 108 func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) *openrtb2.BidRequest { 109 bidRequest := *prebidBidRequest 110 bidRequest.Imp = imps 111 for idx := range bidRequest.Imp { 112 imp := &bidRequest.Imp[idx] 113 imp.TagID = params.Tid 114 imp.Ext = nil 115 } 116 return &bidRequest 117 } 118 119 // MakeBids translates Logicad bid response to prebid-server specific format 120 func (adapter *LogicadAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 121 if response.StatusCode == http.StatusNoContent { 122 return nil, nil 123 } 124 if response.StatusCode != http.StatusOK { 125 msg := fmt.Sprintf("Unexpected http status code: %d", response.StatusCode) 126 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 127 128 } 129 var bidResp openrtb2.BidResponse 130 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 131 msg := fmt.Sprintf("Bad server response: %d", err) 132 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 133 } 134 if len(bidResp.SeatBid) != 1 { 135 msg := fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid)) 136 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 137 } 138 139 seatBid := bidResp.SeatBid[0] 140 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seatBid.Bid)) 141 142 for i := 0; i < len(seatBid.Bid); i++ { 143 bid := seatBid.Bid[i] 144 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 145 Bid: &bid, 146 BidType: openrtb_ext.BidTypeBanner, 147 }) 148 } 149 if bidResp.Cur != "" { 150 bidResponse.Currency = bidResp.Cur 151 } 152 return bidResponse, nil 153 } 154 155 // Builder builds a new instance of the Logicad adapter for the given bidder with the given config. 156 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 157 bidder := &LogicadAdapter{ 158 endpoint: config.Endpoint, 159 } 160 return bidder, nil 161 }