Add `durations` utility for computing durations

This commit is contained in:
Evan Hahn 2021-08-26 09:10:58 -05:00 committed by GitHub
parent c6aa668a9b
commit f86f753df9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 99 additions and 95 deletions

View File

@ -19,6 +19,7 @@ import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings';
import { SocketStatus } from './types/SocketStatus'; import { SocketStatus } from './types/SocketStatus';
import { DEFAULT_CONVERSATION_COLOR } from './types/Colors'; import { DEFAULT_CONVERSATION_COLOR } from './types/Colors';
import { ChallengeHandler } from './challenge'; import { ChallengeHandler } from './challenge';
import * as durations from './util/durations';
import { isWindowDragElement } from './util/isWindowDragElement'; import { isWindowDragElement } from './util/isWindowDragElement';
import { assert, strictAssert } from './util/assert'; import { assert, strictAssert } from './util/assert';
import { dropNull } from './util/dropNull'; import { dropNull } from './util/dropNull';
@ -2261,7 +2262,7 @@ export async function startApp(): Promise<void> {
window.SignalContext.nativeThemeListener.subscribe(themeChanged); window.SignalContext.nativeThemeListener.subscribe(themeChanged);
const FIVE_MINUTES = 5 * 60 * 1000; const FIVE_MINUTES = 5 * durations.MINUTE;
// Note: once this function returns, there still might be messages being processed on // Note: once this function returns, there still might be messages being processed on
// a given conversation's queue. But we have processed all events from the websocket. // a given conversation's queue. But we have processed all events from the websocket.

View File

@ -23,6 +23,7 @@ import dataInterface from './sql/Client';
import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64'; import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64';
import { assert, strictAssert } from './util/assert'; import { assert, strictAssert } from './util/assert';
import { isMoreRecentThan } from './util/timestamp'; import { isMoreRecentThan } from './util/timestamp';
import * as durations from './util/durations';
import { normalizeUuid } from './util/normalizeUuid'; import { normalizeUuid } from './util/normalizeUuid';
import { dropNull } from './util/dropNull'; import { dropNull } from './util/dropNull';
import { import {
@ -1252,9 +1253,8 @@ export async function modifyGroupV2({
); );
} }
const ONE_MINUTE = 1000 * 60;
const startTime = Date.now(); const startTime = Date.now();
const timeoutTime = startTime + ONE_MINUTE; const timeoutTime = startTime + durations.MINUTE;
const MAX_ATTEMPTS = 5; const MAX_ATTEMPTS = 5;
@ -2723,7 +2723,7 @@ type MaybeUpdatePropsType = {
force?: boolean; force?: boolean;
}; };
const FIVE_MINUTES = 1000 * 60 * 5; const FIVE_MINUTES = 5 * durations.MINUTE;
export async function waitThenMaybeUpdateGroup( export async function waitThenMaybeUpdateGroup(
options: MaybeUpdatePropsType, options: MaybeUpdatePropsType,

View File

@ -4,7 +4,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import * as z from 'zod'; import * as z from 'zod';
import * as moment from 'moment'; import * as durations from '../util/durations';
import type { LoggerType } from '../logging/log'; import type { LoggerType } from '../logging/log';
import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff';
import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob';
@ -12,7 +12,7 @@ import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob';
import { JobQueue } from './JobQueue'; import { JobQueue } from './JobQueue';
import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore';
const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); const MAX_RETRY_TIME = durations.DAY;
const readSyncJobDataSchema = z.object({ const readSyncJobDataSchema = z.object({
readSyncs: z.array( readSyncs: z.array(

View File

@ -3,7 +3,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import * as z from 'zod'; import * as z from 'zod';
import * as moment from 'moment'; import * as durations from '../util/durations';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { waitForOnline } from '../util/waitForOnline'; import { waitForOnline } from '../util/waitForOnline';
import { isDone as isDeviceLinked } from '../util/registration'; import { isDone as isDeviceLinked } from '../util/registration';
@ -16,7 +16,7 @@ import { jobQueueDatabaseStore } from './JobQueueDatabaseStore';
import { parseIntWithFallback } from '../util/parseIntWithFallback'; import { parseIntWithFallback } from '../util/parseIntWithFallback';
import type { WebAPIType } from '../textsecure/WebAPI'; import type { WebAPIType } from '../textsecure/WebAPI';
const RETRY_WAIT_TIME = moment.duration(1, 'minute').asMilliseconds(); const RETRY_WAIT_TIME = durations.MINUTE;
const RETRYABLE_4XX_FAILURE_STATUSES = new Set([ const RETRYABLE_4XX_FAILURE_STATUSES = new Set([
404, 404,
408, 408,

View File

@ -4,7 +4,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import * as z from 'zod'; import * as z from 'zod';
import * as moment from 'moment'; import * as durations from '../util/durations';
import type { LoggerType } from '../logging/log'; import type { LoggerType } from '../logging/log';
import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff';
import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob';
@ -12,7 +12,7 @@ import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob';
import { JobQueue } from './JobQueue'; import { JobQueue } from './JobQueue';
import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore';
const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); const MAX_RETRY_TIME = durations.DAY;
const viewSyncJobDataSchema = z.object({ const viewSyncJobDataSchema = z.object({
viewSyncs: z.array( viewSyncs: z.array(

View File

@ -4,7 +4,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import { z } from 'zod'; import { z } from 'zod';
import * as moment from 'moment'; import * as durations from '../util/durations';
import type { LoggerType } from '../logging/log'; import type { LoggerType } from '../logging/log';
import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff';
import { commonShouldJobContinue } from './helpers/commonShouldJobContinue'; import { commonShouldJobContinue } from './helpers/commonShouldJobContinue';
@ -14,7 +14,7 @@ import { JobQueue } from './JobQueue';
import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore';
import { handleCommonJobRequestError } from './helpers/handleCommonJobRequestError'; import { handleCommonJobRequestError } from './helpers/handleCommonJobRequestError';
const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); const MAX_RETRY_TIME = durations.DAY;
const viewedReceiptsJobDataSchema = z.object({ const viewedReceiptsJobDataSchema = z.object({
viewedReceipt: z.object({ viewedReceipt: z.object({

View File

@ -5,6 +5,7 @@ import { isNumber, omit } from 'lodash';
import { v4 as getGuid } from 'uuid'; import { v4 as getGuid } from 'uuid';
import dataInterface from '../sql/Client'; import dataInterface from '../sql/Client';
import * as durations from '../util/durations';
import { downloadAttachment } from '../util/downloadAttachment'; import { downloadAttachment } from '../util/downloadAttachment';
import { stringFromBytes } from '../Crypto'; import { stringFromBytes } from '../Crypto';
import { import {
@ -28,15 +29,12 @@ const {
const MAX_ATTACHMENT_JOB_PARALLELISM = 3; const MAX_ATTACHMENT_JOB_PARALLELISM = 3;
const SECOND = 1000; const TICK_INTERVAL = durations.MINUTE;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const TICK_INTERVAL = MINUTE;
const RETRY_BACKOFF: Record<number, number> = { const RETRY_BACKOFF: Record<number, number> = {
1: 30 * SECOND, 1: 30 * durations.SECOND,
2: 30 * MINUTE, 2: 30 * durations.MINUTE,
3: 6 * HOUR, 3: 6 * durations.HOUR,
}; };
let enabled = false; let enabled = false;

View File

@ -56,6 +56,7 @@ import { sendReadReceiptsFor } from '../util/sendReadReceiptsFor';
import { updateConversationsWithUuidLookup } from '../updateConversationsWithUuidLookup'; import { updateConversationsWithUuidLookup } from '../updateConversationsWithUuidLookup';
import { ReadStatus } from '../messages/MessageReadStatus'; import { ReadStatus } from '../messages/MessageReadStatus';
import { SendStatus } from '../messages/MessageSendState'; import { SendStatus } from '../messages/MessageSendState';
import * as durations from '../util/durations';
import { import {
concat, concat,
filter, filter,
@ -106,8 +107,8 @@ const {
} = window.Signal.Migrations; } = window.Signal.Migrations;
const { addStickerPackReference } = window.Signal.Data; const { addStickerPackReference } = window.Signal.Data;
const THREE_HOURS = 3 * 60 * 60 * 1000; const THREE_HOURS = durations.HOUR * 3;
const FIVE_MINUTES = 1000 * 60 * 5; const FIVE_MINUTES = durations.MINUTE * 5;
const JOB_REPORTING_THRESHOLD_MS = 25; const JOB_REPORTING_THRESHOLD_MS = 25;

View File

@ -34,7 +34,6 @@ import {
BandwidthMode, BandwidthMode,
} from 'ringrtc'; } from 'ringrtc';
import { uniqBy, noop } from 'lodash'; import { uniqBy, noop } from 'lodash';
import * as moment from 'moment';
import { import {
ActionsType as UxActionsType, ActionsType as UxActionsType,
@ -63,6 +62,7 @@ import {
import { assert } from '../util/assert'; import { assert } from '../util/assert';
import { dropNull, shallowDropNull } from '../util/dropNull'; import { dropNull, shallowDropNull } from '../util/dropNull';
import { getOwn } from '../util/getOwn'; import { getOwn } from '../util/getOwn';
import * as durations from '../util/durations';
import { handleMessageSend } from '../util/handleMessageSend'; import { handleMessageSend } from '../util/handleMessageSend';
import { import {
fetchMembershipProof, fetchMembershipProof,
@ -99,9 +99,7 @@ const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map<
[HttpMethod.Delete, 'DELETE'], [HttpMethod.Delete, 'DELETE'],
]); ]);
const CLEAN_EXPIRED_GROUP_CALL_RINGS_INTERVAL = moment const CLEAN_EXPIRED_GROUP_CALL_RINGS_INTERVAL = 10 * durations.MINUTE;
.duration(10, 'minutes')
.asMilliseconds();
// We send group call update messages to tell other clients to peek, which triggers // We send group call update messages to tell other clients to peek, which triggers
// notifications, timeline messages, big green "Join" buttons, and so on. This enum // notifications, timeline messages, big green "Join" buttons, and so on. This enum

View File

@ -11,6 +11,7 @@ import {
} from '../util/zkgroup'; } from '../util/zkgroup';
import { GroupCredentialType } from '../textsecure/WebAPI'; import { GroupCredentialType } from '../textsecure/WebAPI';
import * as durations from '../util/durations';
import { BackOff } from '../util/BackOff'; import { BackOff } from '../util/BackOff';
import { sleep } from '../util/sleep'; import { sleep } from '../util/sleep';
@ -26,13 +27,8 @@ type NextCredentialsType = {
tomorrow: GroupCredentialType; tomorrow: GroupCredentialType;
}; };
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
function getTodayInEpoch() { function getTodayInEpoch() {
return Math.floor(Date.now() / DAY); return Math.floor(Date.now() / durations.DAY);
} }
let started = false; let started = false;
@ -48,15 +44,17 @@ export async function initializeGroupCredentialFetcher(): Promise<void> {
// Because we fetch eight days of credentials at a time, we really only need to run // Because we fetch eight days of credentials at a time, we really only need to run
// this about once a week. But there's no problem running it more often; it will do // this about once a week. But there's no problem running it more often; it will do
// nothing if no new credentials are needed, and will only request needed credentials. // nothing if no new credentials are needed, and will only request needed credentials.
await runWithRetry(maybeFetchNewCredentials, { scheduleAnother: 4 * HOUR }); await runWithRetry(maybeFetchNewCredentials, {
scheduleAnother: 4 * durations.HOUR,
});
} }
const BACKOFF_TIMEOUTS = [ const BACKOFF_TIMEOUTS = [
SECOND, durations.SECOND,
5 * SECOND, 5 * durations.SECOND,
30 * SECOND, 30 * durations.SECOND,
2 * MINUTE, 2 * durations.MINUTE,
5 * MINUTE, 5 * durations.MINUTE,
]; ];
export async function runWithRetry( export async function runWithRetry(

View File

@ -26,6 +26,7 @@ import {
} from './storageRecordOps'; } from './storageRecordOps';
import { ConversationModel } from '../models/conversations'; import { ConversationModel } from '../models/conversations';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import * as durations from '../util/durations';
import { BackOff } from '../util/BackOff'; import { BackOff } from '../util/BackOff';
import { handleMessageSend } from '../util/handleMessageSend'; import { handleMessageSend } from '../util/handleMessageSend';
import { storageJobQueue } from '../util/JobQueue'; import { storageJobQueue } from '../util/JobQueue';
@ -60,18 +61,19 @@ const validRecordTypes = new Set([
4, // ACCOUNT 4, // ACCOUNT
]); ]);
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const backOff = new BackOff([ const backOff = new BackOff([
SECOND, durations.SECOND,
5 * SECOND, 5 * durations.SECOND,
30 * SECOND, 30 * durations.SECOND,
2 * MINUTE, 2 * durations.MINUTE,
5 * MINUTE, 5 * durations.MINUTE,
]); ]);
const conflictBackOff = new BackOff([SECOND, 5 * SECOND, 30 * SECOND]); const conflictBackOff = new BackOff([
durations.SECOND,
5 * durations.SECOND,
30 * durations.SECOND,
]);
function redactStorageID(storageID: string): string { function redactStorageID(storageID: string): string {
return storageID.substring(0, 3); return storageID.substring(0, 3);
@ -1112,7 +1114,7 @@ async function upload(fromSync = false): Promise<void> {
if (uploadBucket.length >= 3) { if (uploadBucket.length >= 3) {
const [firstMostRecentWrite] = uploadBucket; const [firstMostRecentWrite] = uploadBucket;
if (isMoreRecentThan(5 * MINUTE, firstMostRecentWrite)) { if (isMoreRecentThan(5 * durations.MINUTE, firstMostRecentWrite)) {
throw new Error( throw new Error(
'storageService.uploadManifest: too many writes too soon.' 'storageService.uploadManifest: too many writes too soon.'
); );

View File

@ -29,6 +29,7 @@ import { arrayBufferToBase64, base64ToArrayBuffer } from '../Crypto';
import { CURRENT_SCHEMA_VERSION } from '../../js/modules/types/message'; import { CURRENT_SCHEMA_VERSION } from '../../js/modules/types/message';
import { createBatcher } from '../util/batcher'; import { createBatcher } from '../util/batcher';
import { assert } from '../util/assert'; import { assert } from '../util/assert';
import * as durations from '../util/durations';
import { cleanDataForIpc } from './cleanDataForIpc'; import { cleanDataForIpc } from './cleanDataForIpc';
import { ReactionType } from '../types/Reactions'; import { ReactionType } from '../types/Reactions';
import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ConversationColorType, CustomColorType } from '../types/Colors';
@ -82,7 +83,7 @@ if (ipcRenderer && ipcRenderer.setMaxListeners) {
window.log.warn('sql/Client: ipcRenderer is not available!'); window.log.warn('sql/Client: ipcRenderer is not available!');
} }
const DATABASE_UPDATE_TIMEOUT = 2 * 60 * 1000; // two minutes const DATABASE_UPDATE_TIMEOUT = 2 * durations.MINUTE;
const MIN_TRACE_DURATION = 10; const MIN_TRACE_DURATION = 10;

View File

@ -13,7 +13,6 @@ import mkdirp from 'mkdirp';
import rimraf from 'rimraf'; import rimraf from 'rimraf';
import SQL, { Database, Statement } from 'better-sqlite3'; import SQL, { Database, Statement } from 'better-sqlite3';
import pProps from 'p-props'; import pProps from 'p-props';
import * as moment from 'moment';
import { v4 as generateUUID } from 'uuid'; import { v4 as generateUUID } from 'uuid';
import { import {
@ -41,6 +40,7 @@ import { dropNull } from '../util/dropNull';
import { isNormalNumber } from '../util/isNormalNumber'; import { isNormalNumber } from '../util/isNormalNumber';
import { isNotNil } from '../util/isNotNil'; import { isNotNil } from '../util/isNotNil';
import { parseIntOrThrow } from '../util/parseIntOrThrow'; import { parseIntOrThrow } from '../util/parseIntOrThrow';
import * as durations from '../util/durations';
import { formatCountForLogging } from '../logging/formatCountForLogging'; import { formatCountForLogging } from '../logging/formatCountForLogging';
import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ConversationColorType, CustomColorType } from '../types/Colors';
import { ProcessGroupCallRingRequestResult } from '../types/Calling'; import { ProcessGroupCallRingRequestResult } from '../types/Calling';
@ -5965,7 +5965,7 @@ async function processGroupCallRingCancelation(ringId: bigint): Promise<void> {
// This age, in milliseconds, should be longer than any group call ring duration. Beyond // This age, in milliseconds, should be longer than any group call ring duration. Beyond
// that, it doesn't really matter what the value is. // that, it doesn't really matter what the value is.
const MAX_GROUP_CALL_RING_AGE = moment.duration(30, 'minutes').asMilliseconds(); const MAX_GROUP_CALL_RING_AGE = 30 * durations.MINUTE;
async function cleanExpiredGroupCallRings(): Promise<void> { async function cleanExpiredGroupCallRings(): Promise<void> {
const db = getInstance(); const db = getInstance();

View File

@ -1,18 +1,14 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import * as durations from '../../util/durations';
export type TestExpireTimer = Readonly<{ value: number; label: string }>; export type TestExpireTimer = Readonly<{ value: number; label: string }>;
const SECOND = 1;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
export const EXPIRE_TIMERS: ReadonlyArray<TestExpireTimer> = [ export const EXPIRE_TIMERS: ReadonlyArray<TestExpireTimer> = [
{ value: 42 * SECOND, label: '42 seconds' }, { value: 42 * durations.SECOND, label: '42 seconds' },
{ value: 5 * MINUTE, label: '5 minutes' }, { value: 5 * durations.MINUTE, label: '5 minutes' },
{ value: 1 * HOUR, label: '1 hour' }, { value: 1 * durations.HOUR, label: '1 hour' },
{ value: 6 * DAY, label: '6 days' }, { value: 6 * durations.DAY, label: '6 days' },
{ value: 3 * WEEK, label: '3 weeks' }, { value: 3 * durations.WEEK, label: '3 weeks' },
]; ];

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai'; import { assert } from 'chai';
import * as moment from 'moment'; import * as durations from '../../util/durations';
import { import {
exponentialBackoffSleepTime, exponentialBackoffSleepTime,
@ -20,7 +20,7 @@ describe('exponential backoff utilities', () => {
}); });
it('plateaus at a maximum after 15 attempts', () => { it('plateaus at a maximum after 15 attempts', () => {
const maximum = moment.duration(15, 'minutes').asMilliseconds(); const maximum = 15 * durations.MINUTE;
for (let attempt = 16; attempt < 100; attempt += 1) { for (let attempt = 16; attempt < 100; attempt += 1) {
assert.strictEqual(exponentialBackoffSleepTime(attempt), maximum); assert.strictEqual(exponentialBackoffSleepTime(attempt), maximum);
} }
@ -39,8 +39,7 @@ describe('exponential backoff utilities', () => {
it('returns 110 attempts for 1 day', () => { it('returns 110 attempts for 1 day', () => {
// This is a test case that is lifted from iOS's codebase. // This is a test case that is lifted from iOS's codebase.
const oneDay = moment.duration(24, 'hours').asMilliseconds(); assert.strictEqual(exponentialBackoffMaxAttempts(durations.DAY), 110);
assert.strictEqual(exponentialBackoffMaxAttempts(oneDay), 110);
}); });
}); });
}); });

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai'; import { assert } from 'chai';
import * as durations from '../../util/durations';
import { isConversationUnregistered } from '../../util/isConversationUnregistered'; import { isConversationUnregistered } from '../../util/isConversationUnregistered';
@ -33,12 +34,10 @@ describe('isConversationUnregistered', () => {
}); });
it('returns false if passed a time more than 6 hours ago', () => { it('returns false if passed a time more than 6 hours ago', () => {
const oneMinute = 1000 * 60;
const sixHours = 1000 * 60 * 60 * 6;
assert.isFalse( assert.isFalse(
isConversationUnregistered({ isConversationUnregistered({
discoveredUnregisteredAt: Date.now() - sixHours - oneMinute, discoveredUnregisteredAt:
Date.now() - 6 * durations.HOUR - durations.MINUTE,
}) })
); );
assert.isFalse( assert.isFalse(

View File

@ -8,6 +8,7 @@ import { assert } from 'chai';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import Long from 'long'; import Long from 'long';
import * as durations from '../../util/durations';
import * as Bytes from '../../Bytes'; import * as Bytes from '../../Bytes';
import { typedArrayToArrayBuffer } from '../../Crypto'; import { typedArrayToArrayBuffer } from '../../Crypto';
import { SenderCertificateMode } from '../../textsecure/OutgoingMessage'; import { SenderCertificateMode } from '../../textsecure/OutgoingMessage';
@ -18,7 +19,7 @@ import { SenderCertificateService } from '../../services/senderCertificate';
import SenderCertificate = Proto.SenderCertificate; import SenderCertificate = Proto.SenderCertificate;
describe('SenderCertificateService', () => { describe('SenderCertificateService', () => {
const FIFTEEN_MINUTES = 15 * 60 * 1000; const FIFTEEN_MINUTES = 15 * durations.MINUTE;
let fakeValidCertificate: SenderCertificate; let fakeValidCertificate: SenderCertificate;
let fakeValidCertificateExpiry: number; let fakeValidCertificateExpiry: number;

View File

@ -14,6 +14,7 @@ import { strictAssert } from '../util/assert';
import { explodePromise } from '../util/explodePromise'; import { explodePromise } from '../util/explodePromise';
import { BackOff, FIBONACCI_TIMEOUTS } from '../util/BackOff'; import { BackOff, FIBONACCI_TIMEOUTS } from '../util/BackOff';
import { getUserAgent } from '../util/getUserAgent'; import { getUserAgent } from '../util/getUserAgent';
import * as durations from '../util/durations';
import { sleep } from '../util/sleep'; import { sleep } from '../util/sleep';
import { SocketStatus } from '../types/SocketStatus'; import { SocketStatus } from '../types/SocketStatus';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
@ -30,9 +31,9 @@ import { WebAPICredentials, IRequestHandler } from './Types.d';
// TODO: remove once we move away from ArrayBuffers // TODO: remove once we move away from ArrayBuffers
const FIXMEU8 = Uint8Array; const FIXMEU8 = Uint8Array;
const TEN_SECONDS = 1000 * 10; const TEN_SECONDS = 10 * durations.SECOND;
const FIVE_MINUTES = 5 * 60 * 1000; const FIVE_MINUTES = 5 * durations.MINUTE;
export type SocketManagerOptions = Readonly<{ export type SocketManagerOptions = Readonly<{
url: string; url: string;

View File

@ -1,12 +1,14 @@
// Copyright 2020 Signal Messenger, LLC // Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import * as durations from '../util/durations';
export default function createTaskWithTimeout<T, Args extends Array<unknown>>( export default function createTaskWithTimeout<T, Args extends Array<unknown>>(
task: (...args: Args) => Promise<T>, task: (...args: Args) => Promise<T>,
id: string, id: string,
options: { timeout?: number } = {} options: { timeout?: number } = {}
): (...args: Args) => Promise<T> { ): (...args: Args) => Promise<T> {
const timeout = options.timeout || 1000 * 60 * 2; // two minutes const timeout = options.timeout || 2 * durations.MINUTE;
const errorForStack = new Error('for stack'); const errorForStack = new Error('for stack');

View File

@ -30,6 +30,7 @@ import { z } from 'zod';
import Long from 'long'; import Long from 'long';
import { assert, strictAssert } from '../util/assert'; import { assert, strictAssert } from '../util/assert';
import * as durations from '../util/durations';
import { getUserAgent } from '../util/getUserAgent'; import { getUserAgent } from '../util/getUserAgent';
import { toWebSafeBase64 } from '../util/webSafeBase64'; import { toWebSafeBase64 } from '../util/webSafeBase64';
import { SocketStatus } from '../types/SocketStatus'; import { SocketStatus } from '../types/SocketStatus';
@ -266,7 +267,7 @@ function _validateResponse(response: any, schema: any) {
return true; return true;
} }
const FIVE_MINUTES = 1000 * 60 * 5; const FIVE_MINUTES = 5 * durations.MINUTE;
type AgentCacheType = { type AgentCacheType = {
[name: string]: { [name: string]: {

View File

@ -27,6 +27,7 @@ import { connection as WebSocket, IMessage } from 'websocket';
import EventTarget, { EventHandler } from './EventTarget'; import EventTarget, { EventHandler } from './EventTarget';
import * as durations from '../util/durations';
import { dropNull } from '../util/dropNull'; import { dropNull } from '../util/dropNull';
import { isOlderThan } from '../util/timestamp'; import { isOlderThan } from '../util/timestamp';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
@ -34,7 +35,7 @@ import { normalizeNumber } from '../util/normalizeNumber';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
import { SignalService as Proto } from '../protobuf'; import { SignalService as Proto } from '../protobuf';
const THIRTY_SECONDS = 30 * 1000; const THIRTY_SECONDS = 30 * durations.SECOND;
const MAX_MESSAGE_SIZE = 64 * 1024; const MAX_MESSAGE_SIZE = 64 * 1024;
@ -385,7 +386,7 @@ export type KeepAliveOptionsType = {
const KEEPALIVE_INTERVAL_MS = 55000; // 55 seconds + 5 seconds for closing the const KEEPALIVE_INTERVAL_MS = 55000; // 55 seconds + 5 seconds for closing the
// socket above. // socket above.
const MAX_KEEPALIVE_INTERVAL_MS = 300 * 1000; // 5 minutes const MAX_KEEPALIVE_INTERVAL_MS = 5 * durations.MINUTE;
class KeepAlive { class KeepAlive {
private keepAliveTimer: NodeJS.Timeout | undefined; private keepAliveTimer: NodeJS.Timeout | undefined;

View File

@ -21,14 +21,13 @@ import {
setUpdateListener, setUpdateListener,
UpdaterInterface, UpdaterInterface,
} from './common'; } from './common';
import * as durations from '../util/durations';
import { LoggerType } from '../types/Logging'; import { LoggerType } from '../types/Logging';
import { hexToBinary, verifySignature } from './signature'; import { hexToBinary, verifySignature } from './signature';
import { markShouldQuit } from '../../app/window_state'; import { markShouldQuit } from '../../app/window_state';
import { DialogType } from '../types/Dialogs'; import { DialogType } from '../types/Dialogs';
const SECOND = 1000; const INTERVAL = 30 * durations.MINUTE;
const MINUTE = SECOND * 60;
const INTERVAL = MINUTE * 30;
export async function start( export async function start(
getMainWindow: () => BrowserWindow, getMainWindow: () => BrowserWindow,

View File

@ -19,6 +19,7 @@ import {
setUpdateListener, setUpdateListener,
UpdaterInterface, UpdaterInterface,
} from './common'; } from './common';
import * as durations from '../util/durations';
import { LoggerType } from '../types/Logging'; import { LoggerType } from '../types/Logging';
import { hexToBinary, verifySignature } from './signature'; import { hexToBinary, verifySignature } from './signature';
import { markShouldQuit } from '../../app/window_state'; import { markShouldQuit } from '../../app/window_state';
@ -27,9 +28,7 @@ import { DialogType } from '../types/Dialogs';
const readdir = pify(readdirCallback); const readdir = pify(readdirCallback);
const unlink = pify(unlinkCallback); const unlink = pify(unlinkCallback);
const SECOND = 1000; const INTERVAL = 30 * durations.MINUTE;
const MINUTE = SECOND * 60;
const INTERVAL = MINUTE * 30;
let fileName: string; let fileName: string;
let version: string; let version: string;

View File

@ -2,13 +2,11 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { MessageModel } from '../models/messages'; import { MessageModel } from '../models/messages';
import * as durations from './durations';
import { map, filter } from './iterables'; import { map, filter } from './iterables';
import { isNotNil } from './isNotNil'; import { isNotNil } from './isNotNil';
const SECOND = 1000; const FIVE_MINUTES = 5 * durations.MINUTE;
const MINUTE = SECOND * 60;
const FIVE_MINUTES = MINUTE * 5;
const HOUR = MINUTE * 60;
type LookupItemType = { type LookupItemType = {
timestamp: number; timestamp: number;
@ -121,6 +119,6 @@ export class MessageController {
} }
startCleanupInterval(): NodeJS.Timeout | number { startCleanupInterval(): NodeJS.Timeout | number {
return setInterval(this.cleanup.bind(this), HOUR); return setInterval(this.cleanup.bind(this), durations.HOUR);
} }
} }

View File

@ -28,6 +28,7 @@ import * as universalExpireTimer from './universalExpireTimer';
import { PhoneNumberDiscoverability } from './phoneNumberDiscoverability'; import { PhoneNumberDiscoverability } from './phoneNumberDiscoverability';
import { PhoneNumberSharingMode } from './phoneNumberSharingMode'; import { PhoneNumberSharingMode } from './phoneNumberSharingMode';
import { assert } from './assert'; import { assert } from './assert';
import * as durations from './durations';
import { isPhoneNumberSharingEnabled } from './isPhoneNumberSharingEnabled'; import { isPhoneNumberSharingEnabled } from './isPhoneNumberSharingEnabled';
type ThemeType = 'light' | 'dark' | 'system'; type ThemeType = 'light' | 'dark' | 'system';
@ -333,7 +334,7 @@ export function createIPCEvents(
isPrimary: () => window.textsecure.storage.user.getDeviceId() === 1, isPrimary: () => window.textsecure.storage.user.getDeviceId() === 1,
syncRequest: () => syncRequest: () =>
new Promise<void>((resolve, reject) => { new Promise<void>((resolve, reject) => {
const FIVE_MINUTES = 5 * 60 * 60 * 1000; const FIVE_MINUTES = 5 * durations.MINUTE;
const syncRequest = window.getSyncRequest(FIVE_MINUTES); const syncRequest = window.getSyncRequest(FIVE_MINUTES);
syncRequest.addEventListener('success', () => resolve()); syncRequest.addEventListener('success', () => resolve());
syncRequest.addEventListener('timeout', () => syncRequest.addEventListener('timeout', () =>

8
ts/util/durations.ts Normal file
View File

@ -0,0 +1,8 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export const SECOND = 1000;
export const MINUTE = SECOND * 60;
export const HOUR = MINUTE * 60;
export const DAY = HOUR * 24;
export const WEEK = DAY * 7;

View File

@ -1,10 +1,10 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import * as moment from 'moment'; import * as durations from './durations';
const BACKOFF_FACTOR = 1.9; const BACKOFF_FACTOR = 1.9;
const MAX_BACKOFF = moment.duration(15, 'minutes').asMilliseconds(); const MAX_BACKOFF = 15 * durations.MINUTE;
/** /**
* For a given attempt, how long should we sleep (in milliseconds)? * For a given attempt, how long should we sleep (in milliseconds)?

View File

@ -1,7 +1,7 @@
// Copyright 2020-2021 Signal Messenger, LLC // Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import moment from 'moment'; import * as durations from './durations';
import { LocalizerType } from '../types/Util'; import { LocalizerType } from '../types/Util';
import { getMutedUntilText } from './getMutedUntilText'; import { getMutedUntilText } from './getMutedUntilText';
import { isMuted } from './isMuted'; import { isMuted } from './isMuted';
@ -32,19 +32,19 @@ export function getMuteOptions(
: []), : []),
{ {
name: i18n('muteHour'), name: i18n('muteHour'),
value: moment.duration(1, 'hour').as('milliseconds'), value: durations.HOUR,
}, },
{ {
name: i18n('muteEightHours'), name: i18n('muteEightHours'),
value: moment.duration(8, 'hour').as('milliseconds'), value: 8 * durations.HOUR,
}, },
{ {
name: i18n('muteDay'), name: i18n('muteDay'),
value: moment.duration(1, 'day').as('milliseconds'), value: durations.DAY,
}, },
{ {
name: i18n('muteWeek'), name: i18n('muteWeek'),
value: moment.duration(1, 'week').as('milliseconds'), value: durations.WEEK,
}, },
{ {
name: i18n('muteAlways'), name: i18n('muteAlways'),