UNPKG

microgateway-plugins

Version:
148 lines (118 loc) 4.74 kB
'use strict'; // QUOTA // module: microgateway-plugins/quota var async = require('async'); var Quota = require('volos-quota-apigee'); var debug = require('debug')('gateway:quota'); var url = require('url'); module.exports.init = function(config /*, logger, stats */) { const { product_to_proxy, proxies } = config; const prodsObj = {}; var quotas = {}; // productName -> connectMiddleware var options = { key: function(req) { return req.token.application_name; } }; var quotaManagers = {} if ( (product_to_proxy === undefined) || (proxies === undefined) ) { // debug("quota plugin did not recieve valid produc-proxy map or list of proxies") return(undefined) } Object.keys(config).forEach(function(productName) { var product = config[productName]; if (!product.uri && !product.key && !product.secret && !product.allow && !product.interval || product.interval === "null") { // skip non-quota config debug('Quota not configured on the API product, skipping. This message is safe to ignore'); return; } if ( product.timeUnit === 'month' ) { //product.timeUnit = '30days'; // this is broken - volos does not consider 30days as an option, but tries to process it anyway. } const prodProxiesArr = product_to_proxy[productName]; const prodObj = {}; if (Array.isArray(prodProxiesArr)) { prodProxiesArr.reduce((acc, val) => { acc[val] = true; return acc; }, prodObj); } const basePaths = {}; if (Array.isArray(proxies)) { proxies.reduce((acc, prox) => { if (prox.name !== 'edgemicro-auth' && prodObj[prox.name] === true) acc[prox.base_path] = true; return acc; }, basePaths); } prodObj.basePaths = basePaths; prodsObj[productName] = prodObj; config[productName].request = config.request; var quota = Quota.create(config[productName]); quotas[productName] = quota.connectMiddleware().apply(options); // quotaManagers[productName] = quota; debug('created quota for', productName); }); var middleware = function(req, res, next) { if (!req.token || !req.token.api_product_list || !req.token.api_product_list.length) { return next(); } debug('quota checking products', req.token.api_product_list); req.originalUrl = req.originalUrl || req.url; // emulate connect let proxyPath = res.proxy ? res.proxy.base_path : undefined; let proxyUrl = req.url ? url.parse(req.url).pathname : undefined; let matchedPathProxy = proxyPath || proxyUrl || ''; debug('matchedPathProxy',matchedPathProxy); const prodList = []; if (Array.isArray(req.token.api_product_list)) { req.token.api_product_list.reduce((acc, prod) => { if (prodsObj[prod] && prodsObj[prod].basePaths && prodsObj[prod].basePaths[matchedPathProxy] === true) acc.push(prod); return acc; }, prodList); debug('prodList', prodList); } // this is arbitrary, but not sure there's a better way? // async.eachSeries(req.token.api_product_list, async.eachSeries(prodList, function(productName, cb) { var connectMiddleware = quotas[productName]; debug('applying quota for', productName); if ( connectMiddleware ){ connectMiddleware(req, res, cb) } else cb(); }, function(err) { next(err); } ); } return { testprobe: function() { return quotas }, onrequest: function(req, res, next) { if ( process.env.EDGEMICRO_LOCAL !== undefined ) { debug("MG running in local mode. Skipping Quota"); next(); } else { middleware(req, res, next); } }, shutdown: function() { // look for extant timers ... for global graceful shutdown... for ( var qmKey in quotaManagers ) { var q = quotaManagers[qmKey]; if ( q.quota ) { q = q.quota; } if ( q.bucketTimer ) { clearInterval(q.bucketTimer) } if ( q.flushTimer ) { clearInterval(q.flushTimer) } } } } };