// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only const SECOND = 1000; export const FIBONACCI_TIMEOUTS: ReadonlyArray = [ 1 * SECOND, 2 * SECOND, 3 * SECOND, 5 * SECOND, 8 * SECOND, 13 * SECOND, 21 * SECOND, 34 * SECOND, 55 * SECOND, ]; export type BackOffOptionsType = Readonly<{ jitter?: number; // Testing random?: () => number; }>; const DEFAULT_RANDOM = () => Math.random(); export class BackOff { private count = 0; constructor( private readonly timeouts: ReadonlyArray, private readonly options: BackOffOptionsType = {} ) {} public get(): number { let result = this.timeouts[this.count]; const { jitter = 0, random = DEFAULT_RANDOM } = this.options; // Do not apply jitter larger than the timeout value. It is supposed to be // activated for longer timeouts. if (jitter < result) { result += random() * jitter; } return result; } public getAndIncrement(): number { const result = this.get(); if (!this.isFull()) { this.count += 1; } return result; } public reset(): void { this.count = 0; } public isFull(): boolean { return this.count === this.timeouts.length - 1; } public getIndex(): number { return this.count; } }