UNPKG

@ronniepettersson/homebridge-dummy

Version:

Create Homebridge accessories to help with automation and control — scheduling, delays, sensors, commands, webhooks, and more

147 lines 5.49 kB
import { DAY, getDelay, HOUR, MINUTE, SECOND, Timeout } from './timeout.js'; import { strings } from '../i18n/i18n.js'; import { isValidTimeUnits, printableValues, TimePeriod, TimeUnits } from '../model/enums.js'; import { Storage } from '../tools/storage.js'; import { assert } from '../tools/validation.js'; export default class Limiter extends Timeout { config; static new(config, caller, log, disableLogging) { if (!assert(log, caller, config, 'limit', 'units', 'period')) { return; } if (!isValidTimeUnits(config.units)) { log.error(strings.limiter.badUnits, caller, `'${config.units}'`, printableValues(TimeUnits)); return; } let periodLength; switch (config.period) { case TimePeriod.HOUR: periodLength = HOUR; break; case TimePeriod.DAY: periodLength = DAY; break; case TimePeriod.WEEK: periodLength = 7 * DAY; break; case TimePeriod.MONTH: periodLength = 31 * DAY; break; default: log.error(strings.limiter.badPeriod, caller, `'${config.period}'`, printableValues(TimePeriod)); return; } const delay = getDelay(config.limit, config.units); if (delay > periodLength) { log.error(strings.limiter.limitExceedsPeriod, caller); return; } return new Limiter(config, caller, log, disableLogging); } limit = { timeRemaining: -1, resetTimestamp: -1, startTimestamp: undefined }; constructor(config, caller, log, disableLogging) { super(caller, log, disableLogging); this.config = config; const cache = Storage.get(this.limitStorageKey); if (cache === undefined) { return; } this.limit = cache; if (this.limit.startTimestamp === undefined) { return; } const elapsedTime = Date.now() - this.limit.startTimestamp; this.limit.timeRemaining = Math.max(0, this.limit.timeRemaining - elapsedTime); } get limitStorageKey() { const identifier = this.config.id ?? this.caller; return `${identifier}:Limit`; } start(callback) { if (Date.now() - this.limit.resetTimestamp >= 0 || this.limit.timeRemaining === -1) { this.resetTimeRemaining(); this.resetPeriod(); } const timeUntilPeriodReset = this.limit.resetTimestamp - Date.now(); if (this.limit.timeRemaining > timeUntilPeriodReset) { this.resetTimeRemaining(); this.limit.timeRemaining += timeUntilPeriodReset; } if (this.limit.timeRemaining > 0) { this.logTimeRemaining(); this.limit.startTimestamp = Date.now(); this.storeLimit(); } this.timeout = setTimeout(async () => { this.reset(); await callback(); }, Math.max(this.limit.timeRemaining, 0.1 * SECOND)); } cancel() { if (!this.limit.startTimestamp) { return; } super.cancel(); } reset() { super.reset(); if (this.limit.startTimestamp !== undefined) { const elapsedTime = Date.now() - this.limit.startTimestamp; this.limit.timeRemaining = Math.max(0, this.limit.timeRemaining - elapsedTime); this.limit.startTimestamp = undefined; this.storeLimit(); } this.logTimeRemaining(); } teardown() { super.reset(); } resetTimeRemaining() { this.limit.timeRemaining = this.getDelay(this.config.limit, this.config.units); } resetPeriod() { const date = new Date(); switch (this.config.period) { case TimePeriod.HOUR: date.setHours(date.getHours() + 1, 0, 0, 0); break; case TimePeriod.DAY: date.setDate(date.getDate() + 1); date.setHours(0, 0, 0, 0); break; case TimePeriod.WEEK: date.setDate(date.getDate() + ((7 - date.getDay()) % 7 || 7)); date.setHours(0, 0, 0, 0); break; case TimePeriod.MONTH: date.setMonth(date.getMonth() + 1, 1); date.setHours(0, 0, 0, 0); break; } this.limit.resetTimestamp = date.getTime(); } storeLimit() { Storage.set(this.limitStorageKey, this.limit); } logTimeRemaining() { if (this.limit.timeRemaining < 0) { return; } if (this.limit.timeRemaining === 0) { this.logIfDesired(strings.limiter.expired); } else if (this.limit.timeRemaining < MINUTE) { this.logIfDesired(strings.limiter.remainingSeconds, Math.round(this.limit.timeRemaining / SECOND)); } else if (this.limit.timeRemaining < HOUR) { this.logIfDesired(strings.limiter.remainingMinutes, Math.round(this.limit.timeRemaining / MINUTE)); } else if (this.limit.timeRemaining < DAY) { this.logIfDesired(strings.limiter.remainingHours, Math.round(this.limit.timeRemaining / HOUR)); } else { this.logIfDesired(strings.limiter.remainingDayPlus); } } } //# sourceMappingURL=limiter.js.map