From f86f753df938f938dcb354688a0f1dad574a7692 Mon Sep 17 00:00:00 2001 From: Evan Hahn <69474926+EvanHahn-Signal@users.noreply.github.com> Date: Thu, 26 Aug 2021 09:10:58 -0500 Subject: [PATCH] Add `durations` utility for computing durations --- ts/background.ts | 3 ++- ts/groups.ts | 6 ++--- ts/jobs/readSyncJobQueue.ts | 4 ++-- ts/jobs/reportSpamJobQueue.ts | 4 ++-- ts/jobs/viewSyncJobQueue.ts | 4 ++-- ts/jobs/viewedReceiptsJobQueue.ts | 4 ++-- ts/messageModifiers/AttachmentDownloads.ts | 12 +++++----- ts/models/conversations.ts | 5 +++-- ts/services/calling.ts | 6 ++--- ts/services/groupCredentialFetcher.ts | 22 +++++++++---------- ts/services/storage.ts | 22 ++++++++++--------- ts/sql/Client.ts | 3 ++- ts/sql/Server.ts | 4 ++-- ts/test-both/util/expireTimers.ts | 18 ++++++--------- ts/test-both/util/exponentialBackoff_test.ts | 7 +++--- .../util/isConversationUnregistered_test.ts | 7 +++--- .../services/senderCertificate_test.ts | 3 ++- ts/textsecure/SocketManager.ts | 5 +++-- ts/textsecure/TaskWithTimeout.ts | 4 +++- ts/textsecure/WebAPI.ts | 3 ++- ts/textsecure/WebsocketResources.ts | 5 +++-- ts/updater/macos.ts | 5 ++--- ts/updater/windows.ts | 5 ++--- ts/util/MessageController.ts | 8 +++---- ts/util/createIPCEvents.ts | 3 ++- ts/util/durations.ts | 8 +++++++ ts/util/exponentialBackoff.ts | 4 ++-- ts/util/getMuteOptions.ts | 10 ++++----- 28 files changed, 99 insertions(+), 95 deletions(-) create mode 100644 ts/util/durations.ts diff --git a/ts/background.ts b/ts/background.ts index c52c1e167..ba48bf165 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -19,6 +19,7 @@ import { getTitleBarVisibility, TitleBarVisibility } from './types/Settings'; import { SocketStatus } from './types/SocketStatus'; import { DEFAULT_CONVERSATION_COLOR } from './types/Colors'; import { ChallengeHandler } from './challenge'; +import * as durations from './util/durations'; import { isWindowDragElement } from './util/isWindowDragElement'; import { assert, strictAssert } from './util/assert'; import { dropNull } from './util/dropNull'; @@ -2261,7 +2262,7 @@ export async function startApp(): Promise { 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 // a given conversation's queue. But we have processed all events from the websocket. diff --git a/ts/groups.ts b/ts/groups.ts index 18d84c720..63f70e949 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -23,6 +23,7 @@ import dataInterface from './sql/Client'; import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64'; import { assert, strictAssert } from './util/assert'; import { isMoreRecentThan } from './util/timestamp'; +import * as durations from './util/durations'; import { normalizeUuid } from './util/normalizeUuid'; import { dropNull } from './util/dropNull'; import { @@ -1252,9 +1253,8 @@ export async function modifyGroupV2({ ); } - const ONE_MINUTE = 1000 * 60; const startTime = Date.now(); - const timeoutTime = startTime + ONE_MINUTE; + const timeoutTime = startTime + durations.MINUTE; const MAX_ATTEMPTS = 5; @@ -2723,7 +2723,7 @@ type MaybeUpdatePropsType = { force?: boolean; }; -const FIVE_MINUTES = 1000 * 60 * 5; +const FIVE_MINUTES = 5 * durations.MINUTE; export async function waitThenMaybeUpdateGroup( options: MaybeUpdatePropsType, diff --git a/ts/jobs/readSyncJobQueue.ts b/ts/jobs/readSyncJobQueue.ts index 1a685275c..3feaf8cd6 100644 --- a/ts/jobs/readSyncJobQueue.ts +++ b/ts/jobs/readSyncJobQueue.ts @@ -4,7 +4,7 @@ /* eslint-disable class-methods-use-this */ import * as z from 'zod'; -import * as moment from 'moment'; +import * as durations from '../util/durations'; import type { LoggerType } from '../logging/log'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; @@ -12,7 +12,7 @@ import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; import { JobQueue } from './JobQueue'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; -const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); +const MAX_RETRY_TIME = durations.DAY; const readSyncJobDataSchema = z.object({ readSyncs: z.array( diff --git a/ts/jobs/reportSpamJobQueue.ts b/ts/jobs/reportSpamJobQueue.ts index 31387c0bc..e69696fcb 100644 --- a/ts/jobs/reportSpamJobQueue.ts +++ b/ts/jobs/reportSpamJobQueue.ts @@ -3,7 +3,7 @@ /* eslint-disable class-methods-use-this */ import * as z from 'zod'; -import * as moment from 'moment'; +import * as durations from '../util/durations'; import { strictAssert } from '../util/assert'; import { waitForOnline } from '../util/waitForOnline'; import { isDone as isDeviceLinked } from '../util/registration'; @@ -16,7 +16,7 @@ import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; import { parseIntWithFallback } from '../util/parseIntWithFallback'; 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([ 404, 408, diff --git a/ts/jobs/viewSyncJobQueue.ts b/ts/jobs/viewSyncJobQueue.ts index 773210d41..054b311c7 100644 --- a/ts/jobs/viewSyncJobQueue.ts +++ b/ts/jobs/viewSyncJobQueue.ts @@ -4,7 +4,7 @@ /* eslint-disable class-methods-use-this */ import * as z from 'zod'; -import * as moment from 'moment'; +import * as durations from '../util/durations'; import type { LoggerType } from '../logging/log'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; @@ -12,7 +12,7 @@ import { runReadOrViewSyncJob } from './helpers/runReadOrViewSyncJob'; import { JobQueue } from './JobQueue'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; -const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); +const MAX_RETRY_TIME = durations.DAY; const viewSyncJobDataSchema = z.object({ viewSyncs: z.array( diff --git a/ts/jobs/viewedReceiptsJobQueue.ts b/ts/jobs/viewedReceiptsJobQueue.ts index 297d285aa..54442cfaf 100644 --- a/ts/jobs/viewedReceiptsJobQueue.ts +++ b/ts/jobs/viewedReceiptsJobQueue.ts @@ -4,7 +4,7 @@ /* eslint-disable class-methods-use-this */ import { z } from 'zod'; -import * as moment from 'moment'; +import * as durations from '../util/durations'; import type { LoggerType } from '../logging/log'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff'; import { commonShouldJobContinue } from './helpers/commonShouldJobContinue'; @@ -14,7 +14,7 @@ import { JobQueue } from './JobQueue'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore'; import { handleCommonJobRequestError } from './helpers/handleCommonJobRequestError'; -const MAX_RETRY_TIME = moment.duration(1, 'day').asMilliseconds(); +const MAX_RETRY_TIME = durations.DAY; const viewedReceiptsJobDataSchema = z.object({ viewedReceipt: z.object({ diff --git a/ts/messageModifiers/AttachmentDownloads.ts b/ts/messageModifiers/AttachmentDownloads.ts index 2f0680703..3fce0bdb1 100644 --- a/ts/messageModifiers/AttachmentDownloads.ts +++ b/ts/messageModifiers/AttachmentDownloads.ts @@ -5,6 +5,7 @@ import { isNumber, omit } from 'lodash'; import { v4 as getGuid } from 'uuid'; import dataInterface from '../sql/Client'; +import * as durations from '../util/durations'; import { downloadAttachment } from '../util/downloadAttachment'; import { stringFromBytes } from '../Crypto'; import { @@ -28,15 +29,12 @@ const { const MAX_ATTACHMENT_JOB_PARALLELISM = 3; -const SECOND = 1000; -const MINUTE = 60 * SECOND; -const HOUR = 60 * MINUTE; -const TICK_INTERVAL = MINUTE; +const TICK_INTERVAL = durations.MINUTE; const RETRY_BACKOFF: Record = { - 1: 30 * SECOND, - 2: 30 * MINUTE, - 3: 6 * HOUR, + 1: 30 * durations.SECOND, + 2: 30 * durations.MINUTE, + 3: 6 * durations.HOUR, }; let enabled = false; diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index fa0c7d162..e42b5f8c8 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -56,6 +56,7 @@ import { sendReadReceiptsFor } from '../util/sendReadReceiptsFor'; import { updateConversationsWithUuidLookup } from '../updateConversationsWithUuidLookup'; import { ReadStatus } from '../messages/MessageReadStatus'; import { SendStatus } from '../messages/MessageSendState'; +import * as durations from '../util/durations'; import { concat, filter, @@ -106,8 +107,8 @@ const { } = window.Signal.Migrations; const { addStickerPackReference } = window.Signal.Data; -const THREE_HOURS = 3 * 60 * 60 * 1000; -const FIVE_MINUTES = 1000 * 60 * 5; +const THREE_HOURS = durations.HOUR * 3; +const FIVE_MINUTES = durations.MINUTE * 5; const JOB_REPORTING_THRESHOLD_MS = 25; diff --git a/ts/services/calling.ts b/ts/services/calling.ts index 6de4855ee..a95e1291e 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -34,7 +34,6 @@ import { BandwidthMode, } from 'ringrtc'; import { uniqBy, noop } from 'lodash'; -import * as moment from 'moment'; import { ActionsType as UxActionsType, @@ -63,6 +62,7 @@ import { import { assert } from '../util/assert'; import { dropNull, shallowDropNull } from '../util/dropNull'; import { getOwn } from '../util/getOwn'; +import * as durations from '../util/durations'; import { handleMessageSend } from '../util/handleMessageSend'; import { fetchMembershipProof, @@ -99,9 +99,7 @@ const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map< [HttpMethod.Delete, 'DELETE'], ]); -const CLEAN_EXPIRED_GROUP_CALL_RINGS_INTERVAL = moment - .duration(10, 'minutes') - .asMilliseconds(); +const CLEAN_EXPIRED_GROUP_CALL_RINGS_INTERVAL = 10 * durations.MINUTE; // 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 diff --git a/ts/services/groupCredentialFetcher.ts b/ts/services/groupCredentialFetcher.ts index 8e2e6572d..5942cc8a4 100644 --- a/ts/services/groupCredentialFetcher.ts +++ b/ts/services/groupCredentialFetcher.ts @@ -11,6 +11,7 @@ import { } from '../util/zkgroup'; import { GroupCredentialType } from '../textsecure/WebAPI'; +import * as durations from '../util/durations'; import { BackOff } from '../util/BackOff'; import { sleep } from '../util/sleep'; @@ -26,13 +27,8 @@ type NextCredentialsType = { tomorrow: GroupCredentialType; }; -const SECOND = 1000; -const MINUTE = 60 * SECOND; -const HOUR = 60 * MINUTE; -const DAY = 24 * HOUR; - function getTodayInEpoch() { - return Math.floor(Date.now() / DAY); + return Math.floor(Date.now() / durations.DAY); } let started = false; @@ -48,15 +44,17 @@ export async function initializeGroupCredentialFetcher(): Promise { // 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 // 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 = [ - SECOND, - 5 * SECOND, - 30 * SECOND, - 2 * MINUTE, - 5 * MINUTE, + durations.SECOND, + 5 * durations.SECOND, + 30 * durations.SECOND, + 2 * durations.MINUTE, + 5 * durations.MINUTE, ]; export async function runWithRetry( diff --git a/ts/services/storage.ts b/ts/services/storage.ts index 0ef0c5c14..53887466a 100644 --- a/ts/services/storage.ts +++ b/ts/services/storage.ts @@ -26,6 +26,7 @@ import { } from './storageRecordOps'; import { ConversationModel } from '../models/conversations'; import { strictAssert } from '../util/assert'; +import * as durations from '../util/durations'; import { BackOff } from '../util/BackOff'; import { handleMessageSend } from '../util/handleMessageSend'; import { storageJobQueue } from '../util/JobQueue'; @@ -60,18 +61,19 @@ const validRecordTypes = new Set([ 4, // ACCOUNT ]); -const SECOND = 1000; -const MINUTE = 60 * SECOND; - const backOff = new BackOff([ - SECOND, - 5 * SECOND, - 30 * SECOND, - 2 * MINUTE, - 5 * MINUTE, + durations.SECOND, + 5 * durations.SECOND, + 30 * durations.SECOND, + 2 * durations.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 { return storageID.substring(0, 3); @@ -1112,7 +1114,7 @@ async function upload(fromSync = false): Promise { if (uploadBucket.length >= 3) { const [firstMostRecentWrite] = uploadBucket; - if (isMoreRecentThan(5 * MINUTE, firstMostRecentWrite)) { + if (isMoreRecentThan(5 * durations.MINUTE, firstMostRecentWrite)) { throw new Error( 'storageService.uploadManifest: too many writes too soon.' ); diff --git a/ts/sql/Client.ts b/ts/sql/Client.ts index 61fa014f7..7138dfee4 100644 --- a/ts/sql/Client.ts +++ b/ts/sql/Client.ts @@ -29,6 +29,7 @@ import { arrayBufferToBase64, base64ToArrayBuffer } from '../Crypto'; import { CURRENT_SCHEMA_VERSION } from '../../js/modules/types/message'; import { createBatcher } from '../util/batcher'; import { assert } from '../util/assert'; +import * as durations from '../util/durations'; import { cleanDataForIpc } from './cleanDataForIpc'; import { ReactionType } from '../types/Reactions'; import { ConversationColorType, CustomColorType } from '../types/Colors'; @@ -82,7 +83,7 @@ if (ipcRenderer && ipcRenderer.setMaxListeners) { 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; diff --git a/ts/sql/Server.ts b/ts/sql/Server.ts index ac489ae60..c17b05db4 100644 --- a/ts/sql/Server.ts +++ b/ts/sql/Server.ts @@ -13,7 +13,6 @@ import mkdirp from 'mkdirp'; import rimraf from 'rimraf'; import SQL, { Database, Statement } from 'better-sqlite3'; import pProps from 'p-props'; -import * as moment from 'moment'; import { v4 as generateUUID } from 'uuid'; import { @@ -41,6 +40,7 @@ import { dropNull } from '../util/dropNull'; import { isNormalNumber } from '../util/isNormalNumber'; import { isNotNil } from '../util/isNotNil'; import { parseIntOrThrow } from '../util/parseIntOrThrow'; +import * as durations from '../util/durations'; import { formatCountForLogging } from '../logging/formatCountForLogging'; import { ConversationColorType, CustomColorType } from '../types/Colors'; import { ProcessGroupCallRingRequestResult } from '../types/Calling'; @@ -5965,7 +5965,7 @@ async function processGroupCallRingCancelation(ringId: bigint): Promise { // This age, in milliseconds, should be longer than any group call ring duration. Beyond // 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 { const db = getInstance(); diff --git a/ts/test-both/util/expireTimers.ts b/ts/test-both/util/expireTimers.ts index 5776a106c..f96ebbef6 100644 --- a/ts/test-both/util/expireTimers.ts +++ b/ts/test-both/util/expireTimers.ts @@ -1,18 +1,14 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import * as durations from '../../util/durations'; + 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 = [ - { value: 42 * SECOND, label: '42 seconds' }, - { value: 5 * MINUTE, label: '5 minutes' }, - { value: 1 * HOUR, label: '1 hour' }, - { value: 6 * DAY, label: '6 days' }, - { value: 3 * WEEK, label: '3 weeks' }, + { value: 42 * durations.SECOND, label: '42 seconds' }, + { value: 5 * durations.MINUTE, label: '5 minutes' }, + { value: 1 * durations.HOUR, label: '1 hour' }, + { value: 6 * durations.DAY, label: '6 days' }, + { value: 3 * durations.WEEK, label: '3 weeks' }, ]; diff --git a/ts/test-both/util/exponentialBackoff_test.ts b/ts/test-both/util/exponentialBackoff_test.ts index ddd3c2011..674605262 100644 --- a/ts/test-both/util/exponentialBackoff_test.ts +++ b/ts/test-both/util/exponentialBackoff_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import * as moment from 'moment'; +import * as durations from '../../util/durations'; import { exponentialBackoffSleepTime, @@ -20,7 +20,7 @@ describe('exponential backoff utilities', () => { }); 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) { assert.strictEqual(exponentialBackoffSleepTime(attempt), maximum); } @@ -39,8 +39,7 @@ describe('exponential backoff utilities', () => { it('returns 110 attempts for 1 day', () => { // This is a test case that is lifted from iOS's codebase. - const oneDay = moment.duration(24, 'hours').asMilliseconds(); - assert.strictEqual(exponentialBackoffMaxAttempts(oneDay), 110); + assert.strictEqual(exponentialBackoffMaxAttempts(durations.DAY), 110); }); }); }); diff --git a/ts/test-both/util/isConversationUnregistered_test.ts b/ts/test-both/util/isConversationUnregistered_test.ts index bed76f26f..64658cd37 100644 --- a/ts/test-both/util/isConversationUnregistered_test.ts +++ b/ts/test-both/util/isConversationUnregistered_test.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; +import * as durations from '../../util/durations'; import { isConversationUnregistered } from '../../util/isConversationUnregistered'; @@ -33,12 +34,10 @@ describe('isConversationUnregistered', () => { }); it('returns false if passed a time more than 6 hours ago', () => { - const oneMinute = 1000 * 60; - const sixHours = 1000 * 60 * 60 * 6; - assert.isFalse( isConversationUnregistered({ - discoveredUnregisteredAt: Date.now() - sixHours - oneMinute, + discoveredUnregisteredAt: + Date.now() - 6 * durations.HOUR - durations.MINUTE, }) ); assert.isFalse( diff --git a/ts/test-electron/services/senderCertificate_test.ts b/ts/test-electron/services/senderCertificate_test.ts index 967caed31..1915bda13 100644 --- a/ts/test-electron/services/senderCertificate_test.ts +++ b/ts/test-electron/services/senderCertificate_test.ts @@ -8,6 +8,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import { v4 as uuid } from 'uuid'; import Long from 'long'; +import * as durations from '../../util/durations'; import * as Bytes from '../../Bytes'; import { typedArrayToArrayBuffer } from '../../Crypto'; import { SenderCertificateMode } from '../../textsecure/OutgoingMessage'; @@ -18,7 +19,7 @@ import { SenderCertificateService } from '../../services/senderCertificate'; import SenderCertificate = Proto.SenderCertificate; describe('SenderCertificateService', () => { - const FIFTEEN_MINUTES = 15 * 60 * 1000; + const FIFTEEN_MINUTES = 15 * durations.MINUTE; let fakeValidCertificate: SenderCertificate; let fakeValidCertificateExpiry: number; diff --git a/ts/textsecure/SocketManager.ts b/ts/textsecure/SocketManager.ts index de8f5a278..89b97a093 100644 --- a/ts/textsecure/SocketManager.ts +++ b/ts/textsecure/SocketManager.ts @@ -14,6 +14,7 @@ import { strictAssert } from '../util/assert'; import { explodePromise } from '../util/explodePromise'; import { BackOff, FIBONACCI_TIMEOUTS } from '../util/BackOff'; import { getUserAgent } from '../util/getUserAgent'; +import * as durations from '../util/durations'; import { sleep } from '../util/sleep'; import { SocketStatus } from '../types/SocketStatus'; import * as Errors from '../types/errors'; @@ -30,9 +31,9 @@ import { WebAPICredentials, IRequestHandler } from './Types.d'; // TODO: remove once we move away from ArrayBuffers 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<{ url: string; diff --git a/ts/textsecure/TaskWithTimeout.ts b/ts/textsecure/TaskWithTimeout.ts index 14b09518e..ff596e38e 100644 --- a/ts/textsecure/TaskWithTimeout.ts +++ b/ts/textsecure/TaskWithTimeout.ts @@ -1,12 +1,14 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import * as durations from '../util/durations'; + export default function createTaskWithTimeout>( task: (...args: Args) => Promise, id: string, options: { timeout?: number } = {} ): (...args: Args) => Promise { - const timeout = options.timeout || 1000 * 60 * 2; // two minutes + const timeout = options.timeout || 2 * durations.MINUTE; const errorForStack = new Error('for stack'); diff --git a/ts/textsecure/WebAPI.ts b/ts/textsecure/WebAPI.ts index 60cea8be6..7bd4ca646 100644 --- a/ts/textsecure/WebAPI.ts +++ b/ts/textsecure/WebAPI.ts @@ -30,6 +30,7 @@ import { z } from 'zod'; import Long from 'long'; import { assert, strictAssert } from '../util/assert'; +import * as durations from '../util/durations'; import { getUserAgent } from '../util/getUserAgent'; import { toWebSafeBase64 } from '../util/webSafeBase64'; import { SocketStatus } from '../types/SocketStatus'; @@ -266,7 +267,7 @@ function _validateResponse(response: any, schema: any) { return true; } -const FIVE_MINUTES = 1000 * 60 * 5; +const FIVE_MINUTES = 5 * durations.MINUTE; type AgentCacheType = { [name: string]: { diff --git a/ts/textsecure/WebsocketResources.ts b/ts/textsecure/WebsocketResources.ts index 3d2d4bea4..f8db3f4f1 100644 --- a/ts/textsecure/WebsocketResources.ts +++ b/ts/textsecure/WebsocketResources.ts @@ -27,6 +27,7 @@ import { connection as WebSocket, IMessage } from 'websocket'; import EventTarget, { EventHandler } from './EventTarget'; +import * as durations from '../util/durations'; import { dropNull } from '../util/dropNull'; import { isOlderThan } from '../util/timestamp'; import { strictAssert } from '../util/assert'; @@ -34,7 +35,7 @@ import { normalizeNumber } from '../util/normalizeNumber'; import * as Errors from '../types/errors'; import { SignalService as Proto } from '../protobuf'; -const THIRTY_SECONDS = 30 * 1000; +const THIRTY_SECONDS = 30 * durations.SECOND; 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 // socket above. -const MAX_KEEPALIVE_INTERVAL_MS = 300 * 1000; // 5 minutes +const MAX_KEEPALIVE_INTERVAL_MS = 5 * durations.MINUTE; class KeepAlive { private keepAliveTimer: NodeJS.Timeout | undefined; diff --git a/ts/updater/macos.ts b/ts/updater/macos.ts index 48a7409c2..9914c6617 100644 --- a/ts/updater/macos.ts +++ b/ts/updater/macos.ts @@ -21,14 +21,13 @@ import { setUpdateListener, UpdaterInterface, } from './common'; +import * as durations from '../util/durations'; import { LoggerType } from '../types/Logging'; import { hexToBinary, verifySignature } from './signature'; import { markShouldQuit } from '../../app/window_state'; import { DialogType } from '../types/Dialogs'; -const SECOND = 1000; -const MINUTE = SECOND * 60; -const INTERVAL = MINUTE * 30; +const INTERVAL = 30 * durations.MINUTE; export async function start( getMainWindow: () => BrowserWindow, diff --git a/ts/updater/windows.ts b/ts/updater/windows.ts index e81083da9..41fcc2374 100644 --- a/ts/updater/windows.ts +++ b/ts/updater/windows.ts @@ -19,6 +19,7 @@ import { setUpdateListener, UpdaterInterface, } from './common'; +import * as durations from '../util/durations'; import { LoggerType } from '../types/Logging'; import { hexToBinary, verifySignature } from './signature'; import { markShouldQuit } from '../../app/window_state'; @@ -27,9 +28,7 @@ import { DialogType } from '../types/Dialogs'; const readdir = pify(readdirCallback); const unlink = pify(unlinkCallback); -const SECOND = 1000; -const MINUTE = SECOND * 60; -const INTERVAL = MINUTE * 30; +const INTERVAL = 30 * durations.MINUTE; let fileName: string; let version: string; diff --git a/ts/util/MessageController.ts b/ts/util/MessageController.ts index f5b6f787b..b8c5a1a6e 100644 --- a/ts/util/MessageController.ts +++ b/ts/util/MessageController.ts @@ -2,13 +2,11 @@ // SPDX-License-Identifier: AGPL-3.0-only import { MessageModel } from '../models/messages'; +import * as durations from './durations'; import { map, filter } from './iterables'; import { isNotNil } from './isNotNil'; -const SECOND = 1000; -const MINUTE = SECOND * 60; -const FIVE_MINUTES = MINUTE * 5; -const HOUR = MINUTE * 60; +const FIVE_MINUTES = 5 * durations.MINUTE; type LookupItemType = { timestamp: number; @@ -121,6 +119,6 @@ export class MessageController { } startCleanupInterval(): NodeJS.Timeout | number { - return setInterval(this.cleanup.bind(this), HOUR); + return setInterval(this.cleanup.bind(this), durations.HOUR); } } diff --git a/ts/util/createIPCEvents.ts b/ts/util/createIPCEvents.ts index b07e9d95d..62695e84e 100644 --- a/ts/util/createIPCEvents.ts +++ b/ts/util/createIPCEvents.ts @@ -28,6 +28,7 @@ import * as universalExpireTimer from './universalExpireTimer'; import { PhoneNumberDiscoverability } from './phoneNumberDiscoverability'; import { PhoneNumberSharingMode } from './phoneNumberSharingMode'; import { assert } from './assert'; +import * as durations from './durations'; import { isPhoneNumberSharingEnabled } from './isPhoneNumberSharingEnabled'; type ThemeType = 'light' | 'dark' | 'system'; @@ -333,7 +334,7 @@ export function createIPCEvents( isPrimary: () => window.textsecure.storage.user.getDeviceId() === 1, syncRequest: () => new Promise((resolve, reject) => { - const FIVE_MINUTES = 5 * 60 * 60 * 1000; + const FIVE_MINUTES = 5 * durations.MINUTE; const syncRequest = window.getSyncRequest(FIVE_MINUTES); syncRequest.addEventListener('success', () => resolve()); syncRequest.addEventListener('timeout', () => diff --git a/ts/util/durations.ts b/ts/util/durations.ts new file mode 100644 index 000000000..b4c22fa97 --- /dev/null +++ b/ts/util/durations.ts @@ -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; diff --git a/ts/util/exponentialBackoff.ts b/ts/util/exponentialBackoff.ts index 3b781b622..87f29c3ac 100644 --- a/ts/util/exponentialBackoff.ts +++ b/ts/util/exponentialBackoff.ts @@ -1,10 +1,10 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import * as moment from 'moment'; +import * as durations from './durations'; 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)? diff --git a/ts/util/getMuteOptions.ts b/ts/util/getMuteOptions.ts index 5a250e71f..52019c888 100644 --- a/ts/util/getMuteOptions.ts +++ b/ts/util/getMuteOptions.ts @@ -1,7 +1,7 @@ // Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import moment from 'moment'; +import * as durations from './durations'; import { LocalizerType } from '../types/Util'; import { getMutedUntilText } from './getMutedUntilText'; import { isMuted } from './isMuted'; @@ -32,19 +32,19 @@ export function getMuteOptions( : []), { name: i18n('muteHour'), - value: moment.duration(1, 'hour').as('milliseconds'), + value: durations.HOUR, }, { name: i18n('muteEightHours'), - value: moment.duration(8, 'hour').as('milliseconds'), + value: 8 * durations.HOUR, }, { name: i18n('muteDay'), - value: moment.duration(1, 'day').as('milliseconds'), + value: durations.DAY, }, { name: i18n('muteWeek'), - value: moment.duration(1, 'week').as('milliseconds'), + value: durations.WEEK, }, { name: i18n('muteAlways'),