diff --git a/Dockerfile b/Dockerfile index cbd9db98f79..c5db7326dd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11-jre-slim +FROM openjdk:17.0.2-oracle WORKDIR /app/prebid-server @@ -7,6 +7,7 @@ VOLUME /app/prebid-server/data COPY src/main/docker/run.sh ./ COPY src/main/docker/application.yaml ./ +COPY src/main/docker/app-settings.yaml ./ COPY target/prebid-server.jar ./ EXPOSE 8080 diff --git a/README.md b/README.md index 617fbe46527..fde71190442 100644 --- a/README.md +++ b/README.md @@ -117,3 +117,26 @@ and verify response status is `200 OK`. - [Code Style](docs/developers/code-style.md) - [Code Review](docs/developers/code-reviews.md) - [Versioning](docs/developers/versioning.md) + + +## Docker build + +- To build run +```bash +docker build -t infytv/infy:hb-latest . +``` + +- To push on docker hub run +```bash +docker push infytv/infy:hb-latest +``` +- To pull from docker hub run +```bash +docker pull infytv/infy:hb-latest +``` + +- To run +```bash +docker run -d -p 8080:8080 \ + infytv/infy:hb-latest +``` diff --git a/sample/prebid-config.yaml b/sample/prebid-config.yaml index fbfb0badbf4..c1b1bfb5d03 100644 --- a/sample/prebid-config.yaml +++ b/sample/prebid-config.yaml @@ -1,11 +1,13 @@ status-response: "ok" adapters: - rubicon: + infytv: enabled: true - XAPI.Username: user1 - XAPI.Password: password1 + modifying-vast-xml-allowed: true metrics: prefix: prebid + console: + enabled: false + interval: 300 cache: scheme: http host: localhost @@ -23,3 +25,8 @@ gdpr: vendorlist: v2: cache-dir: /var/tmp/vendor2 +analytics: + log: + enabled: true +auction: + default-timeout-ms: 1600 diff --git a/src/main/docker/app-settings.yaml b/src/main/docker/app-settings.yaml new file mode 100644 index 00000000000..5b3303a663c --- /dev/null +++ b/src/main/docker/app-settings.yaml @@ -0,0 +1,2 @@ +accounts: + - id: 1001 diff --git a/src/main/docker/application.yaml b/src/main/docker/application.yaml index 458f9b4d25e..c0fc6bf5fa6 100644 --- a/src/main/docker/application.yaml +++ b/src/main/docker/application.yaml @@ -1,4 +1,32 @@ +status-response: "ok" +adapters: + infytv: + enabled: true + modifying-vast-xml-allowed: true +metrics: + prefix: prebid + console: + enabled: false + interval: 300 +cache: + scheme: http + host: localhost + path: /cache + query: uuid= +settings: + filesystem: + settings-filename: app-settings.yaml + stored-requests-dir: + stored-imps-dir: + stored-responses-dir: + categories-dir: gdpr: + default-value: 1 vendorlist: v2: cache-dir: /app/prebid-server/data/vendorlist-v2 +analytics: + log: + enabled: true +auction: + default-timeout-ms: 1600 diff --git a/src/main/java/org/prebid/server/bidder/infytv/InfytvBidder.java b/src/main/java/org/prebid/server/bidder/infytv/InfytvBidder.java new file mode 100644 index 00000000000..2a1c6f80aa1 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/infytv/InfytvBidder.java @@ -0,0 +1,118 @@ +package org.prebid.server.bidder.infytv; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.vertx.core.http.HttpMethod; +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.BidderError; +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.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.infytv.ExtImpInfytv; +import org.prebid.server.proto.openrtb.ext.response.BidType; +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; +import java.util.stream.Collectors; + +public class InfytvBidder implements Bidder { + + final String endpointUrl; + private final JacksonMapper mapper; + + private static final TypeReference> INFYTV_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + + public InfytvBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final List> httpRequests = new ArrayList<>(); + for (Imp imp : request.getImp()) { + ExtImpInfytv infyVars = resolveImpExt(imp); + final BidRequest outgoingRequest = request.toBuilder().imp(Collections.singletonList(imp)).build(); + final String dspUrl = infyVars.getBase() + infyVars.getPath(); + httpRequests.add(HttpRequest.builder() + .method(HttpMethod.POST) + .uri(dspUrl) + .headers(HttpUtil.headers()) + .payload(outgoingRequest) + .body(mapper.encodeToBytes(outgoingRequest)) + .build()); + } + + return Result.withValues(httpRequests); + } + + @Override + public final Result> makeBids(HttpCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + return Result.withValues(extractBids(httpCall.getRequest().getPayload(), bidResponse)); + } catch (DecodeException | PreBidException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + private static List extractBids(BidRequest bidRequest, BidResponse bidResponse) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + return bidsFromResponse(bidRequest, bidResponse); + } + + private static List bidsFromResponse(BidRequest bidRequest, BidResponse bidResponse) { + return bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest.getImp()), bidResponse.getCur())) + .collect(Collectors.toList()); + } + + private static BidType getBidType(String impId, List imps) { + BidType bidType = BidType.banner; + for (Imp imp : imps) { + if (imp.getId().equals(impId)) { + if (imp.getBanner() != null) { + return bidType; + } else if (imp.getVideo() != null) { + bidType = BidType.video; + } else if (imp.getXNative() != null) { + bidType = BidType.xNative; + } else if (imp.getAudio() != null) { + bidType = BidType.audio; + } + } + } + return bidType; + } + + private ExtImpInfytv resolveImpExt(Imp imp) { + try { + return mapper.mapper() + .convertValue(imp.getExt(), INFYTV_EXT_TYPE_REFERENCE) + .getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage(), e); + } + } +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/infytv/ExtImpInfytv.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/infytv/ExtImpInfytv.java new file mode 100644 index 00000000000..3b3f685aae2 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/infytv/ExtImpInfytv.java @@ -0,0 +1,37 @@ +package org.prebid.server.proto.openrtb.ext.request.infytv; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Value; + +/** + * Defines the contract for bidrequest.imp[i].ext.{bidder} + */ +@AllArgsConstructor(staticName = "of") +@Value +public class ExtImpInfytv { + + @JsonProperty("dsp_id") + Integer dspId; + + @JsonProperty("customer_id") + Integer customerId; + + @JsonProperty("tag_id") + Integer tagId; + + @JsonProperty("base") + String base; + + @JsonProperty("path") + String path; + + @JsonProperty("dsp_type") + String dspType; + + @JsonProperty("min_cpm") + Double minCpm; + + @JsonProperty("max_cpm") + Double maxCpm; +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/InfytvConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/InfytvConfiguration.java new file mode 100644 index 00000000000..fc791ec8884 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/InfytvConfiguration.java @@ -0,0 +1,55 @@ +package org.prebid.server.spring.config.bidder; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.infytv.InfytvBidder; +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 javax.validation.constraints.NotBlank; +import java.util.Map; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/infytv.yaml", factory = YamlPropertySourceFactory.class) +public class InfytvConfiguration { + + private static final String BIDDER_NAME = "infytv"; + + @Bean("infytvConfigurationProperties") + @ConfigurationProperties("adapters.infytv") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps infytvBidderDeps(BidderConfigurationProperties infytvConfigurationProperties, + @NotBlank @Value("${external-url}") String externalUrl, + JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(infytvConfigurationProperties) + .usersyncerCreator(UsersyncerCreator.create(externalUrl)) + .bidderCreator(config -> new InfytvBidder(config.getEndpoint(), mapper)) + .assemble(); + } + + @Data + @EqualsAndHashCode(callSuper = true) + @NoArgsConstructor + private static class InfytvConfigurationProperties extends BidderConfigurationProperties { + + Integer platformId; + + Map iabCategories; + } +} diff --git a/src/main/resources/bidder-config/infytv.yaml b/src/main/resources/bidder-config/infytv.yaml new file mode 100644 index 00000000000..b53875db92a --- /dev/null +++ b/src/main/resources/bidder-config/infytv.yaml @@ -0,0 +1,114 @@ +adapters: + infytv: + endpoint: http://nxs.infy.tv/openrtb2/infytv + meta-info: + maintainer-email: tech+prebid@infy.tv + app-media-types: + - video + site-media-types: + - video + supported-vendors: + vendor-id: 0 + usersync: + url: https://ib.adnxs.com/getuid? + redirect-url: /setuid?bidder=adnxs&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&uid=$UID + cookie-family-name: infytv + type: redirect + support-cors: false + platform-id: 5 + iab-categories: + 1: IAB20-3 + 2: IAB18-5 + 3: IAB10-1 + 4: IAB2-3 + 5: IAB19-8 + 6: IAB22-1 + 7: IAB18-1 + 8: IAB12-3 + 9: IAB5-1 + 10: IAB4-5 + 11: IAB13-4 + 12: IAB8-7 + 13: IAB9-7 + 14: IAB7-1 + 15: IAB20-18 + 16: IAB10-7 + 17: IAB19-18 + 18: IAB13-6 + 19: IAB18-4 + 20: IAB1-5 + 21: IAB1-6 + 22: IAB3-4 + 23: IAB19-13 + 24: IAB22-2 + 25: IAB3-9 + 26: IAB17-18 + 27: IAB19-6 + 28: IAB1-7 + 29: IAB9-30 + 30: IAB20-7 + 31: IAB20-17 + 32: IAB7-32 + 33: IAB16-5 + 34: IAB19-34 + 35: IAB11-5 + 36: IAB12-3 + 37: IAB11-4 + 38: IAB12-3 + 39: IAB9-30 + 41: IAB7-44 + 42: IAB7-1 + 43: IAB7-30 + 50: IAB19-30 + 51: IAB17-12 + 52: IAB19-30 + 53: IAB3-1 + 55: IAB13-2 + 56: IAB19-30 + 57: IAB19-30 + 58: IAB7-39 + 59: IAB22-1 + 60: IAB7-39 + 61: IAB21-3 + 62: IAB5-1 + 63: IAB12-3 + 64: IAB20-18 + 65: IAB11-2 + 66: IAB17-18 + 67: IAB9-9 + 68: IAB9-5 + 69: IAB7-44 + 71: IAB22-3 + 73: IAB19-30 + 74: IAB8-5 + 78: IAB22-1 + 85: IAB12-2 + 86: IAB22-3 + 87: IAB11-3 + 112: IAB7-32 + 113: IAB7-32 + 114: IAB7-32 + 115: IAB7-32 + 118: IAB9-5 + 119: IAB9-5 + 120: IAB9-5 + 121: IAB9-5 + 122: IAB9-5 + 123: IAB9-5 + 124: IAB9-5 + 125: IAB9-5 + 126: IAB9-5 + 127: IAB22-1 + 132: IAB1-2 + 133: IAB19-30 + 137: IAB3-9 + 138: IAB19-3 + 140: IAB2-3 + 141: IAB2-1 + 142: IAB2-3 + 143: IAB17-13 + 166: IAB11-4 + 175: IAB3-1 + 176: IAB13-4 + 182: IAB8-9 + 183: IAB3-5 diff --git a/src/main/resources/static/bidder-params/infytv.json b/src/main/resources/static/bidder-params/infytv.json new file mode 100644 index 00000000000..9f2702ea0e9 --- /dev/null +++ b/src/main/resources/static/bidder-params/infytv.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "InfyTV Adapter Params", + "description": "A schema which validates params accepted by the InfyTV adapter", + "type": "object", + "properties": { + "dsp_id": { + "type": "string", + "description": "dsp_id" + }, + "customer_id": { + "type": "string", + "description": "customer_id" + } + }, + "required": ["dsp_id", "customer_id"] +}