mk9-prebid
Version:
Header Bidding Management Library
312 lines (294 loc) • 11.4 kB
JavaScript
import Base64 from 'crypto-js/enc-base64';
import hmacSHA512 from 'crypto-js/hmac-sha512';
import enc from 'crypto-js/enc-utf8';
import adapter from '../src/AnalyticsAdapter.js';
import CONSTANTS from '../src/constants.json';
import adapterManager from '../src/adapterManager.js';
import { ajax } from '../src/ajax.js';
import * as utils from '../src/utils.js';
const secretKey = 'bydata@123456';
const { EVENTS: { NO_BID, BID_TIMEOUT, AUCTION_END } } = CONSTANTS;
const DEFAULT_EVENT_URL = 'https://pbjs-stream.bydata.com/topics/prebid';
const analyticsType = 'endpoint';
var payload = {};
var bdNbTo = { 'to': [], 'nb': [] };
let initOptions = {};
function onBidTimeout(t) {
if (payload['visitor_data'] && t && t.length > 0) {
bdNbTo['to'] = t;
}
}
function onNoBidData(t) {
if (payload['visitor_data'] && t) {
bdNbTo['nb'].push(t);
}
}
function onAuctionEnd(t) {
logInfo('onAuctionEnd', t);
const {isCorrectOption, logFrequency} = initOptions;
var value = Math.floor(Math.random() * 10000 + 1);
logInfo(' value - frequency ', (value + '-' + logFrequency));
setTimeout(() => {
if (isCorrectOption && value < logFrequency) {
ascAdapter.dataProcess(t);
addKeyForPrebidWinningAndWinningsBids();
ascAdapter.sendPayload();
}
}, 500);
}
const ascAdapter = Object.assign(adapter({ url: DEFAULT_EVENT_URL, analyticsType: analyticsType }), {
track({ eventType, args }) {
switch (eventType) {
case NO_BID:
onNoBidData(args);
break;
case BID_TIMEOUT:
onBidTimeout(args);
break;
case AUCTION_END:
onAuctionEnd(args);
break;
default:
break;
}
}
});
// save the base class function
ascAdapter.originEnableAnalytics = ascAdapter.enableAnalytics;
// override enableAnalytics so we can get access to the config passed in from the page
ascAdapter.enableAnalytics = function(config) {
if (this.initConfig(config)) {
logInfo('initiated:', initOptions);
initOptions.isCorrectOption && ascAdapter.getVisitorData();
ascAdapter.originEnableAnalytics(config);
}
};
ascAdapter.initConfig = function (config) {
let isCorrectOption = true;
initOptions = {};
logInfo('initConfig', config);
initOptions.options = utils.deepClone(config.options);
initOptions.clientId = initOptions.options.clientId || null;
initOptions.logFrequency = initOptions.options.logFrequency;
if (!initOptions.clientId) {
logError('"options.clientId" should not empty!!');
isCorrectOption = false;
}
initOptions.isCorrectOption = isCorrectOption;
this.initOptions = initOptions;
return isCorrectOption;
};
ascAdapter.getVisitorData = function(data = {}) {
var ua = data.userId ? data : {};
var module = {
options: [],
header: [window.navigator.platform, window.navigator.userAgent, window.navigator.appVersion, window.navigator.vendor, window.opera],
dataos: [
{ name: 'Windows Phone', value: 'Windows Phone', version: 'OS' },
{ name: 'Windows', value: 'Win', version: 'NT' },
{ name: 'iPhone', value: 'iPhone', version: 'OS' },
{ name: 'iPad', value: 'iPad', version: 'OS' },
{ name: 'Kindle', value: 'Silk', version: 'Silk' },
{ name: 'Android', value: 'Android', version: 'Android' },
{ name: 'PlayBook', value: 'PlayBook', version: 'OS' },
{ name: 'BlackBerry', value: 'BlackBerry', version: '/' },
{ name: 'Macintosh', value: 'Mac', version: 'OS X' },
{ name: 'Linux', value: 'Linux', version: 'rv' },
{ name: 'Palm', value: 'Palm', version: 'PalmOS' }
],
databrowser: [
{ name: 'Chrome', value: 'Chrome', version: 'Chrome' },
{ name: 'Firefox', value: 'Firefox', version: 'Firefox' },
{ name: 'Safari', value: 'Safari', version: 'Version' },
{ name: 'Internet Explorer', value: 'MSIE', version: 'MSIE' },
{ name: 'Opera', value: 'Opera', version: 'Opera' },
{ name: 'BlackBerry', value: 'CLDC', version: 'CLDC' },
{ name: 'Mozilla', value: 'Mozilla', version: 'Mozilla' }
],
init: function () { var agent = this.header.join(' '); var os = this.matchItem(agent, this.dataos); var browser = this.matchItem(agent, this.databrowser); return { os: os, browser: browser }; },
matchItem: function (string, data) {
var i = 0; var j = 0; var regex; var regexv; var match; var matches; var version;
for (i = 0; i < data.length; i += 1) {
regex = new RegExp(data[i].value, 'i');
match = regex.test(string);
if (match) {
regexv = new RegExp(data[i].version + '[- /:;]([\\d._]+)', 'i');
matches = string.match(regexv);
version = '';
if (matches) { if (matches[1]) { matches = matches[1]; } }
if (matches) {
matches = matches.split(/[._]+/);
for (j = 0; j < matches.length; j += 1) {
if (j === 0) {
version += matches[j] + '.';
} else {
version += matches[j];
}
}
} else {
version = '0';
}
return {
name: data[i].name,
version: parseFloat(version)
};
}
}
return { name: 'unknown', version: 0 };
}
};
function generateUid() {
try {
var buffer = new Uint8Array(16);
crypto.getRandomValues(buffer);
buffer[6] = (buffer[6] & ~176) | 64;
buffer[8] = (buffer[8] & ~64) | 128;
var hex = Array.prototype.map.call(new Uint8Array(buffer), function(x) {
return ('00' + x.toString(16)).slice(-2);
}).join('');
return hex.slice(0, 5) + '-' + hex.slice(5, 9) + '-' + hex.slice(9, 13) + '-' + hex.slice(13, 18);
} catch (e) {
return '';
}
}
function base64url(source) {
var encodedSource = Base64.stringify(source);
encodedSource = encodedSource.replace(/=+$/, '');
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
function getJWToken(data) {
var header = {
'alg': 'HS256',
'typ': 'JWT'
};
var stringifiedHeader = enc.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
var stringifiedData = enc.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
var token = encodedHeader + '.' + encodedData;
var signature = hmacSHA512(token, secretKey);
signature = base64url(signature);
var signedToken = token + '.' + signature;
return signedToken;
}
const {clientId} = initOptions;
var userId = window.localStorage.getItem('userId');
if (!userId) {
userId = generateUid();
window.localStorage.setItem('userId', userId);
}
var screenSize = {width: window.screen.width, height: window.screen.height};
var deviceType = window.navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) ? 'Mobile' : 'Desktop';
var e = module.init();
if (!ua['userId']) {
ua['userId'] = userId;
ua['client_id'] = clientId;
ua['plateform_name'] = e.os.name;
ua['os_version'] = e.os.version;
ua['browser_name'] = e.browser.name;
ua['browser_version'] = e.browser.version;
ua['screen_size'] = screenSize;
ua['device_type'] = deviceType;
ua['time_zone'] = window.Intl.DateTimeFormat().resolvedOptions().timeZone;
}
var signedToken = getJWToken(ua);
payload['visitor_data'] = signedToken;
return signedToken;
}
ascAdapter.dataProcess = function(t) {
payload['auction_id'] = t.auctionId;
payload['auction_start'] = t.timestamp;
payload['auctionData'] = [];
var bidderRequestsData = []; var bidsReceivedData = [];
t.bidderRequests && t.bidderRequests.forEach(bidReq => {
var pObj = {}; pObj['bids'] = [];
bidReq.bids.forEach(bid => {
var data = {};
data['adUnitCode'] = bid.adUnitCode;
data['sizes'] = bid.sizes;
data['bidder'] = bid.bidder;
data['bidId'] = bid.bidId;
data['mediaTypes'] = [];
var mt = bid.mediaTypes.banner ? 'display' : 'video';
data['mediaTypes'].push(mt);
pObj['bids'].push(data);
})
bidderRequestsData.push(pObj);
});
t.bidsReceived && t.bidsReceived.forEach(bid => {
const {requestId, bidder, width, height, cpm, currency, timeToRespond, adUnitCode} = bid;
bidsReceivedData.push({requestId, bidder, width, height, cpm, currency, timeToRespond, adUnitCode});
});
bidderRequestsData.length > 0 && bidderRequestsData.forEach(bdObj => {
var bdsArray = bdObj['bids'];
bdsArray.forEach(bid => {
const {adUnitCode, sizes, bidder, bidId, mediaTypes} = bid;
sizes.forEach(size => {
var sstr = size[0] + 'x' + size[1]
payload['auctionData'].push({adUnit: adUnitCode, size: sstr, media_type: mediaTypes[0], bids_bidder: bidder, bids_bid_id: bidId});
});
});
});
bidsReceivedData.length > 0 && bidsReceivedData.forEach(bdRecived => {
const {requestId, bidder, width, height, cpm, currency, timeToRespond} = bdRecived;
payload['auctionData'].forEach(rwData => {
if (rwData['bids_bid_id'] === requestId && rwData['size'] === width + 'x' + height) {
rwData['br_request_id'] = requestId; rwData['br_bidder'] = bidder; rwData['br_pb_mg'] = cpm;
rwData['br_currency'] = currency; rwData['br_time_to_respond'] = timeToRespond; rwData['br_size'] = width + 'x' + height;
}
})
});
payload['auctionData'] && payload['auctionData'].length > 0 && payload['auctionData'].forEach(u => {
bdNbTo['to'].forEach(i => {
if (u.bids_bid_id === i.bidId) u.is_timeout = 1;
});
bdNbTo['nb'].forEach(i => {
if (u.adUnit === i.adUnitCode && u.bids_bidder === i.bidder && u.bids_bid_id === i.bidId) { u.is_nobid = 1; }
})
});
return payload;
}
ascAdapter.sendPayload = function () {
var obj = { 'records': [ { 'value': payload } ] };
let strJSON = JSON.stringify(obj);
logInfo(' sendPayload ', JSON.stringify(obj));
ajax(DEFAULT_EVENT_URL, undefined, strJSON, {
contentType: 'application/vnd.kafka.json.v2+json',
method: 'POST',
withCredentials: true
});
}
function addKeyForPrebidWinningAndWinningsBids() {
var prebidWinningBids = $$PREBID_GLOBAL$$.getAllPrebidWinningBids();
var winningBids = $$PREBID_GLOBAL$$.getAllWinningBids();
prebidWinningBids && prebidWinningBids.length > 0 && prebidWinningBids.forEach(pbbid => {
payload['auctionData'] && payload['auctionData'].forEach(rwData => {
if (rwData['bids_bid_id'] === pbbid.requestId && rwData['br_size'] === pbbid.size) {
rwData['is_prebid_winning_bid'] = 1;
}
});
})
winningBids && winningBids.length > 0 && winningBids.forEach(wBid => {
payload['auctionData'] && payload['auctionData'].forEach(rwData => {
if (rwData['bids_bid_id'] === wBid.requestId && rwData['br_size'] === wBid.size) {
rwData['is_winning_bid'] = 1;
}
});
})
}
adapterManager.registerAnalyticsAdapter({
adapter: ascAdapter,
code: 'bydata'
});
function logInfo(message, meta) {
utils.logInfo(buildLogMessage(message), meta);
}
function logError(message) {
utils.logError(buildLogMessage(message));
}
function buildLogMessage(message) {
return 'Bydata Prebid Analytics: ' + message;
}
export default ascAdapter;