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

Touchup add bid response #1822

Merged
merged 2 commits into from
Nov 16, 2017
Merged
Changes from all 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
283 changes: 141 additions & 142 deletions src/bidmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,176 +80,175 @@ exports.bidsBackAll = function () {
return bidsBackAll();
};

/*
* This function should be called to by the bidder adapter to register a bid response
*/
exports.addBidResponse = createHook('asyncSeries', function (adUnitCode, bid) {
if (isValid()) {
prepareBidForAuction();

if (bid.mediaType === 'video') {
tryAddVideoBid(bid);
} else {
addBidToAuction(bid);
doCallbacksIfNeeded();
}
// Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored.
function isValidBid(bid, adUnitCode) {
function errorMessage(msg) {
return `Invalid bid from ${bid.bidderCode}. Ignoring bid: ${msg}`;
}

// Actual method logic is above. Everything below is helper functions.

// Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored.
function isValid() {
function errorMessage(msg) {
return `Invalid bid from ${bid.bidderCode}. Ignoring bid: ${msg}`;
}
if (!bid) {
utils.logError(`Some adapter tried to add an undefined bid for ${adUnitCode}.`);
return false;
}
if (!adUnitCode) {
utils.logError(errorMessage('No adUnitCode was supplied to addBidResponse.'));
return false;
}

if (!bid) {
utils.logError(`Some adapter tried to add an undefined bid for ${adUnitCode}.`);
return false;
}
if (!adUnitCode) {
utils.logError(errorMessage('No adUnitCode was supplied to addBidResponse.'));
return false;
}
const bidRequest = getBidderRequest(bid.bidderCode, adUnitCode);
if (!bidRequest.start) {
utils.logError(errorMessage('Cannot find valid matching bid request.'));
return false;
}

const bidRequest = getBidderRequest(bid.bidderCode, adUnitCode);
if (!bidRequest.start) {
utils.logError(errorMessage('Cannot find valid matching bid request.'));
return false;
}
if (bid.mediaType === 'native' && !nativeBidIsValid(bid)) {
utils.logError(errorMessage('Native bid missing some required properties.'));
return false;
}
if (bid.mediaType === 'video' && !isValidVideoBid(bid)) {
utils.logError(errorMessage(`Video bid does not have required vastUrl or renderer property`));
return false;
}
if (bid.mediaType === 'banner' && !validBidSize(bid, adUnitCode)) {
utils.logError(errorMessage(`Banner bids require a width and height`));
return false;
}

if (bid.mediaType === 'native' && !nativeBidIsValid(bid)) {
utils.logError(errorMessage('Native bid missing some required properties.'));
return false;
}
if (bid.mediaType === 'video' && !isValidVideoBid(bid)) {
utils.logError(errorMessage(`Video bid does not have required vastUrl or renderer property`));
return false;
}
if (bid.mediaType === 'banner' && !validBidSize(bid)) {
utils.logError(errorMessage(`Banner bids require a width and height`));
return false;
}
return true;
}

// check that the bid has a width and height set
function validBidSize(bid, adUnitCode) {
if ((bid.width || bid.width === 0) && (bid.height || bid.height === 0)) {
return true;
}

// check that the bid has a width and height set
function validBidSize(bid) {
if ((bid.width || bid.width === 0) && (bid.height || bid.height === 0)) {
return true;
}

const adUnit = getBidderRequest(bid.bidderCode, adUnitCode);
const sizes = adUnit && adUnit.bids && adUnit.bids[0] && adUnit.bids[0].sizes;
const parsedSizes = utils.parseSizesInput(sizes);

// if a banner impression has one valid size, we assign that size to any bid
// response that does not explicitly set width or height
if (parsedSizes.length === 1) {
const [ width, height ] = parsedSizes[0].split('x');
bid.width = width;
bid.height = height;
return true;
}
const adUnit = getBidderRequest(bid.bidderCode, adUnitCode);
const sizes = adUnit && adUnit.bids && adUnit.bids[0] && adUnit.bids[0].sizes;
const parsedSizes = utils.parseSizesInput(sizes);

return false;
// if a banner impression has one valid size, we assign that size to any bid
// response that does not explicitly set width or height
if (parsedSizes.length === 1) {
const [ width, height ] = parsedSizes[0].split('x');
bid.width = width;
bid.height = height;
return true;
}

// Postprocess the bids so that all the universal properties exist, no matter which bidder they came from.
// This should be called before addBidToAuction().
function prepareBidForAuction() {
const bidRequest = getBidderRequest(bid.bidderCode, adUnitCode);

Object.assign(bid, {
requestId: bidRequest.requestId,
responseTimestamp: timestamp(),
requestTimestamp: bidRequest.start,
cpm: parseFloat(bid.cpm) || 0,
bidder: bid.bidderCode,
adUnitCode
});
return false;
}

bid.timeToRespond = bid.responseTimestamp - bid.requestTimestamp;
// Postprocess the bids so that all the universal properties exist, no matter which bidder they came from.
// This should be called before addBidToAuction().
function prepareBidForAuction(bid, adUnitCode) {
const bidRequest = getBidderRequest(bid.bidderCode, adUnitCode);

Object.assign(bid, {
requestId: bidRequest.requestId,
responseTimestamp: timestamp(),
requestTimestamp: bidRequest.start,
cpm: parseFloat(bid.cpm) || 0,
bidder: bid.bidderCode,
adUnitCode
});

// Let listeners know that now is the time to adjust the bid, if they want to.
//
// CAREFUL: Publishers rely on certain bid properties to be available (like cpm),
// but others to not be set yet (like priceStrings). See #1372 and #1389.
events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid);
bid.timeToRespond = bid.responseTimestamp - bid.requestTimestamp;

// a publisher-defined renderer can be used to render bids
const adUnitRenderer =
bidRequest.bids && bidRequest.bids[0] && bidRequest.bids[0].renderer;
// Let listeners know that now is the time to adjust the bid, if they want to.
//
// CAREFUL: Publishers rely on certain bid properties to be available (like cpm),
// but others to not be set yet (like priceStrings). See #1372 and #1389.
events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid);

if (adUnitRenderer) {
bid.renderer = Renderer.install({ url: adUnitRenderer.url });
bid.renderer.setRender(adUnitRenderer.render);
}
// a publisher-defined renderer can be used to render bids
const adUnitRenderer =
bidRequest.bids && bidRequest.bids[0] && bidRequest.bids[0].renderer;

const priceStringsObj = getPriceBucketString(
bid.cpm,
config.getConfig('customPriceBucket'),
config.getConfig('currency.granularityMultiplier')
);
bid.pbLg = priceStringsObj.low;
bid.pbMg = priceStringsObj.med;
bid.pbHg = priceStringsObj.high;
bid.pbAg = priceStringsObj.auto;
bid.pbDg = priceStringsObj.dense;
bid.pbCg = priceStringsObj.custom;

// if there is any key value pairs to map do here
var keyValues;
if (bid.bidderCode && (bid.cpm > 0 || bid.dealId)) {
keyValues = getKeyValueTargetingPairs(bid.bidderCode, bid);
}
if (adUnitRenderer) {
bid.renderer = Renderer.install({ url: adUnitRenderer.url });
bid.renderer.setRender(adUnitRenderer.render);
}

// use any targeting provided as defaults, otherwise just set from getKeyValueTargetingPairs
bid.adserverTargeting = Object.assign(bid.adserverTargeting || {}, keyValues);
const priceStringsObj = getPriceBucketString(
bid.cpm,
config.getConfig('customPriceBucket'),
config.getConfig('currency.granularityMultiplier')
);
bid.pbLg = priceStringsObj.low;
bid.pbMg = priceStringsObj.med;
bid.pbHg = priceStringsObj.high;
bid.pbAg = priceStringsObj.auto;
bid.pbDg = priceStringsObj.dense;
bid.pbCg = priceStringsObj.custom;

// if there is any key value pairs to map do here
var keyValues;
if (bid.bidderCode && (bid.cpm > 0 || bid.dealId)) {
keyValues = getKeyValueTargetingPairs(bid.bidderCode, bid);
}

function doCallbacksIfNeeded() {
if (bid.timeToRespond > $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer) {
const timedOut = true;
exports.executeCallback(timedOut);
}
// use any targeting provided as defaults, otherwise just set from getKeyValueTargetingPairs
bid.adserverTargeting = Object.assign(bid.adserverTargeting || {}, keyValues);
}

function doCallbacksIfNeeded(bid) {
if (bid.timeToRespond > $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer) {
const timedOut = true;
exports.executeCallback(timedOut);
}
}

// Add a bid to the auction.
function addBidToAuction() {
events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bid);
// Add a bid to the auction.
function addBidToAuction(bid) {
events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bid);

$$PREBID_GLOBAL$$._bidsReceived.push(bid);
$$PREBID_GLOBAL$$._bidsReceived.push(bid);

if (bid.adUnitCode && bidsBackAdUnit(bid.adUnitCode)) {
triggerAdUnitCallbacks(bid.adUnitCode);
}
if (bid.adUnitCode && bidsBackAdUnit(bid.adUnitCode)) {
triggerAdUnitCallbacks(bid.adUnitCode);
}

if (bidsBackAll()) {
exports.executeCallback();
}
if (bidsBackAll()) {
exports.executeCallback();
}
}

// Video bids may fail if the cache is down, or there's trouble on the network.
function tryAddVideoBid(bid) {
if (config.getConfig('usePrebidCache')) {
store([bid], function(error, cacheIds) {
if (error) {
utils.logWarn(`Failed to save to the video cache: ${error}. Video bid must be discarded.`);
} else {
bid.videoCacheKey = cacheIds[0].uuid;
if (!bid.vastUrl) {
bid.vastUrl = getCacheUrl(bid.videoCacheKey);
}
addBidToAuction(bid);
// Video bids may fail if the cache is down, or there's trouble on the network.
function tryAddVideoBid(bid) {
if (config.getConfig('usePrebidCache')) {
store([bid], function(error, cacheIds) {
if (error) {
utils.logWarn(`Failed to save to the video cache: ${error}. Video bid must be discarded.`);
} else {
bid.videoCacheKey = cacheIds[0].uuid;
if (!bid.vastUrl) {
bid.vastUrl = getCacheUrl(bid.videoCacheKey);
}
doCallbacksIfNeeded();
});
} else {
addBidToAuction(bid);
doCallbacksIfNeeded();
}
addBidToAuction(bid);
}
doCallbacksIfNeeded(bid);
});
} else {
addBidToAuction(bid);
doCallbacksIfNeeded(bid);
}
}

/*
* This function should be called to by the bidder adapter to register a bid response
*/
exports.addBidResponse = createHook('asyncSeries', function (adUnitCode, bid) {
if (!isValidBid(bid, adUnitCode)) {
return;
}
prepareBidForAuction(bid, adUnitCode);

if (bid.mediaType === 'video') {
tryAddVideoBid(bid);
} else {
addBidToAuction(bid);
doCallbacksIfNeeded(bid);
}
});

Expand Down