forked from prebid/prebid-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Adapter: TrafficGate (prebid#2226)
Co-authored-by: vlad <vlaktionov@decenterads.com>
- Loading branch information
Showing
24 changed files
with
1,739 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,48 @@ | ||
package trafficgate | ||
|
||
import ( | ||
"encoding/json" | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
// TestValidParams makes sure that the trafficgate 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.BidderTrafficGate, json.RawMessage(validParam)); err != nil { | ||
t.Errorf("Schema rejected trafficgate params: %s", validParam) | ||
} | ||
} | ||
} | ||
|
||
// TestInvalidParams makes sure that the trafficgate 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.BidderTrafficGate, json.RawMessage(invalidParam)); err == nil { | ||
t.Errorf("Schema allowed unexpected params: %s", invalidParam) | ||
} | ||
} | ||
} | ||
|
||
var validParams = []string{ | ||
`{"placementId": "11", "host": "example"}`, | ||
} | ||
|
||
var invalidParams = []string{ | ||
`{"id": "456"}`, | ||
`{"placementid": "3456", "host": ""}`, | ||
`{"placement_id": 346, "host": ""}`, | ||
`{"placementID": "", "HOST": "example"}`, | ||
`{"placementId": 234}`, | ||
} |
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,181 @@ | ||
package trafficgate | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"text/template" | ||
|
||
"github.com/mxmCherry/openrtb/v15/openrtb2" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/config" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/macros" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
) | ||
|
||
type adapter struct { | ||
EndpointTemplate *template.Template | ||
} | ||
|
||
type BidResponseExt struct { | ||
Prebid struct { | ||
Type string | ||
} | ||
} | ||
|
||
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
|
||
headers := http.Header{ | ||
"Content-Type": {"application/json"}, | ||
"Accept": {"application/json"}, | ||
} | ||
|
||
// Pull the host and source ID info from the bidder params. | ||
reqImps, err := splitImpressions(request.Imp) | ||
if err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
requests := []*adapters.RequestData{} | ||
|
||
var errs []error | ||
for reqExt, reqImp := range reqImps { | ||
request.Imp = reqImp | ||
reqJson, err := json.Marshal(request) | ||
|
||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
urlParams := macros.EndpointTemplateParams{Host: reqExt.Host} | ||
url, err := macros.ResolveMacros(a.EndpointTemplate, urlParams) | ||
|
||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
request := adapters.RequestData{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: reqJson, | ||
Headers: headers} | ||
|
||
requests = append(requests, &request) | ||
} | ||
|
||
return requests, errs | ||
} | ||
|
||
/* | ||
internal original request in OpenRTB, external = result of us having converted it (what comes out of MakeRequests) | ||
*/ | ||
func (a *adapter) MakeBids( | ||
internalRequest *openrtb2.BidRequest, | ||
externalRequest *adapters.RequestData, | ||
response *adapters.ResponseData, | ||
) (*adapters.BidderResponse, []error) { | ||
|
||
if response.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Error response with status %d", response.StatusCode), | ||
}} | ||
} | ||
|
||
var bidResp openrtb2.BidResponse | ||
|
||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: err.Error(), | ||
}} | ||
} | ||
|
||
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp)) | ||
bidResponse.Currency = bidResp.Cur | ||
|
||
for _, seatBid := range bidResp.SeatBid { | ||
for i := range seatBid.Bid { | ||
var bidExt BidResponseExt | ||
if err := json.Unmarshal(seatBid.Bid[i].Ext, &bidExt); err != nil { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Missing response ext"), | ||
}} | ||
} | ||
if len(bidExt.Prebid.Type) < 1 { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Unable to read bid.ext.prebid.type"), | ||
}} | ||
} | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &seatBid.Bid[i], | ||
BidType: getMediaTypeForImp(bidExt.Prebid.Type), | ||
}) | ||
} | ||
} | ||
|
||
return bidResponse, nil | ||
} | ||
|
||
func splitImpressions(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp, error) { | ||
|
||
var multipleImps = make(map[openrtb_ext.ExtImpTrafficGate][]openrtb2.Imp) | ||
|
||
for _, imp := range imps { | ||
bidderParams, err := getBidderParams(&imp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
multipleImps[*bidderParams] = append(multipleImps[*bidderParams], imp) | ||
} | ||
|
||
return multipleImps, nil | ||
} | ||
|
||
func getBidderParams(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTrafficGate, error) { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Missing bidder ext"), | ||
} | ||
} | ||
var TrafficGateExt openrtb_ext.ExtImpTrafficGate | ||
if err := json.Unmarshal(bidderExt.Bidder, &TrafficGateExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Bidder parameters required"), | ||
} | ||
} | ||
|
||
return &TrafficGateExt, nil | ||
} | ||
|
||
func getMediaTypeForImp(bidType string) openrtb_ext.BidType { | ||
switch bidType { | ||
case "video": | ||
return openrtb_ext.BidTypeVideo | ||
case "native": | ||
return openrtb_ext.BidTypeNative | ||
case "audio": | ||
return openrtb_ext.BidTypeAudio | ||
} | ||
return openrtb_ext.BidTypeBanner | ||
} | ||
|
||
// Builder builds a new instance of the TrafficGate adapter for the given bidder with the given config. | ||
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { | ||
template, err := template.New("endpointTemplate").Parse(config.Endpoint) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) | ||
} | ||
|
||
bidder := &adapter{ | ||
EndpointTemplate: template, | ||
} | ||
return bidder, 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,28 @@ | ||
package trafficgate | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
"github.com/prebid/prebid-server/config" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
bidder, buildErr := Builder(openrtb_ext.BidderTrafficGate, config.Adapter{ | ||
Endpoint: "http://{{.Host}}.bc-plugin.com/?c=o&m=rtb"}) | ||
|
||
if buildErr != nil { | ||
t.Fatalf("Builder returned unexpected error %v", buildErr) | ||
} | ||
|
||
adapterstest.RunJSONBidderTest(t, "trafficgatetest", bidder) | ||
} | ||
|
||
func TestEndpointTemplateMalformed(t *testing.T) { | ||
_, buildErr := Builder(openrtb_ext.BidderTrafficGate, config.Adapter{ | ||
Endpoint: "{{Malformed}}"}) | ||
|
||
assert.Error(t, buildErr) | ||
} |
Oops, something went wrong.