@tiledesk/tiledesk-server
Version:
The Tiledesk server module
116 lines (93 loc) • 3.27 kB
JavaScript
const project = require("../models/project");
class RateManager {
constructor(config) {
if (!config) {
throw new Error('config is mandatory')
}
if (!config.tdCache) {
throw new Error('config.tdCache is mandatory')
}
this.tdCache = config.tdCache;
// Default rates
this.defaultRates = {
webhook: {
capacity: parseInt(process.env.BUCKET_WH_CAPACITY) || 10,
refill_rate: (parseInt(process.env.BUCKET_WH_REFILL_RATE_PER_MIN) || 10) / 60
},
message: {
capacity: parseInt(process.env.BUCKET_MSG_CAPACITY) || 100,
refill_rate: (parseInt(process.env.BUCKET_MSG_REFILL_RATE_PER_MIN) || 100) / 60
},
block: {
capacity: parseInt(process.env.BUCKET_BLK_CAPACITY) || 100,
refill_rate: (parseInt(process.env.BUCKET_BLK_REFILL_RATE_PER_MIN) || 100) / 60
}
}
}
async canExecute(projectOrId, id, type) {
let project = projectOrId;
if (typeof projectOrId === 'string') {
project = await this.loadProject(projectOrId);
id = projectOrId;
}
const config = await this.getRateConfig(project, type);
const key = `bucket:${type}:${id}`
let bucket = await this.getBucket(key, type, project);
let current_tokens = bucket.tokens;
let elapsed = (new Date() - new Date(bucket.timestamp)) / 1000;
let tokens = Math.min(config.capacity, current_tokens + (elapsed * config.refill_rate));
if (tokens > 0) {
tokens -= 1;
bucket.tokens = tokens;
bucket.timestamp = new Date();
this.setBucket(key, bucket)
return true;
} else {
bucket.timestamp = new Date();
return false;
}
}
async getRateConfig(project, type) {
const baseConfig = this.defaultRates[type];
if (!project) {
return baseConfig;
}
const custom = project?.profile?.customization?.rates?.[type];
if (!custom) {
return baseConfig;
}
return {
...baseConfig,
...custom
}
}
async setBucket(key, bucket) {
const bucket_string = JSON.stringify(bucket);
await this.tdCache.set(key, bucket_string, { EX: 600 });
}
async getBucket(key, type, project) {
let bucket = await this.tdCache.get(key);
if (bucket) {
return JSON.parse(bucket);
}
bucket = await this.createBucket(type, project);
return bucket;
}
async createBucket(type, project) {
const config = await this.getRateConfig(project, type)
return {
tokens: config.capacity,
timestamp: new Date()
}
}
async loadProject(id_project) {
// Hint: implement redis cache also for project
try {
return project.findById(id_project);
} catch (err) {
winston.error("(RateManager) Error getting project ", err);
return null;
}
}
}
module.exports = RateManager;