-
Notifications
You must be signed in to change notification settings - Fork 755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NinthDecimal Adapter #1249
Merged
Merged
NinthDecimal Adapter #1249
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b0408f3
Submitting Prebid Server
918aeb5
Update Advangelists bidder code
227cd74
Add video test files
d11f5b2
Changes made as requested from Prebid
7a9a926
Made required changes
cca5df2
Correcting placement error
dc57df4
Updating formatting
29e3e44
Updated as requested
1d59a4d
Updated highlighted memory allocation issues
f14089d
PubId macro changes
20c87c9
PublisherID conversion to string on Adkernal adapter
68325e6
Ninth Decimal
f6d8e89
Updated as per prebid recomendation
dc60f2d
Fixed conflicts
b25d97a
Syncd again to check validation
fabd056
Updated as requested
0cacb22
Updating static bidder-params
dac000a
Updated changes requested
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
package ninthdecimal | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"text/template" | ||
|
||
"github.com/mxmCherry/openrtb" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/macros" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
type NinthdecimalAdapter struct { | ||
EndpointTemplate template.Template | ||
} | ||
|
||
//MakeRequests prepares request information for prebid-server core | ||
func (adapter *NinthdecimalAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
errs := make([]error, 0, len(request.Imp)) | ||
if len(request.Imp) == 0 { | ||
errs = append(errs, &errortypes.BadInput{Message: "No impression in the bid request"}) | ||
return nil, errs | ||
} | ||
pub2impressions, imps, err := getImpressionsInfo(request.Imp) | ||
if len(imps) == 0 { | ||
return nil, err | ||
} | ||
errs = append(errs, err...) | ||
|
||
if len(pub2impressions) == 0 { | ||
return nil, errs | ||
} | ||
|
||
result := make([]*adapters.RequestData, 0, len(pub2impressions)) | ||
for k, imps := range pub2impressions { | ||
bidRequest, err := adapter.buildAdapterRequest(request, &k, imps) | ||
if err != nil { | ||
errs = append(errs, err) | ||
return nil, errs | ||
} else { | ||
result = append(result, bidRequest) | ||
} | ||
} | ||
return result, errs | ||
} | ||
|
||
// getImpressionsInfo checks each impression for validity and returns impressions copy with corresponding exts | ||
func getImpressionsInfo(imps []openrtb.Imp) (map[openrtb_ext.ExtImpNinthdecimal][]openrtb.Imp, []openrtb.Imp, []error) { | ||
errors := make([]error, 0, len(imps)) | ||
resImps := make([]openrtb.Imp, 0, len(imps)) | ||
res := make(map[openrtb_ext.ExtImpNinthdecimal][]openrtb.Imp) | ||
|
||
for _, imp := range imps { | ||
impExt, err := getImpressionExt(&imp) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
if err := validateImpression(impExt); err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
//dispatchImpressions | ||
//Group impressions by ninthdecimal-specific parameters `pubid | ||
if err := compatImpression(&imp); err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
if res[*impExt] == nil { | ||
res[*impExt] = make([]openrtb.Imp, 0) | ||
} | ||
res[*impExt] = append(res[*impExt], imp) | ||
resImps = append(resImps, imp) | ||
} | ||
return res, resImps, errors | ||
} | ||
|
||
func validateImpression(impExt *openrtb_ext.ExtImpNinthdecimal) error { | ||
if impExt.PublisherID == "" { | ||
return &errortypes.BadInput{Message: "No pubid value provided"} | ||
} | ||
SyntaxNode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil | ||
} | ||
|
||
//Alter impression info to comply with ninthdecimal platform requirements | ||
func compatImpression(imp *openrtb.Imp) error { | ||
imp.Ext = nil //do not forward ext to ninthdecimal platform | ||
if imp.Banner != nil { | ||
return compatBannerImpression(imp) | ||
} | ||
SyntaxNode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nil | ||
} | ||
|
||
func compatBannerImpression(imp *openrtb.Imp) error { | ||
// Create a copy of the banner, since imp is a shallow copy of the original. | ||
|
||
bannerCopy := *imp.Banner | ||
banner := &bannerCopy | ||
//As banner.w/h are required fields for ninthdecimalAdn platform - take the first format entry | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copy/paste typo: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
if banner.W == nil || banner.H == nil { | ||
if len(banner.Format) == 0 { | ||
return &errortypes.BadInput{Message: "Expected at least one banner.format entry or explicit w/h"} | ||
} | ||
format := banner.Format[0] | ||
banner.Format = banner.Format[1:] | ||
banner.W = &format.W | ||
banner.H = &format.H | ||
imp.Banner = banner | ||
} | ||
return nil | ||
} | ||
|
||
func getImpressionExt(imp *openrtb.Imp) (*openrtb_ext.ExtImpNinthdecimal, error) { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: err.Error(), | ||
} | ||
} | ||
var ninthdecimalExt openrtb_ext.ExtImpNinthdecimal | ||
if err := json.Unmarshal(bidderExt.Bidder, &ninthdecimalExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: err.Error(), | ||
} | ||
} | ||
return &ninthdecimalExt, nil | ||
} | ||
|
||
func (adapter *NinthdecimalAdapter) buildAdapterRequest(prebidBidRequest *openrtb.BidRequest, params *openrtb_ext.ExtImpNinthdecimal, imps []openrtb.Imp) (*adapters.RequestData, error) { | ||
newBidRequest := createBidRequest(prebidBidRequest, params, imps) | ||
reqJSON, err := json.Marshal(newBidRequest) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
headers.Add("Accept", "application/json") | ||
headers.Add("x-openrtb-version", "2.5") | ||
|
||
url, err := adapter.buildEndpointURL(params) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &adapters.RequestData{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: reqJSON, | ||
Headers: headers}, nil | ||
} | ||
|
||
func createBidRequest(prebidBidRequest *openrtb.BidRequest, params *openrtb_ext.ExtImpNinthdecimal, imps []openrtb.Imp) *openrtb.BidRequest { | ||
bidRequest := *prebidBidRequest | ||
bidRequest.Imp = imps | ||
for idx := range bidRequest.Imp { | ||
imp := &bidRequest.Imp[idx] | ||
imp.TagID = params.Placement | ||
} | ||
if bidRequest.Site != nil { | ||
// Need to copy Site as Request is a shallow copy | ||
siteCopy := *bidRequest.Site | ||
bidRequest.Site = &siteCopy | ||
bidRequest.Site.Publisher = nil | ||
bidRequest.Site.Domain = "" | ||
} | ||
if bidRequest.App != nil { | ||
// Need to copy App as Request is a shallow copy | ||
appCopy := *bidRequest.App | ||
bidRequest.App = &appCopy | ||
bidRequest.App.Publisher = nil | ||
} | ||
return &bidRequest | ||
} | ||
|
||
// Builds enpoint url based on adapter-specific pub settings from imp.ext | ||
func (adapter *NinthdecimalAdapter) buildEndpointURL(params *openrtb_ext.ExtImpNinthdecimal) (string, error) { | ||
endpointParams := macros.EndpointTemplateParams{PublisherID: params.PublisherID} | ||
return macros.ResolveMacros(adapter.EndpointTemplate, endpointParams) | ||
} | ||
|
||
//MakeBids translates ninthdecimal bid response to prebid-server specific format | ||
func (adapter *NinthdecimalAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
var msg = "" | ||
if response.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} | ||
if response.StatusCode != http.StatusOK { | ||
msg = fmt.Sprintf("Unexpected http status code: %d", response.StatusCode) | ||
return nil, []error{&errortypes.BadServerResponse{Message: msg}} | ||
|
||
} | ||
var bidResp openrtb.BidResponse | ||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
msg = fmt.Sprintf("Bad server response: %d", err) | ||
return nil, []error{&errortypes.BadServerResponse{Message: msg}} | ||
} | ||
if len(bidResp.SeatBid) != 1 { | ||
var msg = fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid)) | ||
return nil, []error{&errortypes.BadServerResponse{Message: msg}} | ||
} | ||
|
||
seatBid := bidResp.SeatBid[0] | ||
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) | ||
|
||
for i := 0; i < len(seatBid.Bid); i++ { | ||
bid := seatBid.Bid[i] | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &bid, | ||
BidType: getMediaTypeForImpID(bid.ImpID, internalRequest.Imp), | ||
}) | ||
} | ||
return bidResponse, nil | ||
} | ||
|
||
// getMediaTypeForImp figures out which media type this bid is for | ||
func getMediaTypeForImpID(impID string, imps []openrtb.Imp) openrtb_ext.BidType { | ||
for _, imp := range imps { | ||
if imp.ID == impID && imp.Video != nil { | ||
return openrtb_ext.BidTypeVideo | ||
} | ||
} | ||
return openrtb_ext.BidTypeBanner | ||
} | ||
|
||
// NewNinthdecimalAdapter to be called in prebid-server core to create ninthdecimal adapter instance | ||
func NewNinthdecimalBidder(endpointTemplate string) adapters.Bidder { | ||
template, err := template.New("endpointTemplate").Parse(endpointTemplate) | ||
if err != nil { | ||
return nil | ||
} | ||
return &NinthdecimalAdapter{EndpointTemplate: *template} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ninthdecimal | ||
|
||
import ( | ||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
"testing" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
adapterstest.RunJSONBidderTest(t, "ninthdecimaltest", NewNinthdecimalBidder("http://rtb.ninthdecimal.com/xp/get?pubid={{.PublisherID}}")) | ||
} |
95 changes: 95 additions & 0 deletions
95
adapters/ninthdecimal/ninthdecimaltest/exemplary/banner.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
{ | ||
"mockBidRequest": { | ||
"id": "testid", | ||
"imp": [ | ||
{ | ||
"id": "testimpid", | ||
"banner": { | ||
"format": [ | ||
{ | ||
"w": 320, | ||
"h": 250 | ||
}, | ||
{ | ||
"w": 320, | ||
"h": 300 | ||
} | ||
], | ||
"w": 320, | ||
"h": 250 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"pubid": "19f1b372c7548ec1fe734d2c9f8dc688", | ||
"placement": "dummyplacement" | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
|
||
"httpCalls": [ | ||
{ | ||
"expectedRequest": { | ||
"uri": "http://rtb.ninthdecimal.com/xp/get?pubid=19f1b372c7548ec1fe734d2c9f8dc688", | ||
"body":{ | ||
"id": "testid", | ||
"imp": [{ | ||
"id": "testimpid", | ||
"tagid": "dummyplacement", | ||
"banner": { | ||
"format": [{ | ||
"w": 320, | ||
"h": 250 | ||
}, { | ||
"w": 320, | ||
"h": 300 | ||
}], | ||
"w": 320, | ||
"h": 250 | ||
} | ||
|
||
}] | ||
} | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"crid": "24080", | ||
"adid": "2068416", | ||
"price": 0.01, | ||
"id": "testid", | ||
"impid": "testimpid", | ||
"cid": "8048" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
], | ||
|
||
"expectedBidResponses": [ | ||
{ | ||
"currency": "USD", | ||
"bids": [ | ||
{ | ||
"bid": { | ||
"crid": "24080", | ||
"adid": "2068416", | ||
"price": 0.01, | ||
"id": "testid", | ||
"impid": "testimpid", | ||
"cid": "8048" | ||
}, | ||
"type": "banner" | ||
} | ||
] | ||
} | ||
] | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Consider using
NinthDecimal
instead ofNinthdecimal
for struct and method names to make your brand name clearer.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done