UNPKG

@tiledesk/tiledesk-server

Version:
116 lines (93 loc) 3.27 kB
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;