github.com/prebid/prebid-server/v2@v2.18.0/adapters/lm_kiviads/lmkiviads.go (about) 1 package lmkiviads 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 bidType struct { 18 Type string `json:"type"` 19 } 20 21 type bidExt struct { 22 Prebid bidType `json:"prebid"` 23 } 24 25 type adapter struct { 26 endpoint *template.Template 27 } 28 29 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { 30 tmpl, 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: tmpl, 37 } 38 39 return bidder, nil 40 } 41 42 func (a *adapter) buildEndpointFromRequest(imp *openrtb2.Imp) (string, error) { 43 var impExt adapters.ExtImpBidder 44 if err := json.Unmarshal(imp.Ext, &impExt); err != nil { 45 return "", &errortypes.BadInput{ 46 Message: fmt.Sprintf("Failed to deserialize bidder impression extension: %v", err), 47 } 48 } 49 50 var kiviExt openrtb_ext.ExtLmKiviads 51 if err := json.Unmarshal(impExt.Bidder, &kiviExt); err != nil { 52 return "", &errortypes.BadInput{ 53 Message: fmt.Sprintf("Failed to deserialize LmKiviads extension: %v", err), 54 } 55 } 56 57 endpointParams := macros.EndpointTemplateParams{ 58 Host: kiviExt.Env, 59 SourceId: kiviExt.Pid, 60 } 61 62 return macros.ResolveMacros(a.endpoint, endpointParams) 63 } 64 65 func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { 66 var requests []*adapters.RequestData 67 var errs []error 68 69 headers := http.Header{} 70 headers.Add("Content-Type", "application/json;charset=utf-8") 71 headers.Add("Accept", "application/json") 72 73 requestCopy := *request 74 for _, imp := range request.Imp { 75 requestCopy.Imp = []openrtb2.Imp{imp} 76 77 endpoint, err := a.buildEndpointFromRequest(&imp) 78 if err != nil { 79 errs = append(errs, err) 80 continue 81 } 82 83 requestJSON, err := json.Marshal(requestCopy) 84 if err != nil { 85 errs = append(errs, err) 86 continue 87 } 88 89 request := &adapters.RequestData{ 90 Method: http.MethodPost, 91 Body: requestJSON, 92 Uri: endpoint, 93 Headers: headers, 94 ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), 95 } 96 97 requests = append(requests, request) 98 } 99 100 return requests, errs 101 } 102 103 func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (*adapters.BidderResponse, []error) { 104 if adapters.IsResponseStatusCodeNoContent(bidderRawResponse) { 105 return nil, nil 106 } 107 108 if bidderRawResponse.StatusCode == http.StatusServiceUnavailable { 109 return nil, []error{&errortypes.BadInput{ 110 Message: "Bidder LmKiviads is unavailable. Please contact the bidder support.", 111 }} 112 } 113 114 if err := adapters.CheckResponseStatusCodeForErrors(bidderRawResponse); err != nil { 115 return nil, []error{err} 116 } 117 118 var bidResp openrtb2.BidResponse 119 if err := json.Unmarshal(bidderRawResponse.Body, &bidResp); err != nil { 120 return nil, []error{err} 121 } 122 123 if len(bidResp.SeatBid) == 0 { 124 return nil, []error{&errortypes.BadServerResponse{ 125 Message: "Array SeatBid cannot be empty", 126 }} 127 } 128 129 return prepareBidResponse(bidResp.SeatBid) 130 } 131 132 func prepareBidResponse(seats []openrtb2.SeatBid) (*adapters.BidderResponse, []error) { 133 errs := []error{} 134 bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seats)) 135 136 for _, seatBid := range seats { 137 for bidId, bid := range seatBid.Bid { 138 var bidExt bidExt 139 if err := json.Unmarshal(bid.Ext, &bidExt); err != nil { 140 errs = append(errs, &errortypes.BadServerResponse{ 141 Message: fmt.Sprintf("Failed to parse Bid[%d].Ext: %s", bidId, err.Error()), 142 }) 143 continue 144 } 145 146 bidType, err := openrtb_ext.ParseBidType(bidExt.Prebid.Type) 147 if err != nil { 148 errs = append(errs, &errortypes.BadServerResponse{ 149 Message: fmt.Sprintf("Bid[%d].Ext.Prebid.Type expects one of the following values: 'banner', 'native', 'video', 'audio', got '%s'", bidId, bidExt.Prebid.Type), 150 }) 151 continue 152 } 153 154 bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ 155 Bid: &seatBid.Bid[bidId], 156 BidType: bidType, 157 }) 158 } 159 } 160 161 return bidResponse, errs 162 }