UNPKG

homebridge-tsvesync

Version:

Homebridge plugin for VeSync devices including Levoit air purifiers, humidifiers, and Etekcity smart outlets

154 lines 5.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QuotaManager = void 0; /** * Manages API call quotas to prevent exceeding VeSync's daily limits * Based on the formula: 3200 + 1500 * (number of devices) */ class QuotaManager { constructor(logger, deviceCount = 0, config) { var _a, _b; this.logger = logger; this.deviceCount = deviceCount; this.apiCallCount = 0; this.dailyQuota = 0; this.BASE_QUOTA = 3200; this.DEVICE_QUOTA_MULTIPLIER = 1500; this.lastQuotaLogTime = 0; this.QUOTA_LOG_INTERVAL = 30 * 60 * 1000; // 30 minutes in milliseconds // Set default buffer percentage (95% of quota) this.QUOTA_BUFFER = ((_a = config === null || config === void 0 ? void 0 : config.bufferPercentage) !== null && _a !== void 0 ? _a : 95) / 100; // Set default high priority methods this.HIGH_PRIORITY_METHODS = (_b = config === null || config === void 0 ? void 0 : config.priorityMethods) !== null && _b !== void 0 ? _b : [ 'turnOn', 'turnOff', 'setMode', 'setTargetHumidity', 'setBrightness', 'setColorTemperature', 'setColor', 'changeFanSpeed', 'setOscillation', 'setChildLock' ]; // Initialize with today's date this.lastResetDate = this.getCurrentDate(); this.calculateDailyQuota(); this.logger.info(`Initialized QuotaManager with ${this.deviceCount} devices. Daily quota: ${this.dailyQuota} API calls`); } /** * Calculate the daily quota based on the number of devices */ calculateDailyQuota() { this.dailyQuota = Math.floor((this.BASE_QUOTA + (this.DEVICE_QUOTA_MULTIPLIER * this.deviceCount)) * this.QUOTA_BUFFER); } /** * Get the current date in YYYY-MM-DD format */ getCurrentDate() { const now = new Date(); return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`; } /** * Check if the quota should be reset (new day) */ checkAndResetQuota() { const currentDate = this.getCurrentDate(); if (currentDate !== this.lastResetDate) { this.logger.info(`Resetting API call quota. Previous: ${this.apiCallCount}/${this.dailyQuota}`); this.apiCallCount = 0; this.lastResetDate = currentDate; } } /** * Update the device count and recalculate the quota */ updateDeviceCount(count) { if (this.deviceCount !== count) { this.deviceCount = count; this.calculateDailyQuota(); this.logger.info(`Updated device count to ${count}. New daily quota: ${this.dailyQuota} API calls`); } } /** * Check if an API call can be made based on the current quota */ canMakeApiCall(methodName) { this.checkAndResetQuota(); // If we're under the quota, allow the call if (this.apiCallCount < this.dailyQuota) { return true; } // If we're at or over the quota, only allow high priority methods const isHighPriority = this.HIGH_PRIORITY_METHODS.includes(methodName); if (isHighPriority) { this.logger.warn(`Quota exceeded (${this.apiCallCount}/${this.dailyQuota}) but allowing high priority method: ${methodName}`); return true; } // Log at WARN level as requested by user this.logger.warn(`Quota exceeded (${this.apiCallCount}/${this.dailyQuota}). Blocking API call: ${methodName}`, { skippedMethod: methodName }); return false; } /** * Record an API call */ recordApiCall(methodName) { this.checkAndResetQuota(); this.apiCallCount++; // Log when approaching quota limits const quotaPercentage = (this.apiCallCount / this.dailyQuota) * 100; if (quotaPercentage >= 90 && quotaPercentage < 95) { this.logger.warn(`API call quota at 90%: ${this.apiCallCount}/${this.dailyQuota}`); } else if (quotaPercentage >= 95 && quotaPercentage < 100) { this.logger.warn(`API call quota at 95%: ${this.apiCallCount}/${this.dailyQuota}`); } else if (quotaPercentage >= 100) { this.logger.error(`API call quota exceeded: ${this.apiCallCount}/${this.dailyQuota}`); } else if (this.apiCallCount % 100 === 0) { // Log every 100 calls for monitoring this.logger.debug(`API call count: ${this.apiCallCount}/${this.dailyQuota} (${quotaPercentage.toFixed(1)}%)`); } // Log remaining quota every 5 minutes this.logRemainingQuota(); } /** * Log the remaining quota every 5 minutes */ logRemainingQuota() { const now = Date.now(); if (now - this.lastQuotaLogTime >= this.QUOTA_LOG_INTERVAL) { const remaining = this.getRemainingQuota(); const percentage = this.getQuotaUsagePercentage(); this.logger.warn(`Daily quota status: ${this.apiCallCount}/${this.dailyQuota} calls used (${percentage.toFixed(1)}%). Remaining: ${remaining} calls.`); this.lastQuotaLogTime = now; } } /** * Get the current API call count */ getApiCallCount() { return this.apiCallCount; } /** * Get the daily quota */ getDailyQuota() { return this.dailyQuota; } /** * Get the remaining quota */ getRemainingQuota() { return Math.max(0, this.dailyQuota - this.apiCallCount); } /** * Get the quota usage percentage */ getQuotaUsagePercentage() { return (this.apiCallCount / this.dailyQuota) * 100; } } exports.QuotaManager = QuotaManager; //# sourceMappingURL=quota-manager.js.map