Skip to content
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

Add caller info to 33across bid requests. #1656

Merged
merged 7 commits into from
Feb 11, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.bidder.ttx;
package org.prebid.server.bidder.thirtythreeacross;

import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
Expand All @@ -18,17 +19,19 @@
import org.prebid.server.bidder.model.HttpCall;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.bidder.ttx.proto.TtxImpExt;
import org.prebid.server.bidder.ttx.proto.TtxImpExtTtx;
import org.prebid.server.bidder.ttx.response.TtxBidExt;
import org.prebid.server.bidder.ttx.response.TtxBidExtTtx;
import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtx;
import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtxCaller;
import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExt;
import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExtTtx;
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.ttx.ExtImpTtx;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
import org.prebid.server.proto.openrtb.ext.request.thirtythreeacross.ExtImpThirtyThreeAcross;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.HttpUtil;
import org.prebid.server.util.ObjectUtil;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -39,16 +42,19 @@
import java.util.Objects;
import java.util.stream.Collectors;

public class TtxBidder implements Bidder<BidRequest> {
public class ThirtyThreeAcrossBidder implements Bidder<BidRequest> {

private static final TypeReference<ExtPrebid<?, ExtImpTtx>> TTX_EXT_TYPE_REFERENCE =
private static final TypeReference<ExtPrebid<?, ExtImpThirtyThreeAcross>> THIRTY_THREE_ACROSS_EXT_TYPE_REFERENCE =
new TypeReference<>() {
};
private static final ThirtyThreeAcrossExtTtxCaller PREBID_CALLER =
ThirtyThreeAcrossExtTtxCaller.of("Prebid-Server", "n/a");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I am the maintainer from 33Across. Can I request the caller name passed as Prebid-Server-Java to differentiate requests from the Go adapter we already have? Thanks.

private static final JsonPointer BID_MEDIA_TYPE_POINTER = JsonPointer.valueOf("/ttx/mediaType");

private final String endpointUrl;
private final JacksonMapper mapper;

public TtxBidder(String endpointUrl, JacksonMapper mapper) {
public ThirtyThreeAcrossBidder(String endpointUrl, JacksonMapper mapper) {
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.mapper = Objects.requireNonNull(mapper);
}
Expand All @@ -59,52 +65,88 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request
final Map<String, List<Imp>> impsMap = new HashMap<>();
final List<HttpRequest<BidRequest>> requests = new ArrayList<>();

for (Imp imp : request.getImp()) {
final BidRequest modifiedRequest = modifyRequest(request, errors);
for (Imp imp : modifiedRequest.getImp()) {
try {
validateImp(imp);
final ExtImpTtx extImpTtx = parseImpExt(imp);
final Imp updatedImp = updateImp(imp, extImpTtx);
final ExtImpThirtyThreeAcross extImpThirtyThreeAcross = parseImpExt(imp);
final Imp updatedImp = updateImp(imp, extImpThirtyThreeAcross);
impsMap.computeIfAbsent(computeKey(updatedImp), k -> new ArrayList<>()).add(updatedImp);
} catch (PreBidException e) {
errors.add(BidderError.badInput(e.getMessage()));
}
}

for (List<Imp> imps : impsMap.values()) {
requests.add(createRequest(request, imps));
requests.add(createRequest(modifiedRequest, imps));
}

return Result.of(requests, errors);
}

private BidRequest modifyRequest(BidRequest request, List<BidderError> errors) {
try {
return request.toBuilder().ext(modifyRequestExt(request.getExt())).build();
} catch (PreBidException e) {
errors.add(BidderError.badInput(e.getMessage()));
return request;
}
}

private ExtRequest modifyRequestExt(ExtRequest ext) throws PreBidException {
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
final Map<String, JsonNode> properties = ObjectUtil.getIfNotNull(ext, ExtRequest::getProperties);
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
final JsonNode extTtxNode = ObjectUtil.getIfNotNull(properties, p -> p.get("ttx"));
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
final ThirtyThreeAcrossExtTtx extTtx;
try {
extTtx = mapper.mapper().convertValue(extTtxNode, ThirtyThreeAcrossExtTtx.class);
} catch (IllegalArgumentException e) {
throw new PreBidException(e.getMessage());
}

final ExtRequest modifiedExt = ExtRequest.empty();
if (properties != null) {
modifiedExt.addProperties(properties);
}
modifiedExt.addProperty("ttx", mapper.mapper().valueToTree(modifyRequestExtTtx(extTtx)));

return modifiedExt;
}

private static ThirtyThreeAcrossExtTtx modifyRequestExtTtx(ThirtyThreeAcrossExtTtx extTtx) {
final List<ThirtyThreeAcrossExtTtxCaller> callers;
if (extTtx == null || CollectionUtils.isEmpty(extTtx.getCaller())) {
callers = Collections.singletonList(PREBID_CALLER);
} else {
callers = new ArrayList<>(extTtx.getCaller());
callers.add(PREBID_CALLER);
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
}

return ThirtyThreeAcrossExtTtx.of(callers);
}

private void validateImp(Imp imp) throws PreBidException {
if (imp.getBanner() == null && imp.getVideo() == null) {
throw new PreBidException(
String.format("Imp ID %s must have at least one of [Banner, Video] defined", imp.getId()));
}
}

private ExtImpTtx parseImpExt(Imp imp) throws PreBidException {
private ExtImpThirtyThreeAcross parseImpExt(Imp imp) throws PreBidException {
try {
return mapper.mapper().convertValue(imp.getExt(), TTX_EXT_TYPE_REFERENCE).getBidder();
return mapper.mapper().convertValue(imp.getExt(), THIRTY_THREE_ACROSS_EXT_TYPE_REFERENCE).getBidder();
} catch (IllegalArgumentException e) {
throw new PreBidException(e.getMessage());
}
}

private Imp updateImp(Imp imp, ExtImpTtx extImpTtx) throws PreBidException {
final String productId = extImpTtx.getProductId();
private Imp updateImp(Imp imp, ExtImpThirtyThreeAcross extImpThirtyThreeAcross) throws PreBidException {
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
final String productId = extImpThirtyThreeAcross.getProductId();
return imp.toBuilder()
.video(updatedVideo(imp.getVideo(), productId))
.ext(createImpExt(productId, extImpTtx.getZoneId(), extImpTtx.getSiteId()))
.ext(createImpExt(productId, extImpThirtyThreeAcross.getZoneId(), extImpThirtyThreeAcross.getSiteId()))
.build();
}

private String computeKey(Imp imp) {
final JsonNode ttx = imp.getExt().get("ttx");
return ttx.get("prod").asText() + ttx.get("zoneid").asText();
}

private static Video updatedVideo(Video video, String productId) throws PreBidException {
if (video == null) {
return null;
Expand All @@ -117,11 +159,10 @@ private static Video updatedVideo(Video video, String productId) throws PreBidEx
throw new PreBidException("One or more invalid or missing video field(s) "
+ "w, h, protocols, mimes, playbackmethod");
}
final Integer videoPlacement = video.getPlacement();

return video.toBuilder()
.startdelay(resolveStartDelay(video.getStartdelay(), productId))
.placement(resolvePlacement(videoPlacement, productId))
.placement(resolvePlacement(video.getPlacement(), productId))
.build();
}

Expand All @@ -144,9 +185,14 @@ private static Integer resolvePlacement(Integer videoPlacement, String productId
}

private ObjectNode createImpExt(String productId, String zoneId, String siteId) {
final TtxImpExt ttxImpExt = TtxImpExt.of(
TtxImpExtTtx.of(productId, StringUtils.isNotEmpty(zoneId) ? zoneId : siteId));
return mapper.mapper().valueToTree(ttxImpExt);
final ThirtyThreeAcrossImpExt thirtyThreeAcrossImpExt = ThirtyThreeAcrossImpExt.of(
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
ThirtyThreeAcrossImpExtTtx.of(productId, StringUtils.isNotEmpty(zoneId) ? zoneId : siteId));
return mapper.mapper().valueToTree(thirtyThreeAcrossImpExt);
}

private String computeKey(Imp imp) {
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
final JsonNode ttx = imp.getExt().get("ttx");
return ttx.get("prod").asText() + ttx.get("zoneid").asText();
}

private HttpRequest<BidRequest> createRequest(BidRequest request, List<Imp> requestImps) {
Expand All @@ -167,7 +213,7 @@ private HttpRequest<BidRequest> createRequest(BidRequest request, List<Imp> requ
public Result<List<BidderBid>> makeBids(HttpCall<BidRequest> httpCall, BidRequest bidRequest) {
try {
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
return Result.of(extractBids(bidResponse), Collections.emptyList());
return Result.withValues(extractBids(bidResponse));
} catch (DecodeException | PreBidException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}
Expand All @@ -177,32 +223,20 @@ private List<BidderBid> extractBids(BidResponse bidResponse) {
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
return Collections.emptyList();
}
return bidsFromResponse(bidResponse);
}

private List<BidderBid> bidsFromResponse(BidResponse bidResponse) {
return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(SeatBid::getBid)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur()))
.collect(Collectors.toList());
}

private BidType getBidType(Bid
bid) {
try {
final TtxBidExt ttxBidExt = mapper.mapper().convertValue(bid.getExt(), TtxBidExt.class);
return ttxBidExt != null ? getBidTypeByTtx(ttxBidExt.getTtx()) : BidType.banner;
} catch (IllegalArgumentException e) {
return BidType.banner;
}
}

private static BidType getBidTypeByTtx(TtxBidExtTtx bidExt) {
return bidExt != null && Objects.equals(bidExt.getMediaType(), "video")
? BidType.video
: BidType.banner;
private static BidType getBidType(Bid bid) {
final String mediaType = ObjectUtil.getIfNotNull(bid.getExt(),
ext -> ext.at(BID_MEDIA_TYPE_POINTER).asText(null));
return "video".equals(mediaType) ? BidType.video : BidType.banner;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.prebid.server.bidder.thirtythreeacross.proto;

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

import java.util.List;

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

@JsonInclude(JsonInclude.Include.NON_EMPTY)
List<ThirtyThreeAcrossExtTtxCaller> caller;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.prebid.server.bidder.thirtythreeacross.proto;

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

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

@JsonInclude(JsonInclude.Include.NON_EMPTY)
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
String name;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
String version;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.prebid.server.bidder.thirtythreeacross.proto;

import lombok.Value;

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

ThirtyThreeAcrossImpExtTtx ttx;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.prebid.server.bidder.thirtythreeacross.proto;

import lombok.Value;

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

String prod;

String zoneid;
}
11 changes: 0 additions & 11 deletions src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExt.java

This file was deleted.

13 changes: 0 additions & 13 deletions src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExtTtx.java

This file was deleted.

11 changes: 0 additions & 11 deletions src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExt.java

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.prebid.server.proto.openrtb.ext.request.ttx;
package org.prebid.server.proto.openrtb.ext.request.thirtythreeacross;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
Expand All @@ -9,7 +9,7 @@
*/
@AllArgsConstructor(staticName = "of")
@Value
public class ExtImpTtx {
public class ExtImpThirtyThreeAcross {

@JsonProperty("siteId")
String siteId;
Expand Down
Loading