// Copyright 2018-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import EventEmitter from 'events'; import * as log from './logging/log'; import { clearTimeoutIfNecessary } from './util/clearTimeoutIfNecessary'; const POLL_INTERVAL_MS = 5 * 1000; const IDLE_THRESHOLD_MS = 20; export class IdleDetector extends EventEmitter { private handle: undefined | ReturnType; private timeoutId: undefined | ReturnType; public start(): void { log.info('Start idle detector'); this.scheduleNextCallback(); } public stop(): void { if (!this.handle) { return; } log.info('Stop idle detector'); this.clearScheduledCallbacks(); } private clearScheduledCallbacks() { if (this.handle) { cancelIdleCallback(this.handle); delete this.handle; } clearTimeoutIfNecessary(this.timeoutId); delete this.timeoutId; } private scheduleNextCallback() { this.clearScheduledCallbacks(); this.handle = window.requestIdleCallback(deadline => { const { didTimeout } = deadline; const timeRemaining = deadline.timeRemaining(); const isIdle = timeRemaining >= IDLE_THRESHOLD_MS; this.timeoutId = setTimeout( () => this.scheduleNextCallback(), POLL_INTERVAL_MS ); if (isIdle || didTimeout) { this.emit('idle', { timestamp: Date.now(), didTimeout, timeRemaining }); } }); } }