Skip to content

Commit

Permalink
Adtonos: Add new adapter (#3446)
Browse files Browse the repository at this point in the history
  • Loading branch information
Compile-Ninja authored Sep 17, 2024
1 parent 8ecf1a4 commit 1afd0a1
Show file tree
Hide file tree
Showing 12 changed files with 671 additions and 0 deletions.
145 changes: 145 additions & 0 deletions src/main/java/org/prebid/server/bidder/adtonos/AdtonosBidder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package org.prebid.server.bidder.adtonos;

import com.fasterxml.jackson.core.type.TypeReference;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.response.Bid;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.bidder.Bidder;
import org.prebid.server.bidder.model.BidderBid;
import org.prebid.server.bidder.model.BidderCall;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.exception.PreBidException;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
import org.prebid.server.proto.openrtb.ext.request.adtonos.ExtImpAdtonos;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.BidderUtil;
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class AdtonosBidder implements Bidder<BidRequest> {

private static final TypeReference<ExtPrebid<?, ExtImpAdtonos>> ADTONOS_EXT_TYPE_REFERENCE =
new TypeReference<>() {
};
private static final String PUBLISHER_ID_MACRO = "{{PublisherId}}";

private final String endpointUrl;
private final JacksonMapper mapper;

public AdtonosBidder(String endpointUrl, JacksonMapper mapper) {
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.mapper = Objects.requireNonNull(mapper);
}

@Override
public final Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest bidRequest) {
try {
final ExtImpAdtonos impExt = parseImpExt(bidRequest.getImp().getFirst());
return Result.withValue(BidderUtil.defaultRequest(bidRequest, makeUrl(impExt), mapper));
} catch (PreBidException e) {
return Result.withError(BidderError.badInput(e.getMessage()));
}
}

private ExtImpAdtonos parseImpExt(Imp imp) {
try {
return mapper.mapper().convertValue(imp.getExt(), ADTONOS_EXT_TYPE_REFERENCE).getBidder();
} catch (IllegalArgumentException e) {
throw new PreBidException(
"Invalid imp.ext.bidder for impression index 0. Error Infomation: " + e.getMessage());
}
}

private String makeUrl(ExtImpAdtonos extImp) {
return endpointUrl.replace(PUBLISHER_ID_MACRO, extImp.getSupplierId());
}

@Override
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
final BidResponse bidResponse;
try {
bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
} catch (DecodeException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}

final List<BidderError> errors = new ArrayList<>();
final List<BidderBid> bids = extractBids(bidResponse, httpCall.getRequest().getPayload(), errors);

return Result.of(bids, errors);
}

private static List<BidderBid> extractBids(BidResponse bidResponse,
BidRequest bidRequest,
List<BidderError> errors) {

if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
return Collections.emptyList();
}

return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(SeatBid::getBid)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.map(bid -> makeBidderBid(bid, bidResponse.getCur(), bidRequest, errors))
.filter(Objects::nonNull)
.toList();
}

private static BidderBid makeBidderBid(Bid bid, String currency, BidRequest bidRequest, List<BidderError> errors) {
try {
return BidderBid.of(bid, resolveBidType(bid, bidRequest.getImp()), currency);
} catch (PreBidException e) {
errors.add(BidderError.badServerResponse(e.getMessage()));
return null;
}
}

private static BidType resolveBidType(Bid bid, List<Imp> imps) throws PreBidException {
final Integer markupType = bid.getMtype();
if (markupType != null) {
switch (markupType) {
case 1 -> {
return BidType.banner;
}
case 2 -> {
return BidType.video;
}
case 3 -> {
return BidType.audio;
}
case 4 -> {
return BidType.xNative;
}
}
}

final String impId = bid.getImpid();
for (Imp imp : imps) {
if (imp.getId().equals(impId)) {
if (imp.getAudio() != null) {
return BidType.audio;
} else if (imp.getVideo() != null) {
return BidType.video;
}
throw new PreBidException("Unsupported bidtype for bid: " + bid.getId());
}
}

throw new PreBidException("Failed to find impression: " + impId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.prebid.server.proto.openrtb.ext.request.adtonos;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Value;

@Value(staticConstructor = "of")
public class ExtImpAdtonos {

@JsonProperty("supplierId")
String supplierId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.prebid.server.spring.config.bidder;

import org.prebid.server.bidder.BidderDeps;
import org.prebid.server.bidder.adtonos.AdtonosBidder;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
import org.prebid.server.spring.env.YamlPropertySourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import jakarta.validation.constraints.NotBlank;

@Configuration
@PropertySource(value = "classpath:/bidder-config/adtonos.yaml", factory = YamlPropertySourceFactory.class)
public class AdtonosConfiguration {

private static final String BIDDER_NAME = "adtonos";

@Bean("adtonosConfigurationProperties")
@ConfigurationProperties("adapters.adtonos")
BidderConfigurationProperties configurationProperties() {
return new BidderConfigurationProperties();
}

@Bean
BidderDeps adtonosBidderDeps(BidderConfigurationProperties adtonosConfigurationProperties,
@NotBlank @Value("${external-url}") String externalUrl,
JacksonMapper mapper) {

return BidderDepsAssembler.forBidder(BIDDER_NAME)
.withConfig(adtonosConfigurationProperties)
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
.bidderCreator(config -> new AdtonosBidder(config.getEndpoint(), mapper))
.assemble();
}
}
22 changes: 22 additions & 0 deletions src/main/resources/bidder-config/adtonos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
adapters:
adtonos:
endpoint: https://exchange.adtonos.com/bid/{{PublisherId}}
geoscope:
- global
meta-info:
maintainer-email: support@adtonos.com
app-media-types:
- video
- audio
site-media-types:
- audio
dooh-media-types:
- audio
supported-vendors:
vendor-id: 682
usersync:
cookie-family-name: adtonos
redirect:
url: https://play.adtonos.com/redir?to={{redirect_url}}
support-cors: false
uid-macro: '@UUID@'
15 changes: 15 additions & 0 deletions src/main/resources/static/bidder-params/adtonos.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "AdTonos Adapter Params",
"description": "A schema which validates params accepted by the AdTonos adapter",
"type": "object",
"properties": {
"supplierId": {
"type": "string",
"description": "ID of the supplier account in AdTonos platform"
}
},
"required": [
"supplierId"
]
}
Loading

0 comments on commit 1afd0a1

Please sign in to comment.