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

AMX Bid Adapter: add or update general adapter support and code refactoring #6403

Merged
merged 2 commits into from
Mar 15, 2021
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
115 changes: 54 additions & 61 deletions modules/amxBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, VIDEO } from '../src/mediaTypes.js';
import { parseUrl, deepAccess, _each, formatQS, getUniqueIdentifierStr, triggerPixel } from '../src/utils.js';
import { parseUrl, deepAccess, _each, formatQS, getUniqueIdentifierStr, triggerPixel, isFn, logError } from '../src/utils.js';
import { config } from '../src/config.js';
import { getStorageManager } from '../src/storageManager.js';

Expand All @@ -9,7 +9,6 @@ const storage = getStorageManager(737, BIDDER_CODE);
const SIMPLE_TLD_TEST = /\.com?\.\w{2,4}$/;
const DEFAULT_ENDPOINT = 'https://prebid.a-mo.net/a/c';
const VERSION = 'pba1.2.1';
const xmlDTDRxp = /^\s*<\?xml[^\?]+\?>/;
const VAST_RXP = /^\s*<\??(?:vast|xml)/i;
const TRACKING_ENDPOINT = 'https://1x1.a-mo.net/hbx/';
const AMUID_KEY = '__amuidpb';
Expand Down Expand Up @@ -45,11 +44,16 @@ function flatMap(input, mapFn) {
.reduce((acc, item) => item != null && acc.concat(item), [])
}

const generateDTD = (xmlDocument) =>
`<?xml version="${xmlDocument.xmlVersion}" encoding="${xmlDocument.xmlEncoding}" ?>`;

const isVideoADM = (html) => html != null && VAST_RXP.test(html);
const getMediaType = (bid) => isVideoADM(bid.adm) ? VIDEO : BANNER;

function getMediaType(bid) {
if (isVideoADM(bid.adm)) {
return VIDEO;
}

return BANNER;
}

const nullOrType = (value, type) =>
value == null || (typeof value) === type // eslint-disable-line valid-typeof

Expand Down Expand Up @@ -103,6 +107,32 @@ const trackEvent = (eventName, data) =>
eid: getUniqueIdentifierStr(),
})}`);

const DEFAULT_MIN_FLOOR = 0;

function ensureFloor(floorValue) {
return typeof floorValue === 'number' && isFinite(floorValue) && floorValue > 0.0
? floorValue : DEFAULT_MIN_FLOOR;
}

function getFloor(bid) {
if (!isFn(bid.getFloor)) {
return deepAccess(bid, 'params.floor', DEFAULT_MIN_FLOOR);
}

try {
const floor = bid.getFloor({
currency: 'USD',
mediaType: '*',
size: '*',
bidRequest: bid
});
return floor.floor;
} catch (e) {
logError('call to getFloor failed: ', e);
return DEFAULT_MIN_FLOOR;
}
}

function convertRequest(bid) {
const size = largestSize(bid.sizes, bid.mediaTypes) || [0, 0];
const isVideoBid = bid.mediaType === VIDEO || VIDEO in bid.mediaTypes
Expand All @@ -116,16 +146,21 @@ function convertRequest(bid) {
bid.sizes,
deepAccess(bid, `mediaTypes.${BANNER}.sizes`, []) || [],
deepAccess(bid, `mediaTypes.${VIDEO}.sizes`, []) || [],
]
];

const videoData = deepAccess(bid, `mediaTypes.${VIDEO}`, {}) || {};

const params = {
au,
av,
vd: videoData,
vr: isVideoBid,
ms: multiSizes,
aw: size[0],
ah: size[1],
tf: 0,
sc: bid.schain || {},
f: ensureFloor(getFloor(bid))
};

if (typeof tid === 'string' && tid.length > 0) {
Expand All @@ -143,52 +178,6 @@ function decorateADM(bid) {
return bid.adm + impressions;
}

function transformXmlSimple(bid) {
const pixels = []
_each([bid.nurl].concat(bid.ext != null && bid.ext.himp != null ? bid.ext.himp : []), (pixel) => {
if (pixel != null) {
pixels.push(`<Impression><![CDATA[${pixel}]]></Impression>`)
}
});
// find the current "Impression" here & slice ours in
const impressionIndex = bid.adm.indexOf('<Impression')
return bid.adm.slice(0, impressionIndex) + pixels.join('') + bid.adm.slice(impressionIndex)
}

function getOuterHTML(node) {
return 'outerHTML' in node && node.outerHTML != null
? node.outerHTML : (new XMLSerializer()).serializeToString(node)
}

function decorateVideoADM(bid) {
if (typeof DOMParser === 'undefined' || DOMParser.prototype.parseFromString == null) {
return transformXmlSimple(bid)
}

const doc = new DOMParser().parseFromString(bid.adm, 'text/xml');
if (doc == null || doc.querySelector('parsererror') != null) {
return null;
}

const root = doc.querySelector('InLine,Wrapper')
if (root == null) {
return null;
}

const pixels = [bid.nurl].concat(bid.ext != null && bid.ext.himp != null ? bid.ext.himp : [])
.filter((url) => url != null);

_each(pixels, (pxl) => {
const imagePixel = doc.createElement('Impression');
const cdata = doc.createCDATASection(pxl);
imagePixel.appendChild(cdata);
root.appendChild(imagePixel);
});

const dtdMatch = xmlDTDRxp.exec(bid.adm);
return (dtdMatch != null ? dtdMatch[0] : generateDTD(doc)) + getOuterHTML(doc.documentElement);
}

function resolveSize(bid, request, bidId) {
if (bid.w != null && bid.w > 1 && bid.h != null && bid.h > 1) {
return [bid.w, bid.h];
Expand All @@ -212,14 +201,16 @@ function values(source) {
});
}

const isTrue = (boolValue) =>
boolValue === true || boolValue === 1 || boolValue === 'true';

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],

isBidRequestValid(bid) {
return nullOrType(deepAccess(bid, 'params.endpoint', null), 'string') &&
nullOrType(deepAccess(bid, 'params.tagId', null), 'string') &&
nullOrType(deepAccess(bid, 'params.testMode', null), 'boolean');
nullOrType(deepAccess(bid, 'params.tagId', null), 'string')
},

buildRequests(bidRequests, bidderRequest) {
Expand All @@ -239,8 +230,9 @@ export const spec = {
brc: fbid.bidderRequestsCount || 0,
bwc: fbid.bidderWinsCount || 0,
trc: fbid.bidRequestsCount || 0,
tm: testMode,
tm: isTrue(testMode),
V: '$prebid.version$',
vg: '$$PREBID_GLOBAL$$',
i: (testMode && tagId != null) ? tagId : getID(loc),
l: {},
f: 0.01,
Expand All @@ -259,7 +251,8 @@ export const spec = {
d: '',
m: createBidMap(bidRequests),
cpp: config.getConfig('coppa') ? 1 : 0,
fpd: config.getLegacyFpd(config.getConfig('ortb2')),
fpd2: config.getConfig('ortb2'),
tmax: config.getConfig('bidderTimeout'),
eids: values(bidRequests.reduce((all, bid) => {
// we only want unique ones in here
if (bid == null || bid.userIdAsEids == null) {
Expand Down Expand Up @@ -306,7 +299,6 @@ export const spec = {
},

interpretResponse(serverResponse, request) {
// validate the body/response
const response = serverResponse.body;
if (response == null || typeof response === 'string') {
return [];
Expand All @@ -320,13 +312,14 @@ export const spec = {
return flatMap(response.r[bidID], (siteBid) =>
siteBid.b.map((bid) => {
const mediaType = getMediaType(bid);
// let ad = null;
let ad = mediaType === BANNER ? decorateADM(bid) : decorateVideoADM(bid);
const ad = mediaType === BANNER ? decorateADM(bid) : bid.adm;

if (ad == null) {
return null;
}

const size = resolveSize(bid, request.data, bidID);
const defaultExpiration = mediaType === BANNER ? 240 : 300;

return ({
requestId: bidID,
Expand All @@ -341,7 +334,7 @@ export const spec = {
advertiserDomains: bid.adomain,
mediaType,
},
ttl: mediaType === VIDEO ? 90 : 70
ttl: typeof bid.exp === 'number' ? bid.exp : defaultExpiration,
});
})).filter((possibleBid) => possibleBid != null);
});
Expand Down
Loading