Remove window.getAccountManager

This commit is contained in:
Fedor Indutny
2025-10-10 14:38:51 -07:00
committed by GitHub
parent 9a8f8ffe5f
commit bfb390e644
14 changed files with 90 additions and 92 deletions

View File

@@ -31,6 +31,7 @@ import { ThemeType } from './types/Util.js';
import * as durations from './util/durations/index.js';
import { drop } from './util/drop.js';
import { explodePromise } from './util/explodePromise.js';
import { deliveryReceiptQueue } from './util/deliveryReceipt.js';
import type { ExplodePromiseResultType } from './util/explodePromise.js';
import { isWindowDragElement } from './util/isWindowDragElement.js';
import { assertDev, strictAssert } from './util/assert.js';
@@ -148,7 +149,7 @@ import {
reportMessage,
unregisterRequestHandler,
} from './textsecure/WebAPI.js';
import AccountManager from './textsecure/AccountManager.js';
import { accountManager } from './textsecure/AccountManager.js';
import * as KeyChangeListener from './textsecure/KeyChangeListener.js';
import { UpdateKeysListener } from './textsecure/UpdateKeysListener.js';
import { isGroup } from './util/whatTypeOfConversation.js';
@@ -353,8 +354,6 @@ export async function startApp(): Promise<void> {
const onRetryRequestQueue = new PQueue({ concurrency: 1 });
onRetryRequestQueue.pause();
window.Whisper.deliveryReceiptQueue.pause();
if (window.platform === 'darwin') {
window.addEventListener('dblclick', (event: Event) => {
const target = event.target as HTMLElement;
@@ -421,8 +420,8 @@ export async function startApp(): Promise<void> {
'lowKeys',
throttle(
async () => {
await window.getAccountManager().maybeUpdateKeys(ServiceIdKind.ACI);
await window.getAccountManager().maybeUpdateKeys(ServiceIdKind.PNI);
await accountManager.maybeUpdateKeys(ServiceIdKind.ACI);
await accountManager.maybeUpdateKeys(ServiceIdKind.PNI);
},
durations.MINUTE,
{ trailing: true, leading: false }
@@ -447,34 +446,25 @@ export async function startApp(): Promise<void> {
return getSocketStatus();
};
let accountManager: AccountManager;
window.getAccountManager = () => {
if (accountManager) {
return accountManager;
}
accountManager.addEventListener('startRegistration', () => {
pauseProcessing('startRegistration');
// We should already be logged out, but this ensures that the next time we connect
// to the auth socket it is from newly-registered credentials
drop(logout());
authSocketConnectCount = 0;
accountManager = new AccountManager();
accountManager.addEventListener('startRegistration', () => {
pauseProcessing('startRegistration');
// We should already be logged out, but this ensures that the next time we connect
// to the auth socket it is from newly-registered credentials
drop(logout());
authSocketConnectCount = 0;
backupReady.reject(new Error('startRegistration'));
backupReady = explodePromise();
registrationCompleted = explodePromise();
});
backupReady.reject(new Error('startRegistration'));
backupReady = explodePromise();
registrationCompleted = explodePromise();
});
accountManager.addEventListener('endRegistration', () => {
window.Whisper.events.emit('userChanged', false);
accountManager.addEventListener('endRegistration', () => {
window.Whisper.events.emit('userChanged', false);
drop(itemStorage.put('postRegistrationSyncsStatus', 'incomplete'));
registrationCompleted?.resolve();
drop(Registration.markDone());
});
return accountManager;
};
drop(itemStorage.put('postRegistrationSyncsStatus', 'incomplete'));
registrationCompleted?.resolve();
drop(Registration.markDone());
});
const cancelInitializationMessage = setAppLoadingScreenMessage(
undefined,
@@ -1826,9 +1816,8 @@ export async function startApp(): Promise<void> {
drop(StorageService.reprocessUnknownFields());
const manager = window.getAccountManager();
await Promise.all([
manager.maybeUpdateDeviceName(),
accountManager.maybeUpdateDeviceName(),
itemStorage.user.removeSignalingKey(),
]);
} catch (e) {
@@ -1912,7 +1901,7 @@ export async function startApp(): Promise<void> {
lightSessionResetQueue.pause();
onDecryptionErrorQueue.pause();
onRetryRequestQueue.pause();
window.Whisper.deliveryReceiptQueue.pause();
deliveryReceiptQueue.pause();
notificationService.disable();
}
@@ -1923,7 +1912,7 @@ export async function startApp(): Promise<void> {
lightSessionResetQueue.start();
onDecryptionErrorQueue.start();
onRetryRequestQueue.start();
window.Whisper.deliveryReceiptQueue.start();
deliveryReceiptQueue.start();
notificationService.enable();
}

View File

@@ -12,6 +12,10 @@ import { isStory } from './helpers.js';
import { getAuthor } from './sources.js';
import { messageHasPaymentEvent } from './payments.js';
import { getMessageIdForLogging } from '../util/idForLogging.js';
import {
deliveryReceiptQueue,
deliveryReceiptBatcher,
} from '../util/deliveryReceipt.js';
import { getSenderIdentifier } from '../util/getSenderIdentifier.js';
import { isNormalNumber } from '../util/isNormalNumber.js';
import { upgradeMessageSchema } from '../util/migrations.js';
@@ -381,12 +385,12 @@ export async function handleDataMessage(
// processing incoming messages to start sending outgoing delivery receipts.
// The queue can be paused easily.
drop(
window.Whisper.deliveryReceiptQueue.add(() => {
deliveryReceiptQueue.add(() => {
strictAssert(
isAciString(sourceServiceId),
'Incoming message must be from ACI'
);
window.Whisper.deliveryReceiptBatcher.add({
deliveryReceiptBatcher.add({
messageId,
conversationId,
senderE164: source,

View File

@@ -24,6 +24,7 @@ import {
EventKind as ProvisionEventKind,
type EnvelopeType as ProvisionEnvelopeType,
} from '../../textsecure/Provisioner.js';
import { accountManager } from '../../textsecure/AccountManager.js';
import { getProvisioningResource } from '../../textsecure/WebAPI.js';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js';
import { useBoundActions } from '../../hooks/useBoundActions.js';
@@ -320,9 +321,6 @@ function finishInstall({
cancelByBaton.get(baton)?.();
cancelByBaton.delete(baton);
const accountManager = window.getAccountManager();
strictAssert(accountManager, 'Expected an account manager');
if (isLinkAndSync) {
dispatch({ type: SHOW_BACKUP_IMPORT });
} else {

View File

@@ -3,6 +3,7 @@
import React, { memo } from 'react';
import { useSelector } from 'react-redux';
import { requestVerification as doRequestVerification } from '../../textsecure/WebAPI.js';
import { accountManager } from '../../textsecure/AccountManager.js';
import type { VerificationTransport } from '../../types/VerificationTransport.js';
import { DataWriter } from '../../sql/Client.js';
import { App } from '../../components/App.js';
@@ -79,9 +80,7 @@ function registerSingleDevice(
code: string,
sessionId: string
): Promise<void> {
return window
.getAccountManager()
.registerSingleDevice(number, code, sessionId);
return accountManager.registerSingleDevice(number, code, sessionId);
}
function readyForUpdates(): void {

View File

@@ -1405,3 +1405,5 @@ export default class AccountManager extends EventTarget {
}
}
}
export const accountManager = new AccountManager();

View File

@@ -87,6 +87,7 @@ import EventTarget from './EventTarget.js';
import type { IncomingWebSocketRequest } from './WebsocketResources.js';
import { ServerRequestType } from './WebsocketResources.js';
import { type Storage } from './Storage.js';
import { accountManager } from './AccountManager.js';
import { WarnOnlyError } from './Errors.js';
import * as Bytes from '../Bytes.js';
import type {
@@ -3325,8 +3326,7 @@ export default class MessageReceiver
}
this.#pniIdentityKeyCheckRequired = false;
const manager = window.getAccountManager();
await manager.setPni(updatedPni, {
await accountManager.setPni(updatedPni, {
identityKeyPair,
lastResortKyberPreKey: dropNull(lastResortKyberPreKey),
signedPreKey,

View File

@@ -96,6 +96,7 @@ import { MAX_MESSAGE_COUNT } from '../util/deleteForMe.types.js';
import { isProtoBinaryEncodingEnabled } from '../util/isProtoBinaryEncodingEnabled.js';
import type { GroupSendToken } from '../types/GroupSendEndorsements.js';
import { itemStorage } from './Storage.js';
import { accountManager } from './AccountManager.js';
const log = createLogger('SendMessage');
@@ -1057,7 +1058,6 @@ export class MessageSender {
timestamp: number;
urgent: boolean;
}>): Promise<void> {
const accountManager = window.getAccountManager();
try {
if (accountManager.areKeysOutOfDate(ServiceIdKind.ACI)) {
log.warn(

View File

@@ -10,6 +10,7 @@ import * as Errors from '../types/errors.js';
import { HTTPError } from '../types/HTTPError.js';
import { isOnline } from './WebAPI.js';
import { itemStorage } from './Storage.js';
import { accountManager } from './AccountManager.js';
const log = createLogger('UpdateKeysListener');
@@ -54,8 +55,6 @@ export class UpdateKeysListener {
async #run(): Promise<void> {
log.info('Updating keys...');
try {
const accountManager = window.getAccountManager();
await accountManager.maybeUpdateKeys(ServiceIdKind.ACI);
try {

View File

@@ -0,0 +1,42 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import PQueue from 'p-queue';
import lodash from 'lodash';
import {
conversationJobQueue,
conversationQueueJobEnum,
} from '../jobs/conversationJobQueue.js';
import { ReceiptType } from '../types/Receipt.js';
import type { Receipt } from '../types/Receipt.js';
import { MINUTE } from './durations/index.js';
import { createBatcher } from './batcher.js';
const { groupBy } = lodash;
export const deliveryReceiptQueue = new PQueue({
concurrency: 1,
timeout: MINUTE * 30,
});
deliveryReceiptQueue.pause();
export const deliveryReceiptBatcher = createBatcher<Receipt>({
name: 'deliveryReceiptBatcher',
wait: 500,
maxSize: 100,
processBatch: async deliveryReceipts => {
const groups = groupBy(deliveryReceipts, 'conversationId');
await Promise.all(
Object.keys(groups).map(async conversationId => {
await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.Receipts,
conversationId,
receiptsType: ReceiptType.Delivery,
receipts: groups[conversationId],
});
})
);
},
});

View File

@@ -14,6 +14,10 @@ import { ReadStatus } from '../messages/MessageReadStatus.js';
import { DataWriter } from '../sql/Client.js';
import { drop } from './drop.js';
import { upgradeMessageSchema } from './migrations.js';
import {
deliveryReceiptQueue,
deliveryReceiptBatcher,
} from './deliveryReceipt.js';
import {
cacheAttachmentBySignature,
getCachedAttachmentBySignature,
@@ -315,8 +319,8 @@ export async function handleEditMessage(
// processing incoming messages to start sending outgoing delivery receipts.
// The queue can be paused easily.
drop(
window.Whisper.deliveryReceiptQueue.add(() => {
window.Whisper.deliveryReceiptBatcher.add({
deliveryReceiptQueue.add(() => {
deliveryReceiptBatcher.add({
messageId: mainMessage.id,
conversationId: editAttributes.conversationId,
senderE164: editAttributes.message.source,

View File

@@ -11,6 +11,7 @@ import { createLogger } from '../logging/log.js';
import { toLogFormat } from '../types/errors.js';
import { drop } from './drop.js';
import { itemStorage } from '../textsecure/Storage.js';
import { accountManager } from '../textsecure/AccountManager.js';
const log = createLogger('onDeviceNameChangeSync');
@@ -66,9 +67,7 @@ async function fetchAndUpdateDeviceName() {
let newName: string;
try {
newName = await window
.getAccountManager()
.decryptDeviceName(newNameEncrypted);
newName = await accountManager.decryptDeviceName(newNameEncrypted);
} catch (e) {
const deviceNameWasEncrypted = itemStorage.user.getDeviceNameEncrypted();
log.error(

View File

@@ -21,6 +21,7 @@ import {
padMessage,
SenderCertificateMode,
} from '../textsecure/OutgoingMessage.js';
import { accountManager } from '../textsecure/AccountManager.js';
import { Address } from '../types/Address.js';
import { QualifiedAddress } from '../types/QualifiedAddress.js';
import * as Errors from '../types/errors.js';
@@ -198,7 +199,6 @@ export async function sendContentMessageToGroup(
} = options;
const logId = sendTarget.idForLogging();
const accountManager = window.getAccountManager();
if (accountManager.areKeysOutOfDate(ServiceIdKind.ACI)) {
log.warn(`${logId}: Keys are out of date; updating before send`);
await accountManager.maybeUpdateKeys(ServiceIdKind.ACI);

7
ts/window.d.ts vendored
View File

@@ -6,18 +6,14 @@
import type EventEmitter from 'node:events';
import type { Store } from 'redux';
import type { SystemPreferences } from 'electron';
import type PQueue from 'p-queue/dist.js';
import type { assert } from 'chai';
import type { MochaOptions } from 'mocha';
import type { IPCRequest as IPCChallengeRequest } from './challenge.js';
import type AccountManager from './textsecure/AccountManager.js';
import type { OSType } from './util/os/shared.js';
import type { SystemThemeType, ThemeType } from './types/Util.js';
import type { Receipt } from './types/Receipt.js';
import type { ConversationController } from './ConversationController.js';
import type { ReduxActions } from './state/types.js';
import type { BatcherType } from './util/batcher.js';
import type { ScreenShareStatus } from './types/Calling.js';
import type { MessageCache } from './services/MessageCache.js';
import type { StateType } from './state/reducer.js';
@@ -140,7 +136,6 @@ declare global {
interface Window {
enterKeyboardMode: () => void;
enterMouseMode: () => void;
getAccountManager: () => AccountManager;
getAppInstance: () => string | undefined;
getBuildCreation: () => number;
getBuildExpiration: () => number;
@@ -234,7 +229,5 @@ declare global {
}
export type WhisperType = {
deliveryReceiptQueue: PQueue;
deliveryReceiptBatcher: BatcherType<Receipt>;
events: EventEmitter;
};

View File

@@ -5,7 +5,6 @@ import EventEmitter from 'node:events';
import { ipcRenderer as ipc } from 'electron';
import * as semver from 'semver';
import lodash, { throttle } from 'lodash';
import PQueue from 'p-queue';
import type { IPCType } from '../../window.d.ts';
import { parseIntWithFallback } from '../../util/parseIntWithFallback.js';
@@ -28,18 +27,10 @@ import { UNAUTHENTICATED_CHANNEL_NAME } from '../../textsecure/SocketManager.js'
import { isProduction } from '../../util/version.js';
import { ToastType } from '../../types/Toast.js';
import { ConversationController } from '../../ConversationController.js';
import { createBatcher } from '../../util/batcher.js';
import { ReceiptType } from '../../types/Receipt.js';
import type { Receipt } from '../../types/Receipt.js';
import { MINUTE } from '../../util/durations/index.js';
import {
conversationJobQueue,
conversationQueueJobEnum,
} from '../../jobs/conversationJobQueue.js';
import { isEnabled } from '../../RemoteConfig.js';
import { itemStorage } from '../../textsecure/Storage.js';
const { groupBy, mapValues } = lodash;
const { mapValues } = lodash;
const log = createLogger('phase1-ipc');
@@ -62,28 +53,6 @@ window.RETRY_DELAY = false;
window.Whisper = {
events: new EventEmitter(),
deliveryReceiptQueue: new PQueue({
concurrency: 1,
timeout: MINUTE * 30,
}),
deliveryReceiptBatcher: createBatcher<Receipt>({
name: 'Whisper.deliveryReceiptBatcher',
wait: 500,
maxSize: 100,
processBatch: async deliveryReceipts => {
const groups = groupBy(deliveryReceipts, 'conversationId');
await Promise.all(
Object.keys(groups).map(async conversationId => {
await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.Receipts,
conversationId,
receiptsType: ReceiptType.Delivery,
receipts: groups[conversationId],
});
})
);
},
}),
};
window.ConversationController = new ConversationController();
window.platform = process.platform;