From 44491d4c2fda03f752787da2764bd39dd74e993c Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Tue, 19 Dec 2017 15:59:13 -0700 Subject: [PATCH 1/5] initial version of pre1api module to allow use of deprecated API in 1.0 --- modules/pre1api.js | 123 +++++++++++++++++++++++++++++++++++++++++++++ src/config.js | 5 +- src/prebid.js | 6 ++- 3 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 modules/pre1api.js diff --git a/modules/pre1api.js b/modules/pre1api.js new file mode 100644 index 00000000000..5d0fc2b6ca0 --- /dev/null +++ b/modules/pre1api.js @@ -0,0 +1,123 @@ + +import { config } from 'src/config'; +import { logWarn, logInfo } from 'src/utils'; + +const MODULE_NAME = 'pre-1.0 API'; + +let pbjs = window['$$PREBID_GLOBAL$$']; + +logInfo(`loading ${MODULE_NAME} module and patching prebid with deprecated APIs.`); + +let auctionQueue = []; + +let emptyFn = () => []; + +Object.defineProperty(pbjs, '_winningBids', { + get: () => pbjs.getAllWinningBids() +}); + +let auctionPropMap = { + _bidsReceived: auction => auction.getBidsReceived(), + _bidsRequested: auction => auction.getBidRequests(), + _adUnitCodes: auction => auction.getAdUnitCodes(), + cbTimeout: auction => auction.getTimeout(), + allBidsAvailable: auction => auction.getBidRequests().every((bidRequest) => bidRequest.doneCbCallCount >= 1) +}; + +let configPropMap = { + bidderTimeout: 'bidderTimeout', + logging: 'debug', + publisherDomain: 'publisherDomain', + enableSendAllBids: 'enableSendAllBids', + setPriceGranularity: 'priceGranularity', + setBidderSequence: 'bidderSequence', + setS2SConfig: 's2sConfig' +}; + +pbjs.addCallback = pbjs.onEvent; +pbjs.removeCallback = pbjs.offEvent; + +// can't see anywhere that this was used, but it is listed in Prebid 1.0 transition guide... +// so just adding as empty array +pbjs._adsReceived = []; + +config.setDefaults({ + enableSendAllBids: false, + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + } +}); + +let currAuction = { + getBidsReceived: emptyFn, + getBidsRequested: emptyFn, + getAdUnitCodes: emptyFn, + getTimeout: () => config.getConfig('bidderTimeout') +}; + +// we need to intercept s2sConfig rather than call setConfig or setDefaults directly, otherwise the code will fail when +// the server adapter attempts to validate the configuration passed in by the publisher +config.setConfig.addHook((config, next) => { + if (config.s2sConfig) { + config.s2sConfig = Object.assign({ + endpoint: 'https://prebid.adnxs.com/pbs/v1/auction', + syncEndpoint: 'https://prebid.adnxs.com/pbs/v1/cookie_sync' + }, config.s2sConfig); + } + next(config); +}); + +/** + * Hook to queue and disallow concurrent auctions (as Prebid would function pre 1.0) + */ +pbjs.requestBids.addHook((config, next) => { + auctionQueue.push(() => { + let oldHandler = config.bidsBackHandler; + config.bidsBackHandler = (...args) => { + if (typeof oldHandler === 'function') { + oldHandler.apply(null, args); + } + + if (auctionQueue[0]) { + auctionQueue.shift()(); + } + }; + + currAuction = next(config); + }); + + if (auctionQueue.length === 1) { + auctionQueue.shift()(); + } else { + logWarn(`${MODULE_NAME} module: concurrency has been disabled and "$$PREBID_GLOBAL$$.requestBids" call was queued`); + } +}, 100); + +Object.keys(auctionPropMap).forEach(prop => { + if (prop === 'allBidsAvailable') { + pbjs[prop] = deprecated(prop, () => auctionPropMap[prop](currAuction)); + } + Object.defineProperty(pbjs, prop, { + get: deprecated(prop, () => auctionPropMap[prop](currAuction)) + }); +}); + +Object.keys(configPropMap).forEach(prop => { + if (prop === 'enableSendAllBids') { + pbjs[prop] = deprecated(prop, () => config.setConfig({[prop]: true})); + } else if (prop.lastIndexOf('set', 0) === 0) { + pbjs[prop] = deprecated(prop, value => config.setConfig({[configPropMap[prop]]: value})); + } else { + Object.defineProperty(pbjs, prop, { + get: deprecated(prop, () => config.getConfig(configPropMap[prop])), + set: deprecated(prop, value => config.setConfig({[configPropMap[prop]]: value})) + }); + } +}); + +function deprecated(name, fn) { + return (...args) => { + logWarn(`${MODULE_NAME} module: accessed deprecated API "$$PREBID_GLOBAL$$.${name}"`); + return fn.apply(null, args); + }; +} diff --git a/src/config.js b/src/config.js index 146c0f17a65..ff68fc7bfff 100644 --- a/src/config.js +++ b/src/config.js @@ -10,6 +10,7 @@ import { isValidPriceConfig } from './cpmBucketManager'; import find from 'core-js/library/fn/array/find'; import includes from 'core-js/library/fn/array/includes'; +import { createHook } from 'src/hook'; const utils = require('./utils'); const DEFAULT_DEBUG = false; @@ -188,7 +189,7 @@ export function newConfig() { * Sets configuration given an object containing key-value pairs and calls * listeners that were added by the `subscribe` function */ - function setConfig(options) { + let setConfig = createHook('asyncSeries', function setConfig(options) { if (typeof options !== 'object') { utils.logError('setConfig options must be an object'); return; @@ -208,7 +209,7 @@ export function newConfig() { }); callSubscribers(topicalConfig); - } + }); /** * Sets configuration defaults which setConfig values can be applied on top of diff --git a/src/prebid.js b/src/prebid.js index ffecabe05eb..71f918c562e 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -10,6 +10,7 @@ import { loadScript } from './adloader'; import { config } from './config'; import { auctionManager } from './auctionManager'; import { targeting } from './targeting'; +import { createHook } from 'src/hook'; import includes from 'core-js/library/fn/array/includes'; var $$PREBID_GLOBAL$$ = getGlobal(); @@ -282,7 +283,7 @@ $$PREBID_GLOBAL$$.removeAdUnit = function (adUnitCode) { * @param {Array} requestOptions.labels * @alias module:pbjs.requestBids */ -$$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels } = {}) { +$$PREBID_GLOBAL$$.requestBids = createHook('asyncSeries', function ({ bidsBackHandler, timeout, adUnits, adUnitCodes, labels } = {}) { events.emit('requestBids'); const cbTimeout = timeout || config.getConfig('bidderTimeout'); adUnits = adUnits || $$PREBID_GLOBAL$$.adUnits; @@ -332,7 +333,8 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a const auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout, labels}); auction.callBids(); -}; + return auction; +}); /** * From 1037bc2a55004d5d85e9556cf7ad405cd0d80096 Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Tue, 19 Dec 2017 17:26:33 -0700 Subject: [PATCH 2/5] move cbTimeout to config rather than auction properties --- modules/pre1api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pre1api.js b/modules/pre1api.js index 5d0fc2b6ca0..26dbb77b49c 100644 --- a/modules/pre1api.js +++ b/modules/pre1api.js @@ -20,11 +20,11 @@ let auctionPropMap = { _bidsReceived: auction => auction.getBidsReceived(), _bidsRequested: auction => auction.getBidRequests(), _adUnitCodes: auction => auction.getAdUnitCodes(), - cbTimeout: auction => auction.getTimeout(), allBidsAvailable: auction => auction.getBidRequests().every((bidRequest) => bidRequest.doneCbCallCount >= 1) }; let configPropMap = { + cbTimeout: 'bidderTimeout', bidderTimeout: 'bidderTimeout', logging: 'debug', publisherDomain: 'publisherDomain', From fdc24bd1a171842fe335666aedbef2cc1ad7d635 Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Thu, 21 Dec 2017 10:41:52 -0700 Subject: [PATCH 3/5] fix bug in auction queueing for pre-1.0 api module --- modules/pre1api.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/pre1api.js b/modules/pre1api.js index 26dbb77b49c..19f3dd2427c 100644 --- a/modules/pre1api.js +++ b/modules/pre1api.js @@ -78,8 +78,9 @@ pbjs.requestBids.addHook((config, next) => { oldHandler.apply(null, args); } + auctionQueue.shift(); if (auctionQueue[0]) { - auctionQueue.shift()(); + auctionQueue[0](); } }; @@ -87,7 +88,7 @@ pbjs.requestBids.addHook((config, next) => { }); if (auctionQueue.length === 1) { - auctionQueue.shift()(); + auctionQueue[0](); } else { logWarn(`${MODULE_NAME} module: concurrency has been disabled and "$$PREBID_GLOBAL$$.requestBids" call was queued`); } From ae26fb9cffef93093ebce832d113f89a364c4eb8 Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Thu, 4 Jan 2018 10:27:15 -0700 Subject: [PATCH 4/5] updated doc comment for pre-1.0 api module --- modules/pre1api.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/modules/pre1api.js b/modules/pre1api.js index 19f3dd2427c..53e32281ef2 100644 --- a/modules/pre1api.js +++ b/modules/pre1api.js @@ -1,6 +1,38 @@ -import { config } from 'src/config'; -import { logWarn, logInfo } from 'src/utils'; +/** + pre1api module + + This module supports backwards compatibility for those who need extra time to re-code their pages to work with the + Prebid 1.0 API. Use of this backwards compatibility module is recommended only as an interim solution. + + It provides equivalents for the following variables and functions that were deprecated in PBJS 1.0: + - pbjs._winningBids + - pbjs._bidsReceived + - pbjs._bidsRequested + - pbjs._adUnitCodes + - pbjs._adsReceived + - pbjs.cbTimeout + - pbjs.addCallback() + - pbjs.removeCallback() + - pbjs.allBidsAvailable() + - pbjs.bidderTimeout + - pbjs.logging + - pbjs.publisherDomain + - pbjs.setPriceGranularity() + - pbjs.enableSendAllBids() // and also defaults this value to `false` like pre-1.0 + - pbjs.setBidderSequence() + - pbjs.setS2SConfig() // and makes endpoints optional again (defaulting to the appnexus endpoints) + + This will not support the pre-1.0 sizeMapping feature. + + The drawback is that this module disables concurrency for requestBids(), queueing them as was done in pre-1.0. Anytime + an auction request is queued or one of these APIs is accessed it will display a deprecation warning in the console if + logging is enabled. So while this is useful for those that need more time to migrate, it eliminates one of the best + features of PBJS 1.0 as is required to emulate the old API. + */ + +import {config} from 'src/config'; +import {logWarn, logInfo} from 'src/utils'; const MODULE_NAME = 'pre-1.0 API'; From 3a530739c0568f1f01d87a582ba998c071e93889 Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Fri, 5 Jan 2018 15:00:40 -0700 Subject: [PATCH 5/5] set next function correctly if requestBids is called w/ no arguments --- modules/pre1api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pre1api.js b/modules/pre1api.js index 53e32281ef2..707d10fbfd8 100644 --- a/modules/pre1api.js +++ b/modules/pre1api.js @@ -102,7 +102,7 @@ config.setConfig.addHook((config, next) => { /** * Hook to queue and disallow concurrent auctions (as Prebid would function pre 1.0) */ -pbjs.requestBids.addHook((config, next) => { +pbjs.requestBids.addHook((config, next = config) => { auctionQueue.push(() => { let oldHandler = config.bidsBackHandler; config.bidsBackHandler = (...args) => {