Skip to content

Commit

Permalink
Optimize AOL adapter and heavily reduce the size (#653)
Browse files Browse the repository at this point in the history
* Optimize AOL adapter and heavily reduce the size

- no aditional request for a JavaScript library
- also supports deals
- unit tests
- Number.isInterger() polyfill

* Fix AOL adapter to add invalid bid in case of empty response

* Set bid response ID to bid request ID for AOL

* Remove error logging for empty bids and refactor ES6
  • Loading branch information
marian-r authored and Matt Kendall committed Oct 13, 2016
1 parent a651873 commit 38a2d25
Show file tree
Hide file tree
Showing 3 changed files with 554 additions and 156 deletions.
269 changes: 113 additions & 156 deletions src/adapters/aol.js
Original file line number Diff line number Diff line change
@@ -1,183 +1,140 @@
var utils = require('../utils.js');
var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
var adloader = require('../adloader');

var AolAdapter = function AolAdapter() {

// constants
var ADTECH_URI = 'https://secure-ads.pictela.net/rm/marketplace/pubtaglib/0_4_0/pubtaglib_0_4_0.js';
var ADTECH_BIDDER_NAME = 'aol';
var ADTECH_PUBAPI_CONFIG = {
pixelsDivId: 'pixelsDiv',
defaultKey: 'aolBid',
roundingConfig: [
{
from: 0,
to: 999,
roundFunction: 'tenCentsRound'
}, {
from: 1000,
to: -1,
roundValue: 1000
}
],
pubApiOK: _addBid,
pubApiER: _addErrorBid
const utils = require('../utils.js');
const ajax = require('../ajax.js').ajax;
const bidfactory = require('../bidfactory.js');
const bidmanager = require('../bidmanager.js');

const AolAdapter = function AolAdapter() {

const pubapiTemplate = template`${'protocol'}://${'host'}/pubapi/3.0/${'network'}/${'placement'}/${'pageid'}/${'sizeid'}/ADTECH;v=2;cmd=bid;cors=yes;alias=${'alias'}${'bidfloor'};misc=${'misc'}`;
const BIDDER_CODE = 'aol';
const SERVER_MAP = {
us: 'adserver-us.adtech.advertising.com',
eu: 'adserver-eu.adtech.advertising.com',
as: 'adserver-as.adtech.advertising.com'
};

var bids;
var bidsMap = {};
var d = window.document;
var h = d.getElementsByTagName('HEAD')[0];
var dummyUnitIdCount = 0;

/**
* @private create a div that we'll use as the
* location for the AOL unit; AOL will document.write
* if the div is not present in the document.
* @param {String} id to identify the div
* @return {String} the id used with the div
*/
function _dummyUnit(id) {
var div = d.createElement('DIV');

if (!id || !id.length) {
id = 'ad-placeholder-' + (++dummyUnitIdCount);
}

div.id = id + '-head-unit';
h.appendChild(div);
return div.id;
function template(strings, ...keys) {
return function(...values) {
let dict = values[values.length - 1] || {};
let result = [strings[0]];
keys.forEach(function(key, i) {
let value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
};
}

/**
* @private Add a succesful bid response for aol
* @param {ADTECHResponse} response the response for the bid
* @param {ADTECHContext} context the context passed from aol
*/
function _addBid(response, context) {
var bid = bidsMap[context.alias];
var cpm;

if (!bid) {
utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context);
return;
}
function _buildPubapiUrl(bid) {
const params = bid.params;
const serverParam = params.server;
let regionParam = params.region || 'us';
let server;

cpm = response.getCPM();
if (cpm === null || isNaN(cpm)) {
return _addErrorBid(response, context);
if (!SERVER_MAP.hasOwnProperty(regionParam)) {
console.warn(`Unknown region '${regionParam}' for AOL bidder.`);
regionParam = 'us'; // Default region.
}

// clean up--we no longer need to store the bid
delete bidsMap[context.alias];

var bidResponse = bidfactory.createBid(1);
var ad = response.getCreative();
if (typeof response.getPixels() !== 'undefined') {
ad += response.getPixels();
if (serverParam) {
server = serverParam;
} else {
server = SERVER_MAP[regionParam];
}
bidResponse.bidderCode = ADTECH_BIDDER_NAME;
bidResponse.ad = ad;
bidResponse.cpm = cpm;
bidResponse.width = response.getAdWidth();
bidResponse.height = response.getAdHeight();
bidResponse.creativeId = response.getCreativeId();

// add it to the bid manager
// Set region param, used by AOL analytics.
params.region = regionParam;

return pubapiTemplate({
protocol: (document.location.protocol === 'https:') ? 'https' : 'http',
host: server,
network: params.network,
placement: parseInt(params.placement),
pageid: params.pageId || 0,
sizeid: params.sizeId || 0,
alias: params.alias || utils.getUniqueIdentifierStr(),
bidfloor: (typeof params.bidFloor !== 'undefined') ?
`;bidfloor=${params.bidFloor.toString()}` : '',
misc: new Date().getTime() // cache busting
});
}

function _addErrorBidResponse(bid, response = {}) {
const bidResponse = bidfactory.createBid(2, bid);
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.reason = response.nbr;
bidResponse.raw = response;
bidmanager.addBidResponse(bid.placementCode, bidResponse);
}

/**
* @private Add an error bid response for aol
* @param {ADTECHResponse} response the response for the bid
* @param {ADTECHContext} context the context passed from aol
*/
function _addErrorBid(response, context) {
var bid = bidsMap[context.alias];
function _addBidResponse(bid, response) {
let bidData;

if (!bid) {
utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context);
try {
bidData = response.seatbid[0].bid[0];
} catch (e) {
_addErrorBidResponse(bid, response);
return;
}

// clean up--we no longer need to store the bid
delete bidsMap[context.alias];
let cpm;

var bidResponse = bidfactory.createBid(2);
bidResponse.bidderCode = ADTECH_BIDDER_NAME;
bidResponse.reason = response.getNbr();
bidResponse.raw = response.getResponse();
bidmanager.addBidResponse(bid.placementCode, bidResponse);
}
if (bidData.ext && bidData.ext.encp) {
cpm = bidData.ext.encp;
} else {
cpm = bidData.price;

/**
* @private map a prebid bidrequest to an ADTECH/aol bid request
* @param {Bid} bid the bid request
* @return {Object} the bid request, formatted for the ADTECH/DAC api
*/
function _mapUnit(bid) {
var alias = bid.params.alias || utils.getUniqueIdentifierStr();

// save the bid
bidsMap[alias] = bid;

return {
adContainerId: _dummyUnit(bid.params.adContainerId),
server: bid.params.server, // By default, DAC.js will use the US region endpoint (adserver.adtechus.com)
sizeid: bid.params.sizeId || 0,
pageid: bid.params.pageId,
secure: document.location.protocol === 'https:',
serviceType: 'pubapi',
performScreenDetection: false,
alias: alias,
network: bid.params.network,
placement: parseInt(bid.params.placement),
gpt: {
adUnitPath: bid.params.adUnitPath || bid.placementCode,
size: bid.params.size || (bid.sizes || [])[0]
},
params: {
cors: 'yes',
cmd: 'bid',
bidfloor: (typeof bid.params.bidFloor !== "undefined") ? bid.params.bidFloor.toString() : ''
},
pubApiConfig: ADTECH_PUBAPI_CONFIG,
placementCode: bid.placementCode
};
}
if (cpm === null || isNaN(cpm)) {
utils.logError('Invalid price in bid response', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response);
return;
}
}

/**
* @private once ADTECH is loaded, request bids by
* calling ADTECH.loadAd
*/
function _reqBids() {
if (!window.ADTECH) {
utils.logError('window.ADTECH is not present!', ADTECH_BIDDER_NAME);
return;
let ad = bidData.adm;
if (bidData.ext && bidData.ext.pixels) {
ad += bidData.ext.pixels;
}

// get the bids
utils._each(bids, function (bid) {
var bidreq = _mapUnit(bid);
window.ADTECH.loadAd(bidreq);
});
const bidResponse = bidfactory.createBid(1, bid);
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.ad = ad;
bidResponse.cpm = cpm;
bidResponse.width = bidData.w;
bidResponse.height = bidData.h;
bidResponse.creativeId = bidData.crid;
bidResponse.pubapiId = response.id;
bidResponse.currencyCode = response.cur;
if (bidData.dealid) {
bidResponse.dealId = bidData.dealid;
}

bidmanager.addBidResponse(bid.placementCode, bidResponse);
}

/**
* @public call the bids
* this requests the specified bids
* from aol marketplace
* @param {Object} params
* @param {Array} params.bids the bids to be requested
*/
function _callBids(params) {
window.bidRequestConfig = window.bidRequestConfig || {};
window.dacBidRequestConfigs = window.dacBidRequestConfigs || {};
bids = params.bids;
if (!bids || !bids.length) return;
adloader.loadScript(ADTECH_URI, _reqBids, true);
utils._each(params.bids, bid => {
const pubapiUrl = _buildPubapiUrl(bid);

ajax(pubapiUrl, response => {
if (!response && response.length <= 0) {
utils.logError('Empty bid response', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response);
return;
}

try {
response = JSON.parse(response);
} catch (e) {
utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response);
return;
}

_addBidResponse(bid, response);

}, null, { withCredentials: true });
});
}

return {
Expand Down
7 changes: 7 additions & 0 deletions src/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,10 @@ if (!Array.prototype.includes) {
}
});
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
Number.isInteger = Number.isInteger || function(value) {
return typeof value === 'number' &&
isFinite(value) &&
Math.floor(value) === value;
};
Loading

0 comments on commit 38a2d25

Please sign in to comment.