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

new NO_BID event and "no bids" available from auction #3286

Merged
merged 1 commit into from
Dec 17, 2018
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions src/AnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
BID_REQUESTED,
BID_TIMEOUT,
BID_RESPONSE,
NO_BID,
BID_WON,
BID_ADJUSTMENT,
BIDDER_DONE,
Expand Down Expand Up @@ -100,6 +101,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler }
_handlers = {
[BID_REQUESTED]: args => this.enqueue({ eventType: BID_REQUESTED, args }),
[BID_RESPONSE]: args => this.enqueue({ eventType: BID_RESPONSE, args }),
[NO_BID]: args => this.enqueue({ eventType: NO_BID, args }),
[BID_TIMEOUT]: args => this.enqueue({ eventType: BID_TIMEOUT, args }),
[BID_WON]: args => this.enqueue({ eventType: BID_WON, args }),
[BID_ADJUSTMENT]: args => this.enqueue({ eventType: BID_ADJUSTMENT, args }),
Expand Down
14 changes: 9 additions & 5 deletions src/adaptermanager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @module adaptermanger */

import { flatten, getBidderCodes, getDefinedParams, shuffle, timestamp } from './utils';
import { flatten, getBidderCodes, getDefinedParams, shuffle, timestamp, getBidderRequest } from './utils';
import { getLabels, resolveStatus } from './sizeMapping';
import { processNativeAdUnitParams, nativeAdapters } from './native';
import { newBidder } from './adapters/bidderFactory';
Expand Down Expand Up @@ -340,7 +340,7 @@ exports.callBids = (adUnits, bidRequests, addBidResponse, doneCb, requestCallbac
if (s2sBidRequest.ad_units.length) {
let doneCbs = serverBidRequests.map(bidRequest => {
bidRequest.start = timestamp();
return doneCb;
return doneCb.bind(bidRequest);
});

// only log adapters that actually have adUnit bids
Expand All @@ -360,7 +360,12 @@ exports.callBids = (adUnits, bidRequests, addBidResponse, doneCb, requestCallbac
s2sAdapter.callBids(
s2sBidRequest,
serverBidRequests,
addBidResponse,
function(adUnitCode, bid) {
let bidderRequest = getBidderRequest(serverBidRequests, bid.bidderCode, adUnitCode);
if (bidderRequest) {
addBidResponse.call(bidderRequest, adUnitCode, bid)
}
},
() => doneCbs.forEach(done => done()),
s2sAjax
);
Expand All @@ -375,12 +380,11 @@ exports.callBids = (adUnits, bidRequests, addBidResponse, doneCb, requestCallbac
const adapter = _bidderRegistry[bidRequest.bidderCode];
utils.logMessage(`CALLING BIDDER ======= ${bidRequest.bidderCode}`);
events.emit(CONSTANTS.EVENTS.BID_REQUESTED, bidRequest);
bidRequest.doneCbCallCount = 0;
let ajax = ajaxBuilder(requestBidsTimeout, requestCallbacks ? {
request: requestCallbacks.request.bind(null, bidRequest.bidderCode),
done: requestCallbacks.done
} : undefined);
adapter.callBids(bidRequest, addBidResponse, doneCb, ajax);
adapter.callBids(bidRequest, addBidResponse.bind(bidRequest), doneCb.bind(bidRequest), ajax);
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export function newBidder(spec) {
// After all the responses have come back, call done() and
// register any required usersync pixels.
const responses = [];
function afterAllResponses(bids) {
function afterAllResponses() {
done();
events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest);
registerSyncs(responses, bidderRequest.gdprConsent);
Expand Down
57 changes: 38 additions & 19 deletions src/auction.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
* @property {function(): void} callBids - sends requests to all adapters for bids
*/

import { uniques, flatten, timestamp, adUnitsFilter, getBidderRequest, deepAccess, delayExecution, getBidRequest } from './utils';
import { uniques, flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest } from './utils';
import { getPriceBucketString } from './cpmBucketManager';
import { getNativeTargeting } from './native';
import { getCacheUrl, store } from './videoCache';
Expand Down Expand Up @@ -95,6 +95,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
let _adUnitCodes = adUnitCodes;
let _bidderRequests = [];
let _bidsReceived = [];
let _noBids = [];
let _auctionStart;
let _auctionEnd;
let _auctionId = utils.generateUUID();
Expand All @@ -106,6 +107,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})

function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests) };
function addBidReceived(bidsReceived) { _bidsReceived = _bidsReceived.concat(bidsReceived); }
function addNoBid(noBid) { _noBids = _noBids.concat(noBid); }

function getProperties() {
return {
Expand All @@ -117,6 +119,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
adUnitCodes: _adUnitCodes,
labels: _labels,
bidderRequests: _bidderRequests,
noBids: _noBids,
bidsReceived: _bidsReceived,
winningBids: _winningBids,
timeout: _timeout
Expand Down Expand Up @@ -175,7 +178,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
}
}

function auctionDone(bidderCount) {
function auctionDone() {
// when all bidders have called done callback atleast once it means auction is complete
utils.logInfo(`Bids Received for Auction with id: ${_auctionId}`, _bidsReceived);
_auctionStatus = AUCTION_COMPLETED;
Expand Down Expand Up @@ -208,10 +211,12 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
events.emit(CONSTANTS.EVENTS.AUCTION_INIT, getProperties());

let callbacks = auctionCallbacks(auctionDone, this);
let boundObj = {
auctionAddBidResponse: callbacks.addBidResponse
};
adaptermanager.callBids(_adUnits, bidRequests, addBidResponse.bind(boundObj), callbacks.adapterDone, {
adaptermanager.callBids(_adUnits, bidRequests, function(...args) {
addBidResponse.apply({
dispatch: callbacks.addBidResponse,
bidderRequest: this
}, args)
}, callbacks.adapterDone, {
request(source, origin) {
increment(outstandingRequests, origin);
increment(requests, source);
Expand Down Expand Up @@ -296,6 +301,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})

return {
addBidReceived,
addNoBid,
executeCallback,
callBids,
addWinningBid,
Expand All @@ -308,20 +314,19 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
getAdUnitCodes: () => _adUnitCodes,
getBidRequests: () => _bidderRequests,
getBidsReceived: () => _bidsReceived,
getNoBids: () => _noBids
}
}

export const addBidResponse = createHook('asyncSeries', function(adUnitCode, bid) {
this.auctionAddBidResponse(adUnitCode, bid);
this.dispatch.call(this.bidderRequest, adUnitCode, bid);
}, 'addBidResponse');

export function auctionCallbacks(auctionDone, auctionInstance) {
let outstandingBidsAdded = 0;
let allAdapterCalledDone = false;

let onAllAdapterDone = delayExecution(() => {
allAdapterCalledDone = true;
}, auctionInstance.getBidRequests().length);
let bidderRequestsDone = new Set();
let bidResponseMap = {};

function afterBidAdded() {
outstandingBidsAdded--;
Expand All @@ -331,23 +336,37 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
}

function addBidResponse(adUnitCode, bid) {
let bidderRequest = this;

bidResponseMap[bid.requestId] = true;

outstandingBidsAdded++;
let bidRequests = auctionInstance.getBidRequests();
let auctionId = auctionInstance.getAuctionId();

let bidRequest = getBidderRequest(bidRequests, bid.bidderCode, adUnitCode);
let bidResponse = getPreparedBidForAuction({adUnitCode, bid, bidRequest, auctionId});
let bidResponse = getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId});

if (bidResponse.mediaType === 'video') {
tryAddVideoBid(auctionInstance, bidResponse, bidRequest, afterBidAdded);
tryAddVideoBid(auctionInstance, bidResponse, bidderRequest, afterBidAdded);
} else {
addBidToAuction(auctionInstance, bidResponse);
afterBidAdded();
}
}

function adapterDone() {
onAllAdapterDone();
let bidderRequest = this;

bidderRequestsDone.add(bidderRequest);
allAdapterCalledDone = auctionInstance.getBidRequests()
.every(bidderRequest => bidderRequestsDone.has(bidderRequest));

bidderRequest.bids.forEach(bid => {
if (!bidResponseMap[bid.bidId]) {
auctionInstance.addNoBid(bid);
events.emit(CONSTANTS.EVENTS.NO_BID, bid);
}
});

if (allAdapterCalledDone && outstandingBidsAdded === 0) {
auctionDone();
}
Expand Down Expand Up @@ -412,8 +431,8 @@ function tryAddVideoBid(auctionInstance, bidResponse, bidRequests, afterBidAdded

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

let bidObject = Object.assign({}, bid, {
auctionId,
Expand All @@ -433,7 +452,7 @@ function getPreparedBidForAuction({adUnitCode, bid, bidRequest, auctionId}) {
events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bidObject);

// a publisher-defined renderer can be used to render bids
const bidReq = bidRequest.bids && find(bidRequest.bids, bid => bid.adUnitCode == adUnitCode);
const bidReq = bidderRequest.bids && find(bidderRequest.bids, bid => bid.adUnitCode == adUnitCode);
const adUnitRenderer = bidReq && bidReq.renderer;

if (adUnitRenderer && adUnitRenderer.url) {
Expand Down
9 changes: 7 additions & 2 deletions src/auctionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,23 @@ export function newAuctionManager() {
} else {
utils.logWarn(`Auction not found when adding winning bid`);
}
}
};

auctionManager.getAllWinningBids = function() {
return _auctions.map(auction => auction.getWinningBids())
.reduce(flatten, []);
}
};

auctionManager.getBidsRequested = function() {
return _auctions.map(auction => auction.getBidRequests())
.reduce(flatten, []);
};

auctionManager.getNoBids = function() {
return _auctions.map(auction => auction.getNoBids())
.reduce(flatten, []);
};

auctionManager.getBidsReceived = function() {
// As of now, an old bid which is not used in auction 1 can be used in auction n.
// To prevent this, bid.ttl (time to live) will be added to this logic and bid pool will also be added
Expand Down
1 change: 1 addition & 0 deletions src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"BID_TIMEOUT": "bidTimeout",
"BID_REQUESTED": "bidRequested",
"BID_RESPONSE": "bidResponse",
"NO_BID": "noBid",
"BID_WON": "bidWon",
"BIDDER_DONE": "bidderDone",
"SET_TARGETING": "setTargeting",
Expand Down
33 changes: 24 additions & 9 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,8 @@ $$PREBID_GLOBAL$$.getAdserverTargeting = function (adUnitCode) {
return targeting.getAllTargeting(adUnitCode);
};

/**
* This function returns the bid responses at the given moment.
* @alias module:pbjs.getBidResponses
* @return {Object} map | object that contains the bidResponses
*/

$$PREBID_GLOBAL$$.getBidResponses = function () {
utils.logInfo('Invoking $$PREBID_GLOBAL$$.getBidResponses', arguments);
const responses = auctionManager.getBidsReceived()
function getBids(type) {
const responses = auctionManager[type]()
.filter(adUnitsFilter.bind(this, auctionManager.getAdUnitCodes()));

// find the last auction id to get responses for most recent auction only
Expand All @@ -139,6 +132,28 @@ $$PREBID_GLOBAL$$.getBidResponses = function () {
};
})
.reduce((a, b) => Object.assign(a, b), {});
}

/**
* This function returns the bids requests involved in an auction but not bid on
* @alias module:pbjs.getNoBids
* @return {Object} map | object that contains the bidRequests
*/

$$PREBID_GLOBAL$$.getNoBids = function () {
utils.logInfo('Invoking $$PREBID_GLOBAL$$.getNoBids', arguments);
return getBids('getNoBids');
};

/**
* This function returns the bid responses at the given moment.
* @alias module:pbjs.getBidResponses
* @return {Object} map | object that contains the bidResponses
*/

$$PREBID_GLOBAL$$.getBidResponses = function () {
utils.logInfo('Invoking $$PREBID_GLOBAL$$.getBidResponses', arguments);
return getBids('getBidsReceived');
};

/**
Expand Down
4 changes: 4 additions & 0 deletions test/spec/api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ describe('Publisher API', function () {
assert.isFunction($$PREBID_GLOBAL$$.getBidResponses);
});

it('should have function $$PREBID_GLOBAL$$.getBidResponses', function () {
assert.isFunction($$PREBID_GLOBAL$$.getNoBids);
});

it('should have function $$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode', function () {
assert.isFunction($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode);
});
Expand Down
Loading