Skip to content

Commit

Permalink
OpenWeb: Adapter Refactor + New Endpoint (#3670)
Browse files Browse the repository at this point in the history
Co-authored-by: Zdravko Kosanovic <[email protected]>
Co-authored-by: Dedi Sidi <[email protected]>
  • Loading branch information
3 people authored Jul 1, 2024
1 parent 8784615 commit 80a90dd
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 634 deletions.
202 changes: 73 additions & 129 deletions adapters/openweb/openweb.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package openweb

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"strings"

"github.com/prebid/openrtb/v20/openrtb2"

"github.com/prebid/prebid-server/v2/adapters"
"github.com/prebid/prebid-server/v2/config"
"github.com/prebid/prebid-server/v2/errortypes"
Expand All @@ -16,175 +20,115 @@ type adapter struct {
endpoint string
}

type openwebImpExt struct {
OpenWeb openrtb_ext.ExtImpOpenWeb `json:"openweb"`
}

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
totalImps := len(request.Imp)
errors := make([]error, 0, totalImps)
sourceIdToImpIds := make(map[int][]int)
var sourceIds []int

for i := 0; i < totalImps; i++ {

sourceId, err := validateImpression(&request.Imp[i])

if err != nil {
errors = append(errors, err)
continue
}

if _, ok := sourceIdToImpIds[sourceId]; !ok {
sourceIdToImpIds[sourceId] = make([]int, 0, totalImps-i)
sourceIds = append(sourceIds, sourceId)
}

sourceIdToImpIds[sourceId] = append(sourceIdToImpIds[sourceId], i)

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) (requestsToBidder []*adapters.RequestData, errs []error) {
org, err := checkExtAndExtractOrg(request)
if err != nil {
errs = append(errs, fmt.Errorf("checkExtAndExtractOrg: %w", err))
return nil, errs
}

totalReqs := len(sourceIdToImpIds)
if totalReqs == 0 {
return nil, errors
requestJSON, err := json.Marshal(request)
if err != nil {
errs = append(errs, fmt.Errorf("marshal bidRequest: %w", err))
return nil, errs
}

headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")

reqs := make([]*adapters.RequestData, 0, totalReqs)
return append(requestsToBidder, &adapters.RequestData{
Method: http.MethodPost,
Uri: a.endpoint + "?publisher_id=" + org,
Body: requestJSON,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}), nil
}

imps := request.Imp
reqCopy := *request
reqCopy.Imp = make([]openrtb2.Imp, totalImps)
for _, sourceId := range sourceIds {
impIds := sourceIdToImpIds[sourceId]
reqCopy.Imp = reqCopy.Imp[:0]
// checkExtAndExtractOrg checks the presence of required parameters and extracts the Org ID string.
func checkExtAndExtractOrg(request *openrtb2.BidRequest) (string, error) {
var err error
for _, imp := range request.Imp {
var bidderExt adapters.ExtImpBidder
if err = json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return "", fmt.Errorf("unmarshal bidderExt: %w", err)
}

for i := 0; i < len(impIds); i++ {
reqCopy.Imp = append(reqCopy.Imp, imps[impIds[i]])
var impExt openrtb_ext.ExtImpOpenWeb
if err = json.Unmarshal(bidderExt.Bidder, &impExt); err != nil {
return "", fmt.Errorf("unmarshal ExtImpOpenWeb: %w", err)
}

body, err := json.Marshal(reqCopy)
if err != nil {
errors = append(errors, fmt.Errorf("error while encoding bidRequest, err: %s", err))
return nil, errors
if impExt.PlacementID == "" {
return "", errors.New("no placement id supplied")
}

reqs = append(reqs, &adapters.RequestData{
Method: "POST",
Uri: a.endpoint + fmt.Sprintf("?aid=%d", sourceId),
Body: body,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(reqCopy.Imp),
})
}
if impExt.Org != "" {
return strings.TrimSpace(impExt.Org), nil
}

return reqs, errors
if impExt.Aid != 0 {
return strconv.Itoa(impExt.Aid), nil
}
}

return "", errors.New("no org or aid supplied")
}

func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) {

if httpRes.StatusCode == http.StatusNoContent {
func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if adapters.IsResponseStatusCodeNoContent(responseData) {
return nil, nil
}

if httpRes.StatusCode != http.StatusOK {
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("Remote server error: %s", httpRes.Body),
}}
}
var bidResp openrtb2.BidResponse
if err := json.Unmarshal(httpRes.Body, &bidResp); err != nil {
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("error while decoding response, err: %s", err),
}}
if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponse()
var errors []error
var response openrtb2.BidResponse
if err := json.Unmarshal(responseData.Body, &response); err != nil {
return nil, []error{err}
}

for _, sb := range bidResp.SeatBid {
for i := 0; i < len(sb.Bid); i++ {
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
if response.Cur != "" {
bidResponse.Currency = response.Cur
}

bid := sb.Bid[i]
var errs []error

mediaType, impOK := getBidType(bidReq.Imp, bid.ImpID)
if !impOK {
errors = append(errors, &errortypes.BadServerResponse{
Message: fmt.Sprintf("ignoring bid id=%s, request doesn't contain any impression with id=%s", bid.ID, bid.ImpID),
})
for _, seatBid := range response.SeatBid {
for i, bid := range seatBid.Bid {
bidType, err := getMediaTypeForBid(bid)
if err != nil {
errs = append(errs, err)
continue
}

bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: mediaType,
Bid: &seatBid.Bid[i],
BidType: bidType,
})
}
}

return bidResponse, errors
return bidResponse, errs
}

func getBidType(imps []openrtb2.Imp, impId string) (mediaType openrtb_ext.BidType, ok bool) {
mediaType = openrtb_ext.BidTypeBanner
for _, imp := range imps {
if imp.ID == impId {
ok = true

if imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
}

break
}
}

return
}

func validateImpression(imp *openrtb2.Imp) (int, error) {
var bidderExt adapters.ExtImpBidder

if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err),
}
}

impExt := openrtb_ext.ExtImpOpenWeb{}
err := json.Unmarshal(bidderExt.Bidder, &impExt)
if err != nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err),
func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
switch bid.MType {
case openrtb2.MarkupBanner:
return openrtb_ext.BidTypeBanner, nil
case openrtb2.MarkupVideo:
return openrtb_ext.BidTypeVideo, nil
default:
return "", &errortypes.BadServerResponse{
Message: fmt.Sprintf("unsupported MType %d", bid.MType),
}
}

var impExtBuffer []byte

impExtBuffer, err = json.Marshal(&openwebImpExt{
OpenWeb: impExt,
})
if err != nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, error while encoding impExt, err: %s", imp.ID, err),
}
}

if impExt.BidFloor > 0 {
imp.BidFloor = impExt.BidFloor
}

imp.Ext = impExtBuffer

return impExt.SourceID, nil
}

// Builder builds a new instance of the OpenWeb adapter for the given bidder with the given config.
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) {
bidder := &adapter{
endpoint: config.Endpoint,
}
Expand Down
2 changes: 1 addition & 1 deletion adapters/openweb/openweb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(openrtb_ext.BidderOpenWeb, config.Adapter{
Endpoint: "http://ghb.spotim.market/pbs/ortb"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
Endpoint: "https://pbs.openwebmp.com/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})

if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
Expand Down
Loading

0 comments on commit 80a90dd

Please sign in to comment.