github.com/prebid/prebid-server/v2@v2.18.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/v20/openrtb2" 9 "github.com/prebid/prebid-server/v2/adapters" 10 "github.com/prebid/prebid-server/v2/config" 11 "github.com/prebid/prebid-server/v2/errortypes" 12 "github.com/prebid/prebid-server/v2/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, 106 ImpIDs: openrtb_ext.GetImpIDs(imps)}, nil 107 } 108 109 func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpLogicad, imps []openrtb2.Imp) *openrtb2.BidRequest { 110 bidRequest := *prebidBidRequest 111 bidRequest.Imp = imps 112 for idx := range bidRequest.Imp { 113 imp := &bidRequest.Imp[idx] 114 imp.TagID = params.Tid 115 imp.Ext = nil 116 } 117 return &bidRequest 118 } 119 120 // MakeBids translates Logicad bid response to prebid-server specific format 121 func (adapter *LogicadAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { 122 if response.StatusCode == http.StatusNoContent { 123 return nil, nil 124 } 125 if response.StatusCode != http.StatusOK { 126 msg := fmt.Sprintf("Unexpected http status code: %d", response.StatusCode) 127 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 128 129 } 130 var bidResp openrtb2.BidResponse 131 if err := json.Unmarshal(response.Body, &bidResp); err != nil { 132 msg := fmt.Sprintf("Bad server response: %d", err) 133 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 134 } 135 if len(bidResp.SeatBid) != 1 { 136 msg := fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid)) 137 return nil, []error{&errortypes.BadServerResponse{Message: msg}} 138 } 139 140 seatBid := bidResp.SeatBid[0] 141 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seatBid.Bid)) 142 143 for i := 0; i < len(seatBid.Bid); i++ { 144 bid := seatBid.Bid[i] 145 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 146 Bid: &bid, 147 BidType: openrtb_ext.BidTypeBanner, 148 }) 149 } 150 if bidResp.Cur != "" { 151 bidResponse.Currency = bidResp.Cur 152 } 153 return bidResponse, nil 154 } 155 156 // Builder builds a new instance of the Logicad adapter for the given bidder with the given config. 157 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 158 bidder := &LogicadAdapter{ 159 endpoint: config.Endpoint, 160 } 161 return bidder, nil 162 }