@mediarithmics/plugins-nodejs-sdk
Version:
This is the mediarithmics nodejs to help plugin developers bootstrapping their plugin without having to deal with most of the plugin boilerplate
119 lines (118 loc) • 6.25 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const index_1 = require("../../../index");
class BidOptimizerPlugin extends index_1.BasePlugin {
/**
*
* @param bidOptimizerId
*/
fetchBidOptimizer(bidOptimizerId) {
const _super = name => super[name];
return __awaiter(this, void 0, void 0, function* () {
const bidOptimizerResponse = yield _super("requestGatewayHelper").call(this, "GET", `${this.outboundPlatformUrl}/v1/bid_optimizers/${bidOptimizerId}`);
this.logger.debug(`Fetched Bid Optimizer: ${bidOptimizerId} - ${JSON.stringify(bidOptimizerResponse.data)}`);
return bidOptimizerResponse.data;
});
}
/**
*
* @param bidOptimizerId
*/
fetchBidOptimizerProperties(bidOptimizerId) {
const _super = name => super[name];
return __awaiter(this, void 0, void 0, function* () {
const bidOptimizerPropertyResponse = yield _super("requestGatewayHelper").call(this, "GET", `${this.outboundPlatformUrl}/v1/bid_optimizers/${bidOptimizerId}/properties`);
this.logger.debug(`Fetched Creative Properties: ${bidOptimizerId} - ${JSON.stringify(bidOptimizerPropertyResponse.data)}`);
return bidOptimizerPropertyResponse.data;
});
}
findBestSalesConditions(bidPrice, salesConditions) {
// Optimization, we only do the stringify if we are really on debug / silly mode
if (this.logger.level === "debug" || this.logger.level === "silly") {
this.logger.debug(`Looking to find the best sale condition for CPM: ${bidPrice} in: ${JSON.stringify(salesConditions, null, 4)}`);
}
const eligibleSalesConditions = salesConditions.filter(sc => {
return sc.floor_price <= bidPrice;
});
// Optimization, we only do the stringify if we are really on debug / silly mode
if (this.logger.level === "debug" || this.logger.level === "silly") {
this.logger.debug(`Found eligible sales condition for CPM: ${bidPrice} in: ${JSON.stringify(eligibleSalesConditions, null, 4)}`);
}
const sortedEligibleSalesConditions = eligibleSalesConditions.sort((a, b) => {
return a.floor_price - b.floor_price;
});
// Optimization, we only do the stringify if we are really on debug / silly mode
if (this.logger.level === "debug" || this.logger.level === "silly") {
this.logger.debug(`Sorted eligible sales condition for CPM: ${bidPrice} in: ${JSON.stringify(sortedEligibleSalesConditions, null, 4)}`);
}
return sortedEligibleSalesConditions[0];
}
/**
* Method to build an instance context
* To be overriden to get a cutom behavior
* This is a default provided implementation
* @param bidOptimizerId
*/
instanceContextBuilder(bidOptimizerId) {
return __awaiter(this, void 0, void 0, function* () {
const bidOptimizerP = this.fetchBidOptimizer(bidOptimizerId);
const bidOptimizerPropsP = this.fetchBidOptimizerProperties(bidOptimizerId);
const results = yield Promise.all([bidOptimizerP, bidOptimizerPropsP]);
const bidOptimizer = results[0];
const bidOptimizerProps = results[1];
const context = {
bidOptimizer: bidOptimizer,
bidOptimizerProperties: bidOptimizerProps
};
return context;
});
}
initBidDecisions() {
this.app.post("/v1/bid_decisions", this.asyncMiddleware((req, res) => __awaiter(this, void 0, void 0, function* () {
if (!req.body || _.isEmpty(req.body)) {
const msg = {
error: "Missing request body"
};
this.logger.error("POST /v1/bid_decisions : %s", JSON.stringify(msg));
return res.status(500).json(msg);
}
else {
if (this.logger.level === "debug" ||
this.logger.level === "silly") {
this.logger.debug(`POST /v1/bid_decisions ${JSON.stringify(req.body)}`);
}
const bidOptimizerRequest = req.body;
if (!this.onBidDecisions) {
const errMsg = "No BidOptimizer listener registered!";
this.logger.error(errMsg);
return res.status(500).json({ error: errMsg });
}
if (!this.pluginCache.get(bidOptimizerRequest.campaign_info.bid_optimizer_id)) {
this.pluginCache.put(bidOptimizerRequest.campaign_info.bid_optimizer_id, this.instanceContextBuilder(bidOptimizerRequest.campaign_info.bid_optimizer_id), this.INSTANCE_CONTEXT_CACHE_EXPIRATION);
} // We init the specific route to listen for bid decisions requests
const instanceContext = yield this.pluginCache.get(bidOptimizerRequest.campaign_info.bid_optimizer_id);
const bidOptimizerResponse = yield this.onBidDecisions(bidOptimizerRequest, instanceContext);
if (this.logger.level === "debug" ||
this.logger.level === "silly") {
this.logger.debug(`Returning: ${JSON.stringify(bidOptimizerResponse)}`);
}
return res.status(200).send(JSON.stringify(bidOptimizerResponse));
}
})));
}
constructor() {
super();
this.initBidDecisions();
this.setErrorHandler();
}
}
exports.BidOptimizerPlugin = BidOptimizerPlugin;