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

Optimize AOL adapter and heavily reduce the size #653

Merged
merged 4 commits into from
Oct 13, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
252 changes: 103 additions & 149 deletions src/adapters/aol.js
Original file line number Diff line number Diff line change
@@ -1,183 +1,137 @@
var utils = require('../utils.js');
var ajax = require('../ajax.js').ajax;
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 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;
function _buildPubapiUrl(bid) {
const params = bid.params;
const serverParam = params.server;
var regionParam = params.region || 'us';
var server;

if (!bid) {
utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context);
return;
if (!SERVER_MAP.hasOwnProperty(regionParam)) {
console.warn(`Unknown region '${regionParam}' for AOL bidder.`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.warn doesn't play nice in IE 9. Please use utils.logWarn instead for safety.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for using console.warn() directly is that this warning is meant to be shown when a publisher is configuring a site and uses incorrect region. I want to show the warning even if the debug mode is turned off, so the publisher can see what's wrong. And I expect publisher to be configuring it in a browser other than IE9 🤔. After the site is configured correctly, the warning should go away, so I believe it is safe to use this console.warn(). If you feel otherwise, please let me know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough I suppose. Thanks

regionParam = 'us'; // Default region.
}

cpm = response.getCPM();
if (cpm === null || isNaN(cpm)) {
return _addErrorBid(response, context);
if (serverParam) {
server = serverParam;
} else {
server = SERVER_MAP[regionParam];
}

// 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();
}
bidResponse.bidderCode = ADTECH_BIDDER_NAME;
bidResponse.ad = ad;
bidResponse.cpm = cpm;
bidResponse.width = response.getAdWidth();
bidResponse.height = response.getAdHeight();
bidResponse.creativeId = response.getCreativeId();
// 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
});
}

// add it to the bid manager
function _addErrorBidResponse(bid, response) {
var bidResponse = bidfactory.createBid(2);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider setting the bid response ID to match the bid request ID as described here: #509.

Doing so will position the adapter to take advantage of Prebid Roadmap features such as secure iframe support, improved analytics, Prebid Auctions and so on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this suggestion. Done in 38bd3ae.

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) {
var bidData;

if (!bid) {
utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context);
try {
bidData = response.seatbid[0].bid[0];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty bid or "no bid" response causes this to fail which throws an error, though a response with an empty seatbid array appears to be common in my testing, so should be handled as other than Error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an error is thrown here, addErrorBidResponse() is called, which adds bid response to the bidmanager with status 2 (empty or error bid response). That, I believe, is correct behavior, but I removed error logging, so it won't appear as error in the console when debugging. That was done in 981fb75.

} catch (e) {
_addErrorBidResponse(bid, response);
return;
}

// clean up--we no longer need to store the bid
delete bidsMap[context.alias];
var 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)) {
_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;
var 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);
});
var bidResponse = bidfactory.createBid(1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider setting the bid response ID to match the bid request ID as described here: #509.

Doing so will position the adapter to take advantage of Prebid Roadmap features such as secure iframe support, improved analytics, Prebid Auctions and so on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this suggestion. Done in 38bd3ae.

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, function (bid) {
const pubapiUrl = _buildPubapiUrl(bid);

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an empty bid response, you will still want to add a bid response, likely with _addErrorBidResponse.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. This is now fixed.

}

try {
response = JSON.parse(response);
} catch (e) {
_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