Skip to content

Commit

Permalink
PubMatic + OpenWrap: Support request level Bidder Params prebid#1042 (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
sachin-pubmatic authored and shunj-nb committed Nov 8, 2022
1 parent 015ad58 commit d060895
Show file tree
Hide file tree
Showing 18 changed files with 1,415 additions and 27 deletions.
61 changes: 61 additions & 0 deletions adapters/openrtb_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package adapters

import (
"encoding/json"
"errors"
"fmt"
"github.com/mxmCherry/openrtb/v15/openrtb2"
"github.com/prebid/prebid-server/openrtb_ext"
)

func ExtractAdapterReqBidderParams(bidRequest *openrtb2.BidRequest) (map[string]json.RawMessage, error) {
if bidRequest == nil {
return nil, errors.New("error bidRequest should not be nil")
}

reqExt := &openrtb_ext.ExtRequest{}
if len(bidRequest.Ext) > 0 {
err := json.Unmarshal(bidRequest.Ext, &reqExt)
if err != nil {
return nil, fmt.Errorf("error decoding Request.ext : %s", err.Error())
}
}

if reqExt.Prebid.BidderParams == nil {
return nil, nil
}

var bidderParams map[string]json.RawMessage
err := json.Unmarshal(reqExt.Prebid.BidderParams, &bidderParams)
if err != nil {
return nil, err
}

return bidderParams, nil
}

func ExtractReqExtBidderParams(bidReq *openrtb2.BidRequest) (map[string]map[string]json.RawMessage, error) {
if bidReq == nil {
return nil, errors.New("error bidRequest should not be nil")
}

reqExt := &openrtb_ext.ExtRequest{}
if len(bidReq.Ext) > 0 {
err := json.Unmarshal(bidReq.Ext, &reqExt)
if err != nil {
return nil, fmt.Errorf("error decoding Request.ext : %s", err.Error())
}
}

if reqExt.Prebid.BidderParams == nil {
return nil, nil
}

var bidderParams map[string]map[string]json.RawMessage
err := json.Unmarshal(reqExt.Prebid.BidderParams, &bidderParams)
if err != nil {
return nil, err
}

return bidderParams, nil
}
117 changes: 117 additions & 0 deletions adapters/openrtb_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package adapters

import (
"encoding/json"
"github.com/mxmCherry/openrtb/v15/openrtb2"
"reflect"
"testing"
)

func TestExtractAdapterReqBidderParams(t *testing.T) {
type args struct {
bidRequest *openrtb2.BidRequest
}
tests := []struct {
name string
args args
want map[string]json.RawMessage
wantErr bool
}{
{
name: "extract bidder params from nil req",
args: args{
bidRequest: nil,
},
want: nil,
wantErr: true,
},
{
name: "extract bidder params from nil req.Ext",
args: args{
bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{}}`)},
},
want: nil,
wantErr: false,
},
{
name: "extract bidder params from req.Ext for input request in adapter code",
args: args{
bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"bidderparams": {"profile": 1234, "version": 1}}}`)},
},
want: map[string]json.RawMessage{"profile": json.RawMessage(`1234`), "version": json.RawMessage(`1`)},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ExtractAdapterReqBidderParams(tt.args.bidRequest)
if (err != nil) != tt.wantErr {
t.Errorf("ExtractReqExtBidderParams() error = %v, wantErr = %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtractReqExtBidderParams() got = %v, want = %v", got, tt.want)
}
})
}
}

func TestExtractReqExtBidderParams(t *testing.T) {
type args struct {
request *openrtb2.BidRequest
}
tests := []struct {
name string
args args
want map[string]map[string]json.RawMessage
wantErr bool
}{
{
name: "extract bidder params from nil req",
args: args{
request: nil,
},
want: nil,
wantErr: true,
},
{
name: "extract bidder params from nil req.Ext.prebid",
args: args{
request: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{}}`)},
},
want: nil,
wantErr: false,
},
{
name: "extract bidder params from nil req.Ext",
args: args{
request: &openrtb2.BidRequest{Ext: nil},
},
want: nil,
wantErr: false,
},
{
name: "extract bidder params from req.Ext for input request before adapter code",
args: args{
request: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"bidderparams": {"pubmatic": {"profile": 1234, "version": 1}, "appnexus": {"key1": 123, "key2": {"innerKey1":"innerValue1"} } }}}`)},
},
want: map[string]map[string]json.RawMessage{
"pubmatic": {"profile": json.RawMessage(`1234`), "version": json.RawMessage(`1`)},
"appnexus": {"key1": json.RawMessage(`123`), "key2": json.RawMessage(`{"innerKey1":"innerValue1"}`)},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ExtractReqExtBidderParams(tt.args.request)
if (err != nil) != tt.wantErr {
t.Errorf("ExtractReqExtBidderParams() error = %v, wantErr = %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtractReqExtBidderParams() got = %v, want = %v", got, tt.want)
}
})
}
}
103 changes: 84 additions & 19 deletions adapters/pubmatic/pubmatic.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type pubmaticBidExt struct {
VideoCreativeInfo *pubmaticBidExtVideo `json:"video,omitempty"`
}

type pubmaticWrapperExt struct {
ProfileID int `json:"profile,omitempty"`
VersionID int `json:"version,omitempty"`
}

type pubmaticBidExtVideo struct {
Duration *int `json:"duration,omitempty"`
}
Expand Down Expand Up @@ -56,16 +61,51 @@ const (
func (a *PubmaticAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
errs := make([]error, 0, len(request.Imp))

wrapExt := ""
pubID := ""
var wrapperExt *pubmaticWrapperExt
extractWrapperExtFromImp := true
extractPubIDFromImp := true

wrapperExt, err := extractPubmaticWrapperExtFromRequest(request)
if err != nil {
return nil, []error{err}
}
if wrapperExt != nil && wrapperExt.ProfileID != 0 && wrapperExt.VersionID != 0 {
extractWrapperExtFromImp = false
}

for i := 0; i < len(request.Imp); i++ {
err := parseImpressionObject(&request.Imp[i], &wrapExt, &pubID)
wrapperExtFromImp, pubIDFromImp, err := parseImpressionObject(&request.Imp[i], extractWrapperExtFromImp, extractPubIDFromImp)

// If the parsing is failed, remove imp and add the error.
if err != nil {
errs = append(errs, err)
request.Imp = append(request.Imp[:i], request.Imp[i+1:]...)
i--
continue
}

if extractWrapperExtFromImp {
if wrapperExtFromImp != nil {
if wrapperExt == nil {
wrapperExt = &pubmaticWrapperExt{}
}
if wrapperExt.ProfileID == 0 {
wrapperExt.ProfileID = wrapperExtFromImp.ProfileID
}
if wrapperExt.VersionID == 0 {
wrapperExt.VersionID = wrapperExtFromImp.VersionID
}

if wrapperExt != nil && wrapperExt.ProfileID != 0 && wrapperExt.VersionID != 0 {
extractWrapperExtFromImp = false
}
}
}

if extractPubIDFromImp && pubIDFromImp != "" {
pubID = pubIDFromImp
extractPubIDFromImp = false
}
}

Expand All @@ -74,9 +114,14 @@ func (a *PubmaticAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ad
return nil, errs
}

if wrapExt != "" {
rawExt := fmt.Sprintf("{\"wrapper\": %s}", wrapExt)
request.Ext = json.RawMessage(rawExt)
if wrapperExt != nil {
reqExt := make(map[string]interface{})
reqExt["wrapper"] = wrapperExt
rawExt, err := json.Marshal(reqExt)
if err != nil {
return nil, []error{err}
}
request.Ext = rawExt
}

if request.Site != nil {
Expand Down Expand Up @@ -179,10 +224,13 @@ func assignBannerWidthAndHeight(banner *openrtb2.Banner, w, h int64) *openrtb2.B
}

// parseImpressionObject parse the imp to get it ready to send to pubmatic
func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) error {
func parseImpressionObject(imp *openrtb2.Imp, extractWrapperExtFromImp, extractPubIDFromImp bool) (*pubmaticWrapperExt, string, error) {
var wrapExt *pubmaticWrapperExt
var pubID string

// PubMatic supports banner and video impressions.
if imp.Banner == nil && imp.Video == nil {
return fmt.Errorf("Invalid MediaType. PubMatic only supports Banner and Video. Ignoring ImpID=%s", imp.ID)
return wrapExt, pubID, fmt.Errorf("Invalid MediaType. PubMatic only supports Banner and Video. Ignoring ImpID=%s", imp.ID)
}

if imp.Audio != nil {
Expand All @@ -191,36 +239,34 @@ func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) er

var bidderExt ExtImpBidderPubmatic
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return err
return wrapExt, pubID, err
}

var pubmaticExt openrtb_ext.ExtImpPubmatic
if err := json.Unmarshal(bidderExt.Bidder, &pubmaticExt); err != nil {
return err
return wrapExt, pubID, err
}

if *pubID == "" {
*pubID = strings.TrimSpace(pubmaticExt.PublisherId)
if extractPubIDFromImp {
pubID = strings.TrimSpace(pubmaticExt.PublisherId)
}

// Parse Wrapper Extension only once per request
if *wrapExt == "" && len(pubmaticExt.WrapExt) != 0 {
var wrapExtMap map[string]int
err := json.Unmarshal([]byte(pubmaticExt.WrapExt), &wrapExtMap)
if extractWrapperExtFromImp && len(pubmaticExt.WrapExt) != 0 {
err := json.Unmarshal([]byte(pubmaticExt.WrapExt), &wrapExt)
if err != nil {
return fmt.Errorf("Error in Wrapper Parameters = %v for ImpID = %v WrapperExt = %v", err.Error(), imp.ID, string(pubmaticExt.WrapExt))
return wrapExt, pubID, fmt.Errorf("Error in Wrapper Parameters = %v for ImpID = %v WrapperExt = %v", err.Error(), imp.ID, string(pubmaticExt.WrapExt))
}
*wrapExt = string(pubmaticExt.WrapExt)
}

if err := validateAdSlot(strings.TrimSpace(pubmaticExt.AdSlot), imp); err != nil {
return err
return wrapExt, pubID, err
}

if imp.Banner != nil {
bannerCopy, err := assignBannerSize(imp.Banner)
if err != nil {
return err
return wrapExt, pubID, err
}
imp.Banner = bannerCopy
}
Expand Down Expand Up @@ -253,7 +299,26 @@ func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) er
}
}

return nil
return wrapExt, pubID, nil
}

// extractPubmaticWrapperExtFromRequest parse the imp to get it ready to send to pubmatic
func extractPubmaticWrapperExtFromRequest(request *openrtb2.BidRequest) (*pubmaticWrapperExt, error) {
var wrpExt pubmaticWrapperExt
reqExtBidderParams, err := adapters.ExtractAdapterReqBidderParams(request)
if err != nil {
return nil, err
}

//get request ext bidder params
if wrapperObj, present := reqExtBidderParams["wrapper"]; present && len(wrapperObj) != 0 {
err = json.Unmarshal(wrapperObj, &wrpExt)
if err != nil {
return nil, err
}
return &wrpExt, nil
}
return nil, nil
}

func addKeywordsToExt(keywords []*openrtb_ext.ExtImpPubmaticKeyVal, extMap map[string]interface{}) {
Expand Down
Loading

0 comments on commit d060895

Please sign in to comment.