Skip to content

Commit

Permalink
IX Bid Adapter: refactor build request method and ft improves (prebid…
Browse files Browse the repository at this point in the history
…#9793)

Co-authored-by: shahin.rahbariasl <[email protected]>
  • Loading branch information
2 people authored and jorgeluisrocha committed May 18, 2023
1 parent 8f5516c commit b60aaf6
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 176 deletions.
147 changes: 42 additions & 105 deletions modules/ixBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
logError,
logWarn,
mergeDeep,
parseQueryStringParameters,
safeJSONParse
} from '../src/utils.js';
import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js';
Expand Down Expand Up @@ -104,9 +103,12 @@ export const LOCAL_STORAGE_FEATURE_TOGGLES_KEY = `${BIDDER_CODE}_features`;
let hasRegisteredHandler = false;
export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
export const FEATURE_TOGGLES = {
// Update with list of CFTs to be requested from Exchange
REQUESTED_FEATURE_TOGGLES: [],

featureToggles: {},
isFeatureEnabled: function (ft) {
return deepAccess(this.featureToggles, `features.${ft}.activated`)
return deepAccess(this.featureToggles, `features.${ft}.activated`, false)
},
getFeatureToggles: function () {
if (storage.localStorageIsEnabled()) {
Expand Down Expand Up @@ -152,11 +154,6 @@ const MEDIA_TYPES = {
Native: 4
};

let baseRequestSize = 0;
let currentRequestSize = 0;
let wasAdUnitImpressionsTrimmed = false;
let currentImpressionSize = 0;

/**
* Transform valid bid request config object to banner impression object that will be sent to ad server.
*
Expand Down Expand Up @@ -598,19 +595,12 @@ function getEidInfo(allEids) {
*
*/
function buildRequest(validBidRequests, bidderRequest, impressions, version) {
baseRequestSize = 0;
currentRequestSize = 0;
wasAdUnitImpressionsTrimmed = false;
currentImpressionSize = 0;

// Always use secure HTTPS protocol.
let baseUrl = SECURE_BID_URL;
// Get ids from Prebid User ID Modules
let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids'));
let userEids = eidInfo.toSend;

let MAX_REQUEST_SIZE = 8000;

// RTI ids will be included in the bid request if the function getIdentityInfo() is loaded
// and if the data for the partner exist
if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') {
Expand All @@ -625,6 +615,9 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
const requests = [];
let r = createRequest(validBidRequests);

// Add FTs to be requested from Exchange
r = addRequestedFeatureToggles(r, FEATURE_TOGGLES.REQUESTED_FEATURE_TOGGLES)

// getting ixdiags for adunits of the video, outstream & multi format (MF) style
let ixdiag = buildIXDiag(validBidRequests);
for (var key in ixdiag) {
Expand All @@ -636,25 +629,17 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
r = applyRegulations(r, bidderRequest);

let payload = {};
createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE);
createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload);

let requestSequenceNumber = 0;
const transactionIds = Object.keys(impressions);
let isFpdAdded = false;

for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) {
// buildRequestV2 does not have request spliting logic.
if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) {
if (currentRequestSize >= MAX_REQUEST_SIZE) {
break;
}
}
if (requests.length >= MAX_REQUEST_LIMIT) {
break;
}

r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE);
currentRequestSize += currentImpressionSize;
r = addImpressions(impressions, transactionIds, r, adUnitIndex);

const fpd = deepAccess(bidderRequest, 'ortb2') || {};
const site = { ...(fpd.site || fpd.context) };
Expand All @@ -667,31 +652,17 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
clonedRObject.site = mergeDeep({}, clonedRObject.site, site);
clonedRObject.user = mergeDeep({}, clonedRObject.user, user);

const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length;

if (requestSize < MAX_REQUEST_SIZE) {
r.site = mergeDeep({}, r.site, site);
r.user = mergeDeep({}, r.user, user);
isFpdAdded = true;
const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length;
currentRequestSize += fpdRequestSize;
} else {
logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE });
}
r.site = mergeDeep({}, r.site, site);
r.user = mergeDeep({}, r.user, user);
isFpdAdded = true;
}

// add identifiers info to ixDiag
r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE);
r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl);

const isLastAdUnit = adUnitIndex === transactionIds.length - 1;

if (wasAdUnitImpressionsTrimmed || isLastAdUnit) {
if (!isLastAdUnit || requestSequenceNumber) {
r.ext.ixdiag.sn = requestSequenceNumber;
}

requestSequenceNumber++;

if (isLastAdUnit) {
requests.push({
method: 'POST',
url: baseUrl + '?s=' + siteID,
Expand All @@ -702,7 +673,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
validBidRequests
});

currentRequestSize = baseRequestSize;
r.imp = [];
isFpdAdded = false;
}
Expand Down Expand Up @@ -751,6 +721,24 @@ function createRequest(validBidRequests) {
return r
}

/**
* Adds requested feature toggles to the provided request object to be sent to Exchange.
* @param {object} r - The request object to add feature toggles to.
* @param {Array} requestedFeatureToggles - The list of feature toggles to add.
* @returns {object} The updated request object with the added feature toggles.
*/
function addRequestedFeatureToggles(r, requestedFeatureToggles) {
if (requestedFeatureToggles.length > 0) {
r.ext.features = {};
// Loop through each feature toggle and add it to the features object.
// Add current activation status as well.
requestedFeatureToggles.forEach(toggle => {
r.ext.features[toggle] = { activated: FEATURE_TOGGLES.isFeatureEnabled(toggle) };
});
}
return r;
}

/**
* enrichRequest adds userSync configs, source, and referer info to request and ixDiag objects.
*
Expand Down Expand Up @@ -871,9 +859,8 @@ function applyRegulations(r, bidderRequest) {
* @param {string} baseUrl Base exchagne URL.
* @param {array} requests List of request obejcts.
* @param {object} payload Request payload object.
* @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1).
*/
function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE) {
function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload) {
// Use the siteId in the first bid request as the main siteId.
siteID = validBidRequests[0].params.siteId;
payload.s = siteID;
Expand All @@ -882,16 +869,6 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa
const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix';
const otherIxConfig = config.getConfig(bidderCode);

baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length;

if (baseRequestSize > MAX_REQUEST_SIZE) {
logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE });
return requests;
}

currentRequestSize = baseRequestSize;
let fpdRequestSize = 0;

if (otherIxConfig) {
// Append firstPartyData to r.site.page if firstPartyData exists.
if (typeof otherIxConfig.firstPartyData === 'object') {
Expand All @@ -904,25 +881,10 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa
}
firstPartyString = firstPartyString.slice(0, -1);

fpdRequestSize = encodeURIComponent(firstPartyString).length;

if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) {
if (fpdRequestSize < MAX_REQUEST_SIZE) {
if ('page' in r.site) {
r.site.page += firstPartyString;
} else {
r.site.page = firstPartyString;
}
currentRequestSize += fpdRequestSize;
} else {
logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE });
}
if ('page' in r.site) {
r.site.page += firstPartyString;
} else {
if ('page' in r.site) {
r.site.page += firstPartyString;
} else {
r.site.page = firstPartyString;
}
r.site.page = firstPartyString;
}
}
}
Expand All @@ -935,30 +897,17 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa
* @param {array} transactionIds List of transaction Ids.
* @param {object} r Reuqest object.
* @param {int} adUnitIndex Index of the current add unit
* @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1).
* @return {object} Reqyest object with added impressions describing the request to the server.
*/
function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE) {
function addImpressions(impressions, transactionIds, r, adUnitIndex) {
const adUnitImpressions = impressions[transactionIds[adUnitIndex]];
const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions;

let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize;
const sourceImpressions = { ixImps, missingBannerImpressions };
const impressionObjects = Object.keys(sourceImpressions)
.map((key) => sourceImpressions[key])
.filter(item => Array.isArray(item))
.reduce((acc, curr) => acc.concat(...curr), []);

currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length;

if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) {
while (impressionObjects.length && currentImpressionSize > remainingRequestSize) {
wasAdUnitImpressionsTrimmed = true;
impressionObjects.pop();
currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length;
}
}

const gpid = impressions[transactionIds[adUnitIndex]].gpid;
const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code;
const tid = impressions[transactionIds[adUnitIndex]].tid;
Expand Down Expand Up @@ -1071,30 +1020,18 @@ function addFPD(bidderRequest, r, fpd, site, user) {
* @param {int} adUnitIndex Index of the current add unit
* @param {object} payload Request payload object.
* @param {string} baseUrl Base exchagne URL.
* @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1).
* @return {object} Reqyest object with added indentigfier info to ixDiag.
*/
function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE) {
function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl) {
const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot;
const tagId = impressions[transactionIds[adUnitIndex]].tagId;
const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode;
const divId = impressions[transactionIds[adUnitIndex]].divId;
if (pbaAdSlot || tagId || adUnitCode || divId) {
const clonedRObject = deepClone(r);
const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length;
if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) {
if (requestSize < MAX_REQUEST_SIZE) {
r.ext.ixdiag.pbadslot = pbaAdSlot;
r.ext.ixdiag.tagid = tagId;
r.ext.ixdiag.adunitcode = adUnitCode;
r.ext.ixdiag.divId = divId;
}
} else {
r.ext.ixdiag.pbadslot = pbaAdSlot;
r.ext.ixdiag.tagid = tagId;
r.ext.ixdiag.adunitcode = adUnitCode;
r.ext.ixdiag.divId = divId;
}
r.ext.ixdiag.pbadslot = pbaAdSlot;
r.ext.ixdiag.tagid = tagId;
r.ext.ixdiag.adunitcode = adUnitCode;
r.ext.ixdiag.divId = divId;
}

return r;
Expand Down
Loading

0 comments on commit b60aaf6

Please sign in to comment.