Skip to content

Commit

Permalink
Adagio Bid Adapter: preparation for new Rtd module and Prebid.js 9 (#…
Browse files Browse the repository at this point in the history
…11485)

* Utils: add isSafeFrameWindow(), canAccessWindowTop()

* AdagioBidAdapter: prepare to work with Adagio RTD Provider
  • Loading branch information
osazos authored May 21, 2024
1 parent 00144d5 commit aa118c7
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 76 deletions.
151 changes: 84 additions & 67 deletions modules/adagioBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {find} from '../src/polyfill.js';
import {
canAccessWindowTop,
cleanObj,
deepAccess,
deepClone,
Expand All @@ -8,17 +9,18 @@ import {
getUniqueIdentifierStr,
getWindowSelf,
getWindowTop,
inIframe,
isArray,
isArrayOfNums,
isFn,
inIframe,
isInteger,
isNumber,
isArrayOfNums,
isSafeFrameWindow,
isStr,
logError,
logInfo,
logWarn,
mergeDeep,
isStr,
} from '../src/utils.js';
import {config} from '../src/config.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
Expand Down Expand Up @@ -104,13 +106,15 @@ export const GlobalExchange = (function() {
getOrSetGlobalFeatures: function () {
if (!features) {
features = {
type: 'bidAdapter',
page_dimensions: getPageDimensions().toString(),
viewport_dimensions: getViewPortDimensions().toString(),
user_timestamp: getTimestampUTC().toString(),
dom_loading: getDomLoadingDuration().toString(),
}
}
return features;

return { ...features };
},

prepareExchangeData(storageValue) {
Expand All @@ -130,7 +134,7 @@ export const GlobalExchange = (function() {
const data = {
session: {
new: newSession,
rnd: random
rnd: random,
}
}

Expand All @@ -149,6 +153,9 @@ export const GlobalExchange = (function() {
};
})();

/**
* @deprecated will be removed in Prebid.js 9.
*/
export function adagioScriptFromLocalStorageCb(ls) {
try {
if (!ls) {
Expand Down Expand Up @@ -179,6 +186,9 @@ export function adagioScriptFromLocalStorageCb(ls) {
}
}

/**
* @deprecated will be removed in Prebid.js 9.
*/
export function getAdagioScript() {
storage.getDataFromLocalStorage(ADAGIO_LOCALSTORAGE_KEY, (ls) => {
internal.adagioScriptFromLocalStorageCb(ls);
Expand All @@ -204,31 +214,14 @@ export function getAdagioScript() {
});
}

function canAccessTopWindow() {
try {
if (getWindowTop().location.href) {
return true;
}
} catch (error) {
return false;
}
}

function getCurrentWindow() {
return currentWindow || getWindowSelf();
}

function isSafeFrameWindow() {
const ws = getWindowSelf();
return !!(ws.$sf && ws.$sf.ext);
}

function initAdagio() {
if (canAccessTopWindow()) {
currentWindow = (canAccessTopWindow()) ? getWindowTop() : getWindowSelf();
}
currentWindow = (canAccessWindowTop()) ? getWindowTop() : getWindowSelf();

const w = internal.getCurrentWindow();
const w = currentWindow;

w.ADAGIO = w.ADAGIO || {};
w.ADAGIO.adUnits = w.ADAGIO.adUnits || {};
Expand All @@ -240,13 +233,16 @@ function initAdagio() {

storage.getDataFromLocalStorage('adagio', (storageData) => {
try {
GlobalExchange.prepareExchangeData(storageData);
if (w.ADAGIO.hasRtd !== true) {
logInfo(`${LOG_PREFIX} RTD module not found. Loading external script from adagioBidAdapter is deprecated and will be removed in Prebid.js 9.`);

GlobalExchange.prepareExchangeData(storageData);
getAdagioScript();
}
} catch (e) {
logError(LOG_PREFIX, e);
}
});

getAdagioScript();
}

function enqueue(ob) {
Expand Down Expand Up @@ -359,6 +355,12 @@ function setPlayerName(bidRequest) {
return playerName;
}

function hasRtd() {
const w = internal.getCurrentWindow();

return !!(w.ADAGIO && w.ADAGIO.hasRtd);
};

export const internal = {
enqueue,
getPageviewId,
Expand All @@ -368,9 +370,10 @@ export const internal = {
getRefererInfo,
adagioScriptFromLocalStorageCb,
getCurrentWindow,
canAccessTopWindow,
canAccessWindowTop,
isRendererPreferredFromPublisher,
isNewSession
isNewSession,
hasRtd
};

function _getGdprConsent(bidderRequest) {
Expand Down Expand Up @@ -685,7 +688,7 @@ function autoFillParams(bid) {
}

function getPageDimensions() {
if (isSafeFrameWindow() || !canAccessTopWindow()) {
if (isSafeFrameWindow() || !canAccessWindowTop()) {
return '';
}

Expand All @@ -708,7 +711,7 @@ function getPageDimensions() {
* @returns
*/
function getViewPortDimensions() {
if (!isSafeFrameWindow() && !canAccessTopWindow()) {
if (!isSafeFrameWindow() && !canAccessWindowTop()) {
return '';
}

Expand Down Expand Up @@ -746,7 +749,7 @@ function getSlotPosition(adUnitElementId) {
return '';
}

if (!isSafeFrameWindow() && !canAccessTopWindow()) {
if (!isSafeFrameWindow() && !canAccessWindowTop()) {
return '';
}

Expand All @@ -769,7 +772,7 @@ function getSlotPosition(adUnitElementId) {

position.x = Math.round(sfGeom.t);
position.y = Math.round(sfGeom.l);
} else if (canAccessTopWindow()) {
} else if (canAccessWindowTop()) {
try {
// window.top based computing
const wt = getWindowTop();
Expand Down Expand Up @@ -823,22 +826,14 @@ function getTimestampUTC() {
return Math.floor(new Date().getTime() / 1000) - new Date().getTimezoneOffset() * 60;
}

function getPrintNumber(adUnitCode, bidderRequest) {
if (!bidderRequest.bids || !bidderRequest.bids.length) {
return 1;
}
const adagioBid = find(bidderRequest.bids, bid => bid.adUnitCode === adUnitCode);
return adagioBid.bidderRequestsCount || 1;
}

/**
* domLoading feature is computed on window.top if reachable.
*/
function getDomLoadingDuration() {
let domLoadingDuration = -1;
let performance;

performance = (canAccessTopWindow()) ? getWindowTop().performance : getWindowSelf().performance;
performance = (canAccessWindowTop()) ? getWindowTop().performance : getWindowSelf().performance;

if (performance && performance.timing && performance.timing.navigationStart > 0) {
const val = performance.timing.domLoading - performance.timing.navigationStart;
Expand Down Expand Up @@ -958,6 +953,31 @@ const OUTSTREAM_RENDERER = {
}
};

/**
*
* @param {*} bidRequest
* @returns
*/
const _getFeatures = (bidRequest) => {
const f = { ...deepAccess(bidRequest, 'ortb2.ext.features', GlobalExchange.getOrSetGlobalFeatures()) } || {};

f.print_number = deepAccess(bidRequest, 'bidderRequestsCount', 1).toString();

if (f.type === 'bidAdapter') {
f.adunit_position = getSlotPosition(bidRequest.params.adUnitElementId)
} else {
f.adunit_position = deepAccess(bidRequest, 'ortb2Imp.ext.data.adunit_position');
}

Object.keys(f).forEach((prop) => {
if (f[prop] === '') {
delete f[prop];
}
});

return f;
}

export const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
Expand Down Expand Up @@ -986,6 +1006,7 @@ export const spec = {
const device = internal.getDevice();
const site = internal.getSite(bidderRequest);
const pageviewId = internal.getPageviewId();
const hasRtd = internal.hasRtd();
const gdprConsent = _getGdprConsent(bidderRequest) || {};
const uspConsent = _getUspConsent(bidderRequest) || {};
const coppa = _getCoppa();
Expand All @@ -998,6 +1019,9 @@ export const spec = {
// We don't validate the dsa object in adapter and let our server do it.
const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa');

let rtdSamplingSession = deepAccess(bidderRequest, 'ortb2.ext.session');
const dataExchange = (rtdSamplingSession) ? { session: rtdSamplingSession } : GlobalExchange.getExchangeData();

const aucId = generateUUID()

const adUnits = validBidRequests.map(rawBidRequest => {
Expand All @@ -1006,13 +1030,6 @@ export const spec = {
// Fix https://github.com/prebid/Prebid.js/issues/9781
bidRequest.auctionId = aucId

const globalFeatures = GlobalExchange.getOrSetGlobalFeatures();
const features = {
...globalFeatures,
print_number: getPrintNumber(bidRequest.adUnitCode, bidderRequest).toString(),
adunit_position: getSlotPosition(bidRequest.params.adUnitElementId) // adUnitElementId à déplacer ???
};

// Force the Split Keyword to be a String
if (bidRequest.params.splitKeyword) {
if (isStr(bidRequest.params.splitKeyword) || isNumber(bidRequest.params.splitKeyword)) {
Expand Down Expand Up @@ -1056,23 +1073,20 @@ export const spec = {
}
}

Object.keys(features).forEach((prop) => {
if (features[prop] === '') {
delete features[prop];
}
});

const features = _getFeatures(bidRequest);
bidRequest.features = features;

internal.enqueue({
action: 'features',
ts: Date.now(),
data: {
features: bidRequest.features,
params: bidRequest.params,
adUnitCode: bidRequest.adUnitCode
}
});
if (!hasRtd) {
internal.enqueue({
action: 'features',
ts: Date.now(),
data: {
features,
params: { ...bidRequest.params },
adUnitCode: bidRequest.adUnitCode
}
});
}

// Handle priceFloors module
// We need to use `rawBidRequest` as param because:
Expand Down Expand Up @@ -1127,8 +1141,10 @@ export const spec = {
bidRequest.gpid = gpid;
}

// store the whole bidRequest (adUnit) object in the ADAGIO namespace.
storeRequestInAdagioNS(bidRequest);
if (!hasRtd) {
// store the whole bidRequest (adUnit) object in the ADAGIO namespace.
storeRequestInAdagioNS(bidRequest);
}

// Remove some params that are not needed on the server side.
delete bidRequest.params.siteId;
Expand Down Expand Up @@ -1176,12 +1192,13 @@ export const spec = {
url: ENDPOINT,
data: {
organizationId: organizationId,
hasRtd: hasRtd ? 1 : 0,
secure: secure,
device: device,
site: site,
pageviewId: pageviewId,
adUnits: groupedAdUnits[organizationId],
data: GlobalExchange.getExchangeData(),
data: dataExchange,
regs: {
gdpr: gdprConsent,
coppa: coppa,
Expand Down
23 changes: 23 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const internal = {
createTrackPixelIframeHtml,
getWindowSelf,
getWindowTop,
canAccessWindowTop,
getWindowLocation,
insertUserSyncIframe,
insertElement,
Expand Down Expand Up @@ -180,6 +181,16 @@ export function getWindowLocation() {
return window.location;
}

export function canAccessWindowTop() {
try {
if (internal.getWindowTop().location.href) {
return true;
}
} catch (e) {
return false;
}
}

/**
* Wrappers to console.(log | info | warn | error). Takes N arguments, the same as the native methods
*/
Expand Down Expand Up @@ -620,6 +631,18 @@ export function inIframe() {
}
}

/**
* https://iabtechlab.com/wp-content/uploads/2016/03/SafeFrames_v1.1_final.pdf
*/
export function isSafeFrameWindow() {
if (!inIframe()) {
return false;
}

const ws = internal.getWindowSelf();
return !!(ws.$sf && ws.$sf.ext);
}

export function isSafariBrowser() {
return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
}
Expand Down
Loading

0 comments on commit aa118c7

Please sign in to comment.