mk9-prebid
Version:
Header Bidding Management Library
152 lines (135 loc) • 4.96 kB
JavaScript
/**
* This module interacts with the server used to cache video ad content to be restored later.
* At a high level, the expected workflow goes like this:
*
* - Request video ads from Bidders
* - Generate IDs for each valid bid, and cache the key/value pair on the server.
* - Return these IDs so that publishers can use them to fetch the bids later.
*
* This trickery helps integrate with ad servers, which set character limits on request params.
*/
import { ajax } from './ajax.js';
import { config } from './config.js';
import * as utils from './utils.js';
/**
* @typedef {object} CacheableUrlBid
* @property {string} vastUrl A URL which loads some valid VAST XML.
*/
/**
* @typedef {object} CacheablePayloadBid
* @property {string} vastXml Some VAST XML which loads an ad in a video player.
*/
/**
* A CacheableBid describes the types which the videoCache can store.
*
* @typedef {CacheableUrlBid|CacheablePayloadBid} CacheableBid
*/
/**
* Function which wraps a URI that serves VAST XML, so that it can be loaded.
*
* @param {string} uri The URI where the VAST content can be found.
* @param {string} impUrl An impression tracker URL for the delivery of the video ad
* @return A VAST URL which loads XML from the given URI.
*/
function wrapURI(uri, impUrl) {
// Technically, this is vulnerable to cross-script injection by sketchy vastUrl bids.
// We could make sure it's a valid URI... but since we're loading VAST XML from the
// URL they provide anyway, that's probably not a big deal.
let vastImp = (impUrl) ? `<![CDATA[${impUrl}]]>` : ``;
return `<VAST version="3.0">
<Ad>
<Wrapper>
<AdSystem>prebid.org wrapper</AdSystem>
<VASTAdTagURI><![CDATA[${uri}]]></VASTAdTagURI>
<Impression>${vastImp}</Impression>
<Creatives></Creatives>
</Wrapper>
</Ad>
</VAST>`;
}
/**
* Wraps a bid in the format expected by the prebid-server endpoints, or returns null if
* the bid can't be converted cleanly.
*
* @param {CacheableBid} bid
*/
function toStorageRequest(bid) {
const vastValue = bid.vastXml ? bid.vastXml : wrapURI(bid.vastUrl, bid.vastImpUrl);
let payload = {
type: 'xml',
value: vastValue,
ttlseconds: Number(bid.ttl)
};
if (config.getConfig('cache.vasttrack')) {
payload.bidder = bid.bidder;
payload.bidid = bid.requestId;
payload.aid = bid.auctionId;
// function has a thisArg set to bidderRequest for accessing the auctionStart
if (utils.isPlainObject(this) && this.hasOwnProperty('auctionStart')) {
payload.timestamp = this.auctionStart;
}
}
if (typeof bid.customCacheKey === 'string' && bid.customCacheKey !== '') {
payload.key = bid.customCacheKey;
}
return payload;
}
/**
* A function which should be called with the results of the storage operation.
*
* @callback videoCacheStoreCallback
*
* @param {Error} [error] The error, if one occurred.
* @param {?string[]} uuids An array of unique IDs. The array will have one element for each bid we were asked
* to store. It may include null elements if some of the bids were malformed, or an error occurred.
* Each non-null element in this array is a valid input into the retrieve function, which will fetch
* some VAST XML which can be used to render this bid's ad.
*/
/**
* A function which bridges the APIs between the videoCacheStoreCallback and our ajax function's API.
*
* @param {videoCacheStoreCallback} done A callback to the "store" function.
* @return {Function} A callback which interprets the cache server's responses, and makes up the right
* arguments for our callback.
*/
function shimStorageCallback(done) {
return {
success: function (responseBody) {
let ids;
try {
ids = JSON.parse(responseBody).responses
} catch (e) {
done(e, []);
return;
}
if (ids) {
done(null, ids);
} else {
done(new Error("The cache server didn't respond with a responses property."), []);
}
},
error: function (statusText, responseBody) {
done(new Error(`Error storing video ad in the cache: ${statusText}: ${JSON.stringify(responseBody)}`), []);
}
}
}
/**
* If the given bid is for a Video ad, generate a unique ID and cache it somewhere server-side.
*
* @param {CacheableBid[]} bids A list of bid objects which should be cached.
* @param {videoCacheStoreCallback} [done] An optional callback which should be executed after
* @param {BidderRequest} [bidderRequest]
* the data has been stored in the cache.
*/
export function store(bids, done, bidderRequest) {
const requestData = {
puts: bids.map(toStorageRequest, bidderRequest)
};
ajax(config.getConfig('cache.url'), shimStorageCallback(done), JSON.stringify(requestData), {
contentType: 'text/plain',
withCredentials: true
});
}
export function getCacheUrl(id) {
return `${config.getConfig('cache.url')}?uuid=${id}`;
}