-
Notifications
You must be signed in to change notification settings - Fork 762
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
148b1f1
commit 7d9b1ec
Showing
29 changed files
with
1,266 additions
and
0 deletions.
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,189 @@ | ||
package smartrtb | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"text/template" | ||
|
||
"github.com/golang/glog" | ||
"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" | ||
) | ||
|
||
// Base adapter structure. | ||
type SmartRTBAdapter struct { | ||
EndpointTemplate template.Template | ||
} | ||
|
||
// Bid request extension appended to downstream request. | ||
// PubID are non-empty iff request.{App,Site} or | ||
// request.{App,Site}.Publisher are nil, respectively. | ||
type bidRequestExt struct { | ||
PubID string `json:"pub_id,omitempty"` | ||
ZoneID string `json:"zone_id,omitempty"` | ||
ForceBid bool `json:"force_bid,omitempty"` | ||
} | ||
|
||
// bidExt.CreativeType values. | ||
const ( | ||
creativeTypeBanner string = "BANNER" | ||
creativeTypeVideo = "VIDEO" | ||
creativeTypeNative = "NATIVE" | ||
creativeTypeAudio = "AUDIO" | ||
) | ||
|
||
// Bid response extension from downstream. | ||
type bidExt struct { | ||
CreativeType string `json:"format"` | ||
} | ||
|
||
func NewSmartRTBBidder(endpointTemplate string) adapters.Bidder { | ||
template, err := template.New("endpointTemplate").Parse(endpointTemplate) | ||
if err != nil { | ||
glog.Fatal("Template URL error") | ||
return nil | ||
} | ||
return &SmartRTBAdapter{EndpointTemplate: *template} | ||
} | ||
|
||
func (adapter *SmartRTBAdapter) buildEndpointURL(pubID string) (string, error) { | ||
endpointParams := macros.EndpointTemplateParams{PublisherID: pubID} | ||
return macros.ResolveMacros(adapter.EndpointTemplate, endpointParams) | ||
} | ||
|
||
func parseExtImp(dst *bidRequestExt, imp *openrtb.Imp) error { | ||
var ext adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &ext); err != nil { | ||
return adapters.BadInput(err.Error()) | ||
} | ||
|
||
var src openrtb_ext.ExtImpSmartRTB | ||
if err := json.Unmarshal(ext.Bidder, &src); err != nil { | ||
return adapters.BadInput(err.Error()) | ||
} | ||
|
||
if dst.PubID == "" { | ||
dst.PubID = src.PubID | ||
} | ||
|
||
if src.ZoneID != "" { | ||
imp.TagID = src.ZoneID | ||
} | ||
return nil | ||
} | ||
|
||
func (s *SmartRTBAdapter) MakeRequests(brq *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
var imps []openrtb.Imp | ||
var err error | ||
ext := bidRequestExt{} | ||
nrImps := len(brq.Imp) | ||
errs := make([]error, 0, nrImps) | ||
|
||
for i := 0; i < nrImps; i++ { | ||
imp := brq.Imp[i] | ||
if imp.Banner == nil && imp.Video == nil { | ||
continue | ||
} | ||
|
||
err = parseExtImp(&ext, &imp) | ||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
imps = append(imps, imp) | ||
} | ||
|
||
if len(imps) == 0 { | ||
return nil, errs | ||
} | ||
|
||
if ext.PubID == "" { | ||
return nil, append(errs, adapters.BadInput("Cannot infer publisher ID from bid ext")) | ||
} | ||
|
||
brq.Ext, err = json.Marshal(ext) | ||
if err != nil { | ||
return nil, append(errs, err) | ||
} | ||
|
||
brq.Imp = imps | ||
|
||
rq, err := json.Marshal(brq) | ||
if err != nil { | ||
return nil, append(errs, err) | ||
} | ||
|
||
url, err := s.buildEndpointURL(ext.PubID) | ||
if err != nil { | ||
return nil, append(errs, 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") | ||
return []*adapters.RequestData{{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: rq, | ||
Headers: headers, | ||
}}, errs | ||
} | ||
|
||
func (s *SmartRTBAdapter) MakeBids( | ||
brq *openrtb.BidRequest, drq *adapters.RequestData, | ||
rs *adapters.ResponseData, | ||
) (*adapters.BidderResponse, []error) { | ||
if rs.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} else if rs.StatusCode == http.StatusBadRequest { | ||
return nil, []error{adapters.BadInput("Invalid request.")} | ||
} else if rs.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Unexpected HTTP status %d.", rs.StatusCode), | ||
}} | ||
} | ||
|
||
var brs openrtb.BidResponse | ||
if err := json.Unmarshal(rs.Body, &brs); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
rv := adapters.NewBidderResponseWithBidsCapacity(5) | ||
for _, seat := range brs.SeatBid { | ||
for i := range seat.Bid { | ||
var ext bidExt | ||
if err := json.Unmarshal(seat.Bid[i].Ext, &ext); err != nil { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: "Invalid bid extension from endpoint.", | ||
}} | ||
} | ||
|
||
var btype openrtb_ext.BidType | ||
switch ext.CreativeType { | ||
case creativeTypeBanner: | ||
btype = openrtb_ext.BidTypeBanner | ||
case creativeTypeVideo: | ||
btype = openrtb_ext.BidTypeVideo | ||
default: | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Unsupported creative type %s.", | ||
ext.CreativeType), | ||
}} | ||
} | ||
|
||
seat.Bid[i].Ext = nil | ||
|
||
rv.Bids = append(rv.Bids, &adapters.TypedBid{ | ||
Bid: &seat.Bid[i], | ||
BidType: btype, | ||
}) | ||
} | ||
} | ||
return rv, nil | ||
} |
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,11 @@ | ||
package smartrtb | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
adapterstest.RunJSONBidderTest(t, "smartrtbtest", NewSmartRTBBidder("http://market-east.smrtb.com/json/publisher/rtb?pubid=test")) | ||
} |
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,134 @@ | ||
{ | ||
"mockBidRequest": { | ||
"id": "abc", | ||
"site": { | ||
"page": "prebid.org" | ||
}, | ||
"imp": [ | ||
{ | ||
"id": "imp123", | ||
"banner": { | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
} | ||
], | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"pub_id": "test", | ||
"zone_id": "N4zTDq3PPEHBIODv7cXK", | ||
"force_bid": true | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
|
||
"httpCalls": [ | ||
{ | ||
"expectedRequest": { | ||
"uri": "http://market-east.smrtb.com/json/publisher/rtb?pubid=test", | ||
"body":{ | ||
"id": "abc", | ||
"site": { | ||
"page": "prebid.org" | ||
}, | ||
"imp": [{ | ||
"id": "imp123", | ||
"tagid": "N4zTDq3PPEHBIODv7cXK", | ||
"banner": { | ||
"format": [{ | ||
"w": 300, | ||
"h": 250 | ||
}], | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"pub_id": "test", | ||
"zone_id": "N4zTDq3PPEHBIODv7cXK", | ||
"force_bid": true | ||
} | ||
} | ||
}], | ||
"ext": { | ||
"pub_id": "test" | ||
} | ||
} | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"id": "abc", | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"adm": "<b>hi</b>", | ||
"crid": "test_banner_crid", | ||
"cid": "test_cid", | ||
"impid": "imp123", | ||
"id": "1", | ||
"price": 0.01, | ||
"ext": { | ||
"format": "BANNER" | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"bid": [ | ||
{ | ||
"adm": "<VAST></VAST>", | ||
"crid": "test_video_crid", | ||
"cid": "test_cid", | ||
"impid": "imp123", | ||
"id": "2", | ||
"price": 0.01, | ||
"ext": { | ||
"format": "VIDEO" | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
], | ||
|
||
"expectedBidResponses": [ | ||
{ | ||
"currency": "USD", | ||
"bids": [ | ||
{ | ||
"bid": { | ||
"adm": "<b>hi</b>", | ||
"crid": "test_banner_crid", | ||
"cid": "test_cid", | ||
"impid": "imp123", | ||
"price": 0.01, | ||
"id": "1" | ||
}, | ||
"type": "banner" | ||
}, | ||
{ | ||
"bid": { | ||
"adm": "<VAST></VAST>", | ||
"crid": "test_video_crid", | ||
"cid": "test_cid", | ||
"impid": "imp123", | ||
"price": 0.01, | ||
"id": "2" | ||
}, | ||
"type": "video" | ||
} | ||
] | ||
} | ||
] | ||
} |
Oops, something went wrong.