@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
JavaScript
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