-
Notifications
You must be signed in to change notification settings - Fork 735
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding Smartadserver adapter (#1346)
Co-authored-by: tadam <tadam@smartadserver.com>
- Loading branch information
Showing
27 changed files
with
1,198 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,61 @@ | ||
package smartadserver | ||
|
||
import ( | ||
"encoding/json" | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
// This file actually intends to test static/bidder-params/smartadserver.json | ||
// | ||
// These also validate the format of the external API: request.imp[i].ext.smartadserver | ||
|
||
// TestValidParams makes sure that the smartadserver schema accepts all imp.ext fields which we intend to support. | ||
func TestValidParams(t *testing.T) { | ||
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") | ||
if err != nil { | ||
t.Fatalf("Failed to fetch the json-schemas. %v", err) | ||
} | ||
|
||
for _, validParam := range validParams { | ||
if err := validator.Validate(openrtb_ext.BidderSmartadserver, json.RawMessage(validParam)); err != nil { | ||
t.Errorf("Schema rejected smartadserver params: %s \n Error: %s", validParam, err) | ||
} | ||
} | ||
} | ||
|
||
// TestInvalidParams makes sure that the smartadserver schema rejects all the imp.ext fields we don't support. | ||
func TestInvalidParams(t *testing.T) { | ||
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") | ||
if err != nil { | ||
t.Fatalf("Failed to fetch the json-schemas. %v", err) | ||
} | ||
|
||
for _, invalidParam := range invalidParams { | ||
if err := validator.Validate(openrtb_ext.BidderSmartadserver, json.RawMessage(invalidParam)); err == nil { | ||
t.Errorf("Schema allowed unexpected params: %s", invalidParam) | ||
} | ||
} | ||
} | ||
|
||
var validParams = []string{ | ||
`{"networkId":73}`, | ||
`{"networkId":73,"siteId":1,"pageId":2,"formatId":3}`, | ||
} | ||
|
||
var invalidParams = []string{ | ||
``, | ||
`null`, | ||
`true`, | ||
`5`, | ||
`4.2`, | ||
`[]`, | ||
`{}`, | ||
`{"networkId":"73"}`, | ||
`{"networkId":"73","siteId":"1","pageId":"2","formatId":"3"}`, | ||
`{"siteId":1,"pageId":2,"formatId":3}`, | ||
`{"networkId":73,"pageId":2,"formatId":3}`, | ||
`{"networkId":73,"siteId":1,"formatId":3}`, | ||
`{"networkId":73,"siteId":1,"pageId":2}`, | ||
} |
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,179 @@ | ||
package smartadserver | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"path" | ||
"strconv" | ||
|
||
"github.com/mxmCherry/openrtb" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
type SmartAdserverAdapter struct { | ||
host string | ||
} | ||
|
||
func NewSmartadserverBidder(host string) *SmartAdserverAdapter { | ||
return &SmartAdserverAdapter{ | ||
host: host, | ||
} | ||
} | ||
|
||
// MakeRequests makes the HTTP requests which should be made to fetch bids. | ||
func (a *SmartAdserverAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
if len(request.Imp) == 0 { | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: "No impression in the bid request", | ||
}} | ||
} | ||
|
||
var adapterRequests []*adapters.RequestData | ||
var errs []error | ||
|
||
// We copy the original request. | ||
smartRequest := *request | ||
|
||
// We create or copy the Site object. | ||
if smartRequest.Site == nil { | ||
smartRequest.Site = &openrtb.Site{} | ||
} else { | ||
site := *smartRequest.Site | ||
smartRequest.Site = &site | ||
} | ||
|
||
// We create or copy the Publisher object. | ||
if smartRequest.Site.Publisher == nil { | ||
smartRequest.Site.Publisher = &openrtb.Publisher{} | ||
} else { | ||
publisher := *smartRequest.Site.Publisher | ||
smartRequest.Site.Publisher = &publisher | ||
} | ||
|
||
// We send one serialized "smartRequest" per impression of the original request. | ||
for _, imp := range request.Imp { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
errs = append(errs, &errortypes.BadInput{ | ||
Message: "Error parsing bidderExt object", | ||
}) | ||
continue | ||
} | ||
|
||
var smartadserverExt openrtb_ext.ExtImpSmartadserver | ||
if err := json.Unmarshal(bidderExt.Bidder, &smartadserverExt); err != nil { | ||
errs = append(errs, &errortypes.BadInput{ | ||
Message: "Error parsing smartadserverExt parameters", | ||
}) | ||
continue | ||
} | ||
|
||
// Adding publisher id. | ||
smartRequest.Site.Publisher.ID = strconv.Itoa(smartadserverExt.NetworkID) | ||
|
||
// We send one request for each impression. | ||
smartRequest.Imp = []openrtb.Imp{imp} | ||
|
||
var errMarshal error | ||
if imp.Ext, errMarshal = json.Marshal(smartadserverExt); errMarshal != nil { | ||
errs = append(errs, &errortypes.BadInput{ | ||
Message: errMarshal.Error(), | ||
}) | ||
continue | ||
} | ||
|
||
reqJSON, err := json.Marshal(smartRequest) | ||
if err != nil { | ||
errs = append(errs, &errortypes.BadInput{ | ||
Message: "Error parsing reqJSON object", | ||
}) | ||
continue | ||
} | ||
|
||
url, err := a.BuildEndpointURL(&smartadserverExt) | ||
if url == "" { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
headers.Add("Accept", "application/json") | ||
adapterRequests = append(adapterRequests, &adapters.RequestData{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: reqJSON, | ||
Headers: headers, | ||
}) | ||
} | ||
return adapterRequests, errs | ||
} | ||
|
||
// MakeBids unpacks the server's response into Bids. | ||
func (a *SmartAdserverAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
if response.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} | ||
|
||
if response.StatusCode == http.StatusBadRequest { | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), | ||
}} | ||
} | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: "Unexpected status code: " + strconv.Itoa(response.StatusCode) + ". Run with request.debug = 1 for more info", | ||
}} | ||
} | ||
|
||
var bidResp openrtb.BidResponse | ||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) | ||
|
||
for _, sb := range bidResp.SeatBid { | ||
for i := 0; i < len(sb.Bid); i++ { | ||
bid := sb.Bid[i] | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &bid, | ||
BidType: getMediaTypeForImp(bid.ImpID, internalRequest.Imp), | ||
}) | ||
|
||
} | ||
} | ||
return bidResponse, []error{} | ||
} | ||
|
||
// BuildEndpointURL : Builds endpoint url | ||
func (a *SmartAdserverAdapter) BuildEndpointURL(params *openrtb_ext.ExtImpSmartadserver) (string, error) { | ||
uri, err := url.Parse(a.host) | ||
if err != nil || uri.Scheme == "" || uri.Host == "" { | ||
return "", &errortypes.BadInput{ | ||
Message: "Malformed URL: " + a.host + ".", | ||
} | ||
} | ||
|
||
uri.Path = path.Join(uri.Path, "api/bid") | ||
uri.RawQuery = "callerId=5" | ||
|
||
return uri.String(), nil | ||
} | ||
|
||
func getMediaTypeForImp(impID string, imps []openrtb.Imp) openrtb_ext.BidType { | ||
for _, imp := range imps { | ||
if imp.ID == impID { | ||
if imp.Video != nil { | ||
return openrtb_ext.BidTypeVideo | ||
} | ||
return openrtb_ext.BidTypeBanner | ||
} | ||
} | ||
return openrtb_ext.BidTypeBanner | ||
} |
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 smartadserver | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
adapterstest.RunJSONBidderTest(t, "smartadservertest", NewSmartadserverBidder("https://ssb.smartadserver.com")) | ||
} |
Oops, something went wrong.