67 lines
1.3 KiB
TypeScript
67 lines
1.3 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
const SECOND = 1000;
|
|
|
|
export const FIBONACCI_TIMEOUTS: ReadonlyArray<number> = [
|
|
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<number>,
|
|
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;
|
|
}
|
|
}
|