UNPKG

@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
"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;