From 0684c1b9d34ffdee103bfee9f0cdb0697e04f7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Wed, 5 Jul 2017 19:08:19 +0200 Subject: [PATCH] Work in progress: get timeout from redis --- lib/cartodb/api/user_limits_api.js | 88 ++++++++++++++++--- .../provider/create-layergroup-provider.js | 2 +- .../mapconfig/provider/map-store-provider.js | 2 +- .../mapconfig/provider/named-map-provider.js | 2 +- test/acceptance/user-timeout-limit.js | 82 +++++++++++++++++ 5 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 test/acceptance/user-timeout-limit.js diff --git a/lib/cartodb/api/user_limits_api.js b/lib/cartodb/api/user_limits_api.js index ae9cd46b..7f244e7d 100644 --- a/lib/cartodb/api/user_limits_api.js +++ b/lib/cartodb/api/user_limits_api.js @@ -1,3 +1,5 @@ +var step = require('step'); + /** * * @param metadataBackend @@ -13,16 +15,82 @@ function UserLimitsApi(metadataBackend, options) { module.exports = UserLimitsApi; -UserLimitsApi.prototype.getRenderLimits = function (username, callback) { +UserLimitsApi.prototype.getRenderLimits = function (username, apiKey, callback) { var self = this; - this.metadataBackend.getTilerRenderLimit(username, function handleTilerLimits(err, renderLimit) { - if (err) { - return callback(err); - } - return callback(null, { - cacheOnTimeout: self.options.limits.cacheOnTimeout || false, - render: renderLimit || self.options.limits.render || 0 - }); - }); + var limits = { + cacheOnTimeout: self.options.limits.cacheOnTimeout || false, + render: self.options.limits.render || 0 + }; + + step( + function getTilerLimit() { + var next = this; + self.getTilerRenderLimit(username, function (err, tilerRenderLimit) { + if (err) { + return callback(err); + } + + if (Number.isFinite(tilerRenderLimit)) { + limits.render = tilerRenderLimit; + return callback(null, limits); + } + + return next(); + }); + }, + function getTimeoutLimit() { + self.getTimeoutRenderLimit(username, apiKey, function (err, timeoutRenderLimit) { + if (err) { + return callback(err); + } + + if (timeoutRenderLimit && timeoutRenderLimit.render) { + if (Number.isFinite(timeoutRenderLimit.render)) { + limits.render = timeoutRenderLimit.render; + } + } + + return callback(null, limits); + }); + } + ); +}; + +UserLimitsApi.prototype.getTilerRenderLimit = function (username, callback) { + this.metadataBackend.getTilerRenderLimit(username, callback); +}; + +UserLimitsApi.prototype.getTimeoutRenderLimit = function (username, apiKey, callback) { + var self = this; + + step( + function isAuthorized() { + var next = this; + + if (!apiKey) { + return next(null, false); + } + + self.metadataBackend.getUserMapKey(username, function (err, userApiKey) { + if (err) { + return next(err); + } + + return next(null, userApiKey === apiKey); + }); + }, + function getUserTimeoutRenderLimits(err, authorized) { + if (err) { + return next(err); + } + self.metadataBackend.getUserTimeoutRenderLimits(username, authorized, this); + }, + function setTilerRenderLimit(err, timeoutRenderLimit) { + if (err) { + return callback(err); + } + return callback(null, timeoutRenderLimit); + } + ); }; diff --git a/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js b/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js index af5a775b..340073b5 100644 --- a/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js +++ b/lib/cartodb/models/mapconfig/provider/create-layergroup-provider.js @@ -26,7 +26,7 @@ CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) { var context = {}; step( function prepareContextLimits() { - self.userLimitsApi.getRenderLimits(self.user, this); + self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this); }, function handleRenderLimits(err, renderLimits) { assert.ifError(err); diff --git a/lib/cartodb/models/mapconfig/provider/map-store-provider.js b/lib/cartodb/models/mapconfig/provider/map-store-provider.js index c07f9abc..177322d4 100644 --- a/lib/cartodb/models/mapconfig/provider/map-store-provider.js +++ b/lib/cartodb/models/mapconfig/provider/map-store-provider.js @@ -27,7 +27,7 @@ MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) { var context = {}; step( function prepareContextLimits() { - self.userLimitsApi.getRenderLimits(self.user, this); + self.userLimitsApi.getRenderLimits(self.user, self.params.api_key, this); }, function handleRenderLimits(err, renderLimits) { assert.ifError(err); diff --git a/lib/cartodb/models/mapconfig/provider/named-map-provider.js b/lib/cartodb/models/mapconfig/provider/named-map-provider.js index 594ec247..17c66c29 100644 --- a/lib/cartodb/models/mapconfig/provider/named-map-provider.js +++ b/lib/cartodb/models/mapconfig/provider/named-map-provider.js @@ -114,7 +114,7 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) { function prepareContextLimits(err, _mapConfig) { assert.ifError(err); mapConfig = _mapConfig; - self.userLimitsApi.getRenderLimits(self.owner, this); + self.userLimitsApi.getRenderLimits(self.owner, self.params.api_key, this); }, function cacheAndReturnMapConfig(err, renderLimits) { self.err = err; diff --git a/test/acceptance/user-timeout-limit.js b/test/acceptance/user-timeout-limit.js new file mode 100644 index 00000000..b595cd0e --- /dev/null +++ b/test/acceptance/user-timeout-limit.js @@ -0,0 +1,82 @@ +require('../support/test_helper'); + +var assert = require('../support/assert'); +var TestClient = require('../support/test-client'); +var testHelper = require('../support/test_helper'); + +var redis = require('redis'); +var keysToDelete; + +function withUserTimeoutRenderLimit(redisClient, user, userTimeoutLimit, callback) { + redisClient.SELECT(5, function(err) { + if (err) { + return callback(err); + } + + var userTimeoutLimitsKey = 'limits:timeout:' + user; + var redisParams = [ + userTimeoutLimitsKey, + 'render', userTimeoutLimit, + 'render_public', userTimeoutLimit + ]; + + redisClient.hmset(redisParams, function (err) { + if (err) { + return callback(err); + } + keysToDelete[userTimeoutLimitsKey] = 5; + return callback(); + }); + }); +} + +function createMapConfig (cartocss) { + return { + version: '1.6.0', + layers: [{ + type: "cartodb", + options: { + sql: [ + 'SELECT', + ' pg_sleep(1),', + ' 1 cartodb_id,', + ' \'SRID=3857;POINT(0 0)\'::geometry the_geom_webmercator' + ].join('\n'), + cartocss: cartocss, + cartocss_version: '2.3.0', + interactivity: 'cartodb_id' + } + }] + }; +} + + + +describe('user timeout limits', function () { + var redisClient = redis.createClient(global.environment.redis.port); + + beforeEach(function() { + keysToDelete = {}; + }); + + afterEach(function (done) { + testHelper.deleteRedisKeys(keysToDelete, done); + }); + + it('layergroup creation works even if test tile is slow', function (done) { + withUserTimeoutRenderLimit(redisClient, 'localhost', 1, function (err) { + if (err) { + return done(err); + } + + var mapConfig = createMapConfig(TestClient.CARTOCSS.POINTS); + var testClient = new TestClient(mapConfig, 1234); + testClient.getTile(4, 4, 4, {}, function (err, res, tile) { + assert.ok(err, err); + // TODO: check timeout tile + + testClient.drain(done) + }); + }); + }); +});