diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index 8084b2bcabe..40a80a4eaa9 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -40,9 +40,14 @@ type pubmaticBidExtVideo struct { Duration *int `json:"duration,omitempty"` } +type pubmaticContext struct { + Data json.RawMessage `json:"data"` +} + type ExtImpBidderPubmatic struct { adapters.ExtImpBidder - Data json.RawMessage `json:"data,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + Context pubmaticContext `json:"context"` } type ExtAdServer struct { @@ -305,6 +310,10 @@ func parseImpressionObject(imp *openrtb2.Imp, extractWrapperExtFromImp, extractP populateFirstPartyDataImpAttributes(bidderExt.Data, extMap) } + if len(bidderExt.Context.Data) > 0 { + populateFirstPartyDataImpAttributes(bidderExt.Context.Data, extMap) + } + imp.Ext = nil if len(extMap) > 0 { ext, err := json.Marshal(extMap) diff --git a/exchange/exchange.go b/exchange/exchange.go index 24ca193f989..737091d4ba8 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -348,13 +348,12 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog liveAdapters []openrtb_ext.BidderName ) - if len(r.StoredAuctionResponses) > 0 { - adapterBids, fledge, liveAdapters, err = buildStoredAuctionResponse(r.StoredAuctionResponses) + shouldMspBackfillBids := mspUpdateStoredAuctionResponse(r) + if len(r.StoredAuctionResponses) > 0 && !shouldMspBackfillBids { + adapterBids, fledge, liveAdapters, err, anyBidsReturned = mspApplyStoredAuctionResponse(r) if err != nil { return nil, err } - anyBidsReturned = true - } else { // List of bidders we have requests for. liveAdapters = listBiddersWithRequests(bidderRequests) @@ -367,6 +366,10 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog alternateBidderCodes = *r.Account.AlternateBidderCodes } adapterBids, adapterExtra, fledge, anyBidsReturned = e.getAllBids(auctionCtx, bidderRequests, bidAdjustmentFactors, conversions, accountDebugAllow, r.GlobalPrivacyControlHeader, debugLog.DebugOverride, alternateBidderCodes, requestExtLegacy.Prebid.Experiment, r.HookExecutor, r.StartTime, bidAdjustmentRules) + adapterBids, fledge, liveAdapters, err, anyBidsReturned = mspPostProcessAuction(r, liveAdapters, adapterBids, adapterExtra, fledge, anyBidsReturned, shouldMspBackfillBids) + if err != nil { + return nil, err + } r.MakeBidsTimeInfo = buildMakeBidsTimeInfoMap(adapterExtra) } diff --git a/exchange/msp_exchange.go b/exchange/msp_exchange.go new file mode 100644 index 00000000000..9a712c382ca --- /dev/null +++ b/exchange/msp_exchange.go @@ -0,0 +1,62 @@ +package exchange + +import ( + "encoding/json" + "time" + + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/exchange/entities" + "github.com/prebid/prebid-server/openrtb_ext" +) + +const ( + MSP_SEAT_IN_HOUSE = "msp-in-house" +) + +func mspUpdateStoredAuctionResponse(r *AuctionRequest) bool { + if len(r.StoredAuctionResponses) > 0 { + if rawSeatBid, ok := r.StoredAuctionResponses[r.BidRequestWrapper.Imp[0].ID]; ok { + var seatBids []openrtb2.SeatBid + + err := json.Unmarshal(rawSeatBid, &seatBids) + if err == nil && len(seatBids) > 0 && seatBids[0].Seat == MSP_SEAT_IN_HOUSE { + // when price is the same, randomly choose one + swapIdx := time.Now().Second() % len(seatBids[0].Bid) + seatBids[0].Bid[0], seatBids[0].Bid[swapIdx] = seatBids[0].Bid[swapIdx], seatBids[0].Bid[0] + updatedJson, _ := json.Marshal(seatBids) + r.StoredAuctionResponses[r.BidRequestWrapper.Imp[0].ID] = updatedJson + return true + } + } + } + + return false +} + +func mspApplyStoredAuctionResponse(r *AuctionRequest) (map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, + *openrtb_ext.Fledge, + []openrtb_ext.BidderName, + error, bool) { + adapterBids, fledge, liveAdapters, err := buildStoredAuctionResponse(r.StoredAuctionResponses) + return adapterBids, fledge, liveAdapters, err, err == nil +} + +func mspPostProcessAuction( + r *AuctionRequest, + liveAdapters []openrtb_ext.BidderName, + adapterBids map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, + adapterExtra map[openrtb_ext.BidderName]*seatResponseExtra, + fledge *openrtb_ext.Fledge, + anyBidsReturned bool, + shouldMspBackfillBids bool) (map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid, + *openrtb_ext.Fledge, + []openrtb_ext.BidderName, + error, bool) { + // TODO: freqcap, blocking + + if shouldMspBackfillBids && !anyBidsReturned { + return mspApplyStoredAuctionResponse(r) + } + + return adapterBids, fledge, liveAdapters, nil, anyBidsReturned +}