Reinitialize redux after importing a backup
This commit is contained in:
parent
19e0eb4444
commit
abdef4847a
21 changed files with 437 additions and 264 deletions
|
@ -48,11 +48,6 @@ import {
|
|||
update as updateExpiringMessagesService,
|
||||
} from './services/expiringMessagesDeletion';
|
||||
import { tapToViewMessagesDeletionService } from './services/tapToViewMessagesDeletionService';
|
||||
import { getStoriesForRedux, loadStories } from './services/storyLoader';
|
||||
import {
|
||||
getDistributionListsForRedux,
|
||||
loadDistributionLists,
|
||||
} from './services/distributionListLoader';
|
||||
import { senderCertificateService } from './services/senderCertificate';
|
||||
import { GROUP_CREDENTIALS_KEY } from './services/groupCredentialFetcher';
|
||||
import * as KeyboardLayout from './services/keyboardLayout';
|
||||
|
@ -112,7 +107,6 @@ import { UpdateKeysListener } from './textsecure/UpdateKeysListener';
|
|||
import { isDirectConversation } from './util/whatTypeOfConversation';
|
||||
import { BackOff, FIBONACCI_TIMEOUTS } from './util/BackOff';
|
||||
import { AppViewType } from './state/ducks/app';
|
||||
import type { BadgesStateType } from './state/ducks/badges';
|
||||
import { areAnyCallsActiveOrRinging } from './state/selectors/calling';
|
||||
import { badgeImageFileDownloader } from './badges/badgeImageFileDownloader';
|
||||
import * as Deletes from './messageModifiers/Deletes';
|
||||
|
@ -148,10 +142,8 @@ import {
|
|||
import { isAciString } from './util/isAciString';
|
||||
import { normalizeAci } from './util/normalizeAci';
|
||||
import * as log from './logging/log';
|
||||
import { loadRecentEmojis } from './util/loadRecentEmojis';
|
||||
import { deleteAllLogs } from './util/deleteAllLogs';
|
||||
import { startInteractionMode } from './services/InteractionMode';
|
||||
import type { MainWindowStatsType } from './windows/context';
|
||||
import { ReactionSource } from './reactions/ReactionSource';
|
||||
import { singleProtoJobQueue } from './jobs/singleProtoJobQueue';
|
||||
import {
|
||||
|
@ -178,26 +170,15 @@ import {
|
|||
import { RetryPlaceholders } from './util/retryPlaceholders';
|
||||
import { setBatchingStrategy } from './util/messageBatcher';
|
||||
import { parseRemoteClientExpiration } from './util/parseRemoteClientExpiration';
|
||||
import { makeLookup } from './util/makeLookup';
|
||||
import { addGlobalKeyboardShortcuts } from './services/addGlobalKeyboardShortcuts';
|
||||
import { createEventHandler } from './quill/signal-clipboard/util';
|
||||
import { onCallLogEventSync } from './util/onCallLogEventSync';
|
||||
import {
|
||||
getCallsHistoryForRedux,
|
||||
getCallsHistoryUnreadCountForRedux,
|
||||
loadCallsHistory,
|
||||
} from './services/callHistoryLoader';
|
||||
import {
|
||||
getCallLinksForRedux,
|
||||
loadCallLinks,
|
||||
} from './services/callLinksLoader';
|
||||
import { backupsService } from './services/backups';
|
||||
import {
|
||||
getCallIdFromEra,
|
||||
updateLocalGroupCallHistoryTimestamp,
|
||||
} from './util/callDisposition';
|
||||
import { deriveStorageServiceKey } from './Crypto';
|
||||
import { getThemeType } from './util/getThemeType';
|
||||
import { AttachmentDownloadManager } from './jobs/AttachmentDownloadManager';
|
||||
import { onCallLinkUpdateSync } from './util/onCallLinkUpdateSync';
|
||||
import { CallMode } from './types/CallDisposition';
|
||||
|
@ -211,6 +192,7 @@ import { getConversationIdForLogging } from './util/idForLogging';
|
|||
import { encryptConversationAttachments } from './util/encryptConversationAttachments';
|
||||
import { DataReader, DataWriter } from './sql/Client';
|
||||
import { restoreRemoteConfigFromStorage } from './RemoteConfig';
|
||||
import { getParametersForRedux, loadAll } from './services/allLoaders';
|
||||
|
||||
export function isOverHourIntoPast(timestamp: number): boolean {
|
||||
return isNumber(timestamp) && isOlderThan(timestamp, HOUR);
|
||||
|
@ -255,13 +237,6 @@ export async function startApp(): Promise<void> {
|
|||
|
||||
await initializeMessageCounter();
|
||||
|
||||
let initialBadgesState: BadgesStateType = { byId: {} };
|
||||
async function loadInitialBadgesState(): Promise<void> {
|
||||
initialBadgesState = {
|
||||
byId: makeLookup(await DataReader.getAllBadges(), 'id'),
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize WebAPI as early as possible
|
||||
let server: WebAPIType | undefined;
|
||||
let messageReceiver: MessageReceiver | undefined;
|
||||
|
@ -1110,21 +1085,6 @@ export async function startApp(): Promise<void> {
|
|||
drop(window.Events.cleanupDownloads());
|
||||
}, DAY);
|
||||
|
||||
let mainWindowStats = {
|
||||
isMaximized: false,
|
||||
isFullScreen: false,
|
||||
};
|
||||
|
||||
let menuOptions = {
|
||||
development: false,
|
||||
devTools: false,
|
||||
includeSetup: false,
|
||||
isProduction: true,
|
||||
platform: 'unknown',
|
||||
};
|
||||
|
||||
let theme: ThemeType = window.systemTheme;
|
||||
|
||||
try {
|
||||
// This needs to load before we prime the data because we expect
|
||||
// ConversationController to be loaded and ready to use by then.
|
||||
|
@ -1132,23 +1092,8 @@ export async function startApp(): Promise<void> {
|
|||
|
||||
await Promise.all([
|
||||
window.ConversationController.getOrCreateSignalConversation(),
|
||||
Stickers.load(),
|
||||
loadRecentEmojis(),
|
||||
loadInitialBadgesState(),
|
||||
loadStories(),
|
||||
loadDistributionLists(),
|
||||
loadCallsHistory(),
|
||||
loadCallLinks(),
|
||||
window.textsecure.storage.protocol.hydrateCaches(),
|
||||
(async () => {
|
||||
mainWindowStats = await window.SignalContext.getMainWindowStats();
|
||||
})(),
|
||||
(async () => {
|
||||
menuOptions = await window.SignalContext.getMenuOptions();
|
||||
})(),
|
||||
(async () => {
|
||||
theme = await getThemeType();
|
||||
})(),
|
||||
loadAll(),
|
||||
]);
|
||||
await window.ConversationController.checkForConflicts();
|
||||
} catch (error) {
|
||||
|
@ -1157,7 +1102,7 @@ export async function startApp(): Promise<void> {
|
|||
Errors.toLogFormat(error)
|
||||
);
|
||||
} finally {
|
||||
setupAppState({ mainWindowStats, menuOptions, theme });
|
||||
setupAppState();
|
||||
drop(start());
|
||||
window.Signal.Services.initializeNetworkObserver(
|
||||
window.reduxActions.network
|
||||
|
@ -1189,26 +1134,8 @@ export async function startApp(): Promise<void> {
|
|||
log.info('Storage fetch');
|
||||
drop(window.storage.fetch());
|
||||
|
||||
function setupAppState({
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
theme,
|
||||
}: {
|
||||
mainWindowStats: MainWindowStatsType;
|
||||
menuOptions: MenuOptionsType;
|
||||
theme: ThemeType;
|
||||
}) {
|
||||
initializeRedux({
|
||||
callLinks: getCallLinksForRedux(),
|
||||
callsHistory: getCallsHistoryForRedux(),
|
||||
callsHistoryUnreadCount: getCallsHistoryUnreadCountForRedux(),
|
||||
initialBadgesState,
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
stories: getStoriesForRedux(),
|
||||
storyDistributionLists: getDistributionListsForRedux(),
|
||||
theme,
|
||||
});
|
||||
function setupAppState() {
|
||||
initializeRedux(getParametersForRedux());
|
||||
|
||||
// Here we set up a full redux store with initial state for our LeftPane Root
|
||||
const convoCollection = window.getConversations();
|
||||
|
|
60
ts/services/allLoaders.ts
Normal file
60
ts/services/allLoaders.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// loader services
|
||||
import { getBadgesForRedux, loadBadges } from './badgeLoader';
|
||||
import {
|
||||
getCallsHistoryForRedux,
|
||||
getCallsHistoryUnreadCountForRedux,
|
||||
loadCallHistory,
|
||||
} from './callHistoryLoader';
|
||||
import { getCallLinksForRedux, loadCallLinks } from './callLinksLoader';
|
||||
import {
|
||||
getDistributionListsForRedux,
|
||||
loadDistributionLists,
|
||||
} from './distributionListLoader';
|
||||
import { getStoriesForRedux, loadStories } from './storyLoader';
|
||||
import { getUserDataForRedux, loadUserData } from './userLoader';
|
||||
|
||||
// old-style loaders
|
||||
import {
|
||||
getEmojiReducerState,
|
||||
loadRecentEmojis,
|
||||
} from '../util/loadRecentEmojis';
|
||||
import {
|
||||
load as loadStickers,
|
||||
getInitialState as getStickersReduxState,
|
||||
} from '../types/Stickers';
|
||||
|
||||
import type { ReduxInitData } from '../state/initializeRedux';
|
||||
|
||||
export async function loadAll(): Promise<void> {
|
||||
await Promise.all([
|
||||
loadBadges(),
|
||||
loadCallHistory(),
|
||||
loadCallLinks(),
|
||||
loadDistributionLists(),
|
||||
loadRecentEmojis(),
|
||||
loadStickers(),
|
||||
loadStories(),
|
||||
loadUserData(),
|
||||
]);
|
||||
}
|
||||
|
||||
export function getParametersForRedux(): ReduxInitData {
|
||||
const { mainWindowStats, menuOptions, theme } = getUserDataForRedux();
|
||||
|
||||
return {
|
||||
badgesState: getBadgesForRedux(),
|
||||
callHistory: getCallsHistoryForRedux(),
|
||||
callHistoryUnreadCount: getCallsHistoryUnreadCountForRedux(),
|
||||
callLinks: getCallLinksForRedux(),
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
recentEmoji: getEmojiReducerState(),
|
||||
stickers: getStickersReduxState(),
|
||||
stories: getStoriesForRedux(),
|
||||
storyDistributionLists: getDistributionListsForRedux(),
|
||||
theme,
|
||||
};
|
||||
}
|
|
@ -88,7 +88,6 @@ import { canBeSynced as canPreferredReactionEmojiBeSynced } from '../../reaction
|
|||
import { SendStatus } from '../../messages/MessageSendState';
|
||||
import { BACKUP_VERSION } from './constants';
|
||||
import { getMessageIdForLogging } from '../../util/idForLogging';
|
||||
import { getCallsHistoryForRedux } from '../callHistoryLoader';
|
||||
import { makeLookup } from '../../util/makeLookup';
|
||||
import type {
|
||||
CallHistoryDetails,
|
||||
|
@ -470,7 +469,7 @@ export class BackupExportStream extends Readable {
|
|||
|
||||
let cursor: PageMessagesCursorType | undefined;
|
||||
|
||||
const callHistory = getCallsHistoryForRedux();
|
||||
const callHistory = await DataReader.getAllCallHistory();
|
||||
const callHistoryByCallId = makeLookup(callHistory, 'callId');
|
||||
|
||||
const me = window.ConversationController.getOurConversationOrThrow();
|
||||
|
|
|
@ -34,6 +34,8 @@ import { getKeyMaterial } from './crypto';
|
|||
import { BackupCredentials } from './credentials';
|
||||
import { BackupAPI } from './api';
|
||||
import { validateBackup } from './validator';
|
||||
import { reinitializeRedux } from '../../state/reinitializeRedux';
|
||||
import { getParametersForRedux, loadAll } from '../allLoaders';
|
||||
|
||||
const IV_LENGTH = 16;
|
||||
|
||||
|
@ -192,14 +194,27 @@ export class BackupsService {
|
|||
'importBackup: Bad MAC, second pass'
|
||||
);
|
||||
|
||||
await this.resetStateAfterImport();
|
||||
|
||||
log.info('importBackup: finished...');
|
||||
} catch (error) {
|
||||
log.info(`importBackup: failed, error: ${Errors.toLogFormat(error)}`);
|
||||
throw error;
|
||||
} finally {
|
||||
this.isRunning = false;
|
||||
|
||||
if (window.SignalCI) {
|
||||
window.SignalCI.handleEvent('backupImportComplete', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async resetStateAfterImport(): Promise<void> {
|
||||
window.ConversationController.reset();
|
||||
await window.ConversationController.load();
|
||||
await loadAll();
|
||||
reinitializeRedux(getParametersForRedux());
|
||||
}
|
||||
|
||||
public async fetchAndSaveBackupCdnObjectMetadata(): Promise<void> {
|
||||
log.info('fetchAndSaveBackupCdnObjectMetadata: clearing existing metadata');
|
||||
|
|
22
ts/services/badgeLoader.ts
Normal file
22
ts/services/badgeLoader.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { DataReader } from '../sql/Client';
|
||||
import { strictAssert } from '../util/assert';
|
||||
import { makeLookup } from '../util/makeLookup';
|
||||
|
||||
import type { BadgeType } from '../badges/types';
|
||||
import type { BadgesStateType } from '../state/ducks/badges';
|
||||
|
||||
let badges: Array<BadgeType> | undefined;
|
||||
|
||||
export async function loadBadges(): Promise<void> {
|
||||
badges = await DataReader.getAllBadges();
|
||||
}
|
||||
|
||||
export function getBadgesForRedux(): BadgesStateType {
|
||||
strictAssert(badges != null, 'badges have not been loaded');
|
||||
return {
|
||||
byId: makeLookup(badges, 'id'),
|
||||
};
|
||||
}
|
|
@ -8,7 +8,7 @@ import { strictAssert } from '../util/assert';
|
|||
let callsHistoryData: ReadonlyArray<CallHistoryDetails>;
|
||||
let callsHistoryUnreadCount: number;
|
||||
|
||||
export async function loadCallsHistory(): Promise<void> {
|
||||
export async function loadCallHistory(): Promise<void> {
|
||||
await DataWriter.cleanupCallHistoryMessages();
|
||||
callsHistoryData = await DataReader.getAllCallHistory();
|
||||
callsHistoryUnreadCount = await DataReader.getCallHistoryUnreadCount();
|
||||
|
|
39
ts/services/userLoader.ts
Normal file
39
ts/services/userLoader.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { strictAssert } from '../util/assert';
|
||||
import { getThemeType } from '../util/getThemeType';
|
||||
|
||||
import type { MenuOptionsType } from '../types/menu';
|
||||
import type { MainWindowStatsType } from '../windows/context';
|
||||
import type { ThemeType } from '../types/Util';
|
||||
|
||||
let mainWindowStats: MainWindowStatsType | undefined;
|
||||
let menuOptions: MenuOptionsType | undefined;
|
||||
let theme: ThemeType | undefined;
|
||||
|
||||
export async function loadUserData(): Promise<void> {
|
||||
await Promise.all([
|
||||
(async () => {
|
||||
mainWindowStats = await window.SignalContext.getMainWindowStats();
|
||||
})(),
|
||||
(async () => {
|
||||
menuOptions = await window.SignalContext.getMenuOptions();
|
||||
})(),
|
||||
(async () => {
|
||||
theme = await getThemeType();
|
||||
})(),
|
||||
]);
|
||||
}
|
||||
|
||||
export function getUserDataForRedux(): {
|
||||
mainWindowStats: MainWindowStatsType;
|
||||
menuOptions: MenuOptionsType;
|
||||
theme: ThemeType;
|
||||
} {
|
||||
strictAssert(
|
||||
mainWindowStats != null && menuOptions != null && theme != null,
|
||||
'user data has not been loaded'
|
||||
);
|
||||
return { mainWindowStats, menuOptions, theme };
|
||||
}
|
|
@ -26,7 +26,7 @@ import {
|
|||
import {
|
||||
getCallsHistoryForRedux,
|
||||
getCallsHistoryUnreadCountForRedux,
|
||||
loadCallsHistory,
|
||||
loadCallHistory,
|
||||
} from '../../services/callHistoryLoader';
|
||||
import { makeLookup } from '../../util/makeLookup';
|
||||
|
||||
|
@ -217,7 +217,7 @@ export function reloadCallHistory(): ThunkAction<
|
|||
> {
|
||||
return async dispatch => {
|
||||
try {
|
||||
await loadCallsHistory();
|
||||
await loadCallHistory();
|
||||
const callsHistory = getCallsHistoryForRedux();
|
||||
const callsHistoryUnreadCount = getCallsHistoryUnreadCountForRedux();
|
||||
dispatch({
|
||||
|
@ -234,6 +234,7 @@ export const actions = {
|
|||
addCallHistory,
|
||||
removeCallHistory,
|
||||
resetCallHistory,
|
||||
reloadCallHistory,
|
||||
clearAllCallHistory,
|
||||
updateCallHistoryUnreadCount,
|
||||
markCallHistoryRead,
|
||||
|
|
|
@ -59,7 +59,7 @@ function useEmoji(payload: string): UseEmojiAction {
|
|||
|
||||
// Reducer
|
||||
|
||||
function getEmptyState(): EmojisStateType {
|
||||
export function getEmptyState(): EmojisStateType {
|
||||
return {
|
||||
recents: [],
|
||||
};
|
||||
|
|
|
@ -1,75 +1,175 @@
|
|||
// Copyright 2022 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { getEmptyState as accounts } from './ducks/accounts';
|
||||
import { getEmptyState as app } from './ducks/app';
|
||||
import { getEmptyState as audioPlayer } from './ducks/audioPlayer';
|
||||
import { getEmptyState as audioRecorder } from './ducks/audioRecorder';
|
||||
import { getEmptyState as callHistory } from './ducks/callHistory';
|
||||
import { getEmptyState as calling } from './ducks/calling';
|
||||
import { getEmptyState as composer } from './ducks/composer';
|
||||
import { getEmptyState as conversations } from './ducks/conversations';
|
||||
import { getEmptyState as crashReports } from './ducks/crashReports';
|
||||
import { getEmptyState as expiration } from './ducks/expiration';
|
||||
import { getEmptyState as globalModals } from './ducks/globalModals';
|
||||
import { getEmptyState as inbox } from './ducks/inbox';
|
||||
import { getEmptyState as lightbox } from './ducks/lightbox';
|
||||
import { getEmptyState as linkPreviews } from './ducks/linkPreviews';
|
||||
import { getEmptyState as mediaGallery } from './ducks/mediaGallery';
|
||||
import { getEmptyState as nav } from './ducks/nav';
|
||||
import { getEmptyState as network } from './ducks/network';
|
||||
import { getEmptyState as preferredReactions } from './ducks/preferredReactions';
|
||||
import { getEmptyState as safetyNumber } from './ducks/safetyNumber';
|
||||
import { getEmptyState as search } from './ducks/search';
|
||||
import { getEmptyState as getStoriesEmptyState } from './ducks/stories';
|
||||
import { getEmptyState as getStoryDistributionListsEmptyState } from './ducks/storyDistributionLists';
|
||||
import { getEmptyState as getToastEmptyState } from './ducks/toast';
|
||||
import { getEmptyState as updates } from './ducks/updates';
|
||||
import { getEmptyState as user } from './ducks/user';
|
||||
import { getEmptyState as username } from './ducks/username';
|
||||
import { getEmptyState as accountsEmptyState } from './ducks/accounts';
|
||||
import { getEmptyState as appEmptyState } from './ducks/app';
|
||||
import { getEmptyState as audioPlayerEmptyState } from './ducks/audioPlayer';
|
||||
import { getEmptyState as audioRecorderEmptyState } from './ducks/audioRecorder';
|
||||
import { getEmptyState as badgesEmptyState } from './ducks/badges';
|
||||
import { getEmptyState as callHistoryEmptyState } from './ducks/callHistory';
|
||||
import { getEmptyState as callingEmptyState } from './ducks/calling';
|
||||
import { getEmptyState as composerEmptyState } from './ducks/composer';
|
||||
import { getEmptyState as conversationsEmptyState } from './ducks/conversations';
|
||||
import { getEmptyState as crashReportsEmptyState } from './ducks/crashReports';
|
||||
import { getEmptyState as emojiEmptyState } from './ducks/emojis';
|
||||
import { getEmptyState as itemsEmptyState } from './ducks/items';
|
||||
import { getEmptyState as stickersEmptyState } from './ducks/stickers';
|
||||
import { getEmptyState as expirationEmptyState } from './ducks/expiration';
|
||||
import { getEmptyState as globalModalsEmptyState } from './ducks/globalModals';
|
||||
import { getEmptyState as inboxEmptyState } from './ducks/inbox';
|
||||
import { getEmptyState as lightboxEmptyState } from './ducks/lightbox';
|
||||
import { getEmptyState as linkPreviewsEmptyState } from './ducks/linkPreviews';
|
||||
import { getEmptyState as mediaGalleryEmptyState } from './ducks/mediaGallery';
|
||||
import { getEmptyState as navEmptyState } from './ducks/nav';
|
||||
import { getEmptyState as networkEmptyState } from './ducks/network';
|
||||
import { getEmptyState as preferredReactionsEmptyState } from './ducks/preferredReactions';
|
||||
import { getEmptyState as safetyNumberEmptyState } from './ducks/safetyNumber';
|
||||
import { getEmptyState as searchEmptyState } from './ducks/search';
|
||||
import { getEmptyState as storiesEmptyState } from './ducks/stories';
|
||||
import { getEmptyState as storyDistributionListsEmptyState } from './ducks/storyDistributionLists';
|
||||
import { getEmptyState as toastEmptyState } from './ducks/toast';
|
||||
import { getEmptyState as updatesEmptyState } from './ducks/updates';
|
||||
import { getEmptyState as userEmptyState } from './ducks/user';
|
||||
import { getEmptyState as usernameEmptyState } from './ducks/username';
|
||||
|
||||
import type { StateType } from './reducer';
|
||||
import type { BadgesStateType } from './ducks/badges';
|
||||
import type { MainWindowStatsType } from '../windows/context';
|
||||
import type { MenuOptionsType } from '../types/menu';
|
||||
import type { StoryDataType } from './ducks/stories';
|
||||
import type { StoryDistributionListDataType } from './ducks/storyDistributionLists';
|
||||
import OS from '../util/os/osMain';
|
||||
import { getEmojiReducerState as emojis } from '../util/loadRecentEmojis';
|
||||
import { getInitialState as stickers } from '../types/Stickers';
|
||||
import { getInteractionMode } from '../services/InteractionMode';
|
||||
import { makeLookup } from '../util/makeLookup';
|
||||
import type { CallHistoryDetails } from '../types/CallDisposition';
|
||||
import type { ThemeType } from '../types/Util';
|
||||
import type { CallLinkType } from '../types/CallLink';
|
||||
|
||||
export function getInitialState({
|
||||
badges,
|
||||
import type { StateType } from './reducer';
|
||||
import type { MainWindowStatsType } from '../windows/context';
|
||||
import type { ConversationsStateType } from './ducks/conversations';
|
||||
import type { MenuOptionsType } from '../types/menu';
|
||||
import type {
|
||||
StoryDistributionListDataType,
|
||||
StoryDistributionListStateType,
|
||||
} from './ducks/storyDistributionLists';
|
||||
import type { ThemeType } from '../types/Util';
|
||||
import type { UserStateType } from './ducks/user';
|
||||
import type { ReduxInitData } from './initializeRedux';
|
||||
|
||||
export function getInitialState(
|
||||
{
|
||||
badgesState,
|
||||
callLinks,
|
||||
callsHistory,
|
||||
callsHistoryUnreadCount,
|
||||
callHistory: calls,
|
||||
callHistoryUnreadCount,
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
recentEmoji,
|
||||
stickers,
|
||||
stories,
|
||||
storyDistributionLists,
|
||||
theme,
|
||||
}: ReduxInitData,
|
||||
existingState?: StateType
|
||||
): StateType {
|
||||
const items = window.storage.getItemsState();
|
||||
|
||||
const baseState: StateType = existingState ?? getEmptyState();
|
||||
|
||||
return {
|
||||
...baseState,
|
||||
badges: badgesState,
|
||||
callHistory: {
|
||||
...callHistoryEmptyState(),
|
||||
callHistoryByCallId: makeLookup(calls, 'callId'),
|
||||
unreadCount: callHistoryUnreadCount,
|
||||
},
|
||||
calling: {
|
||||
...callingEmptyState(),
|
||||
callLinks: makeLookup(callLinks, 'roomId'),
|
||||
},
|
||||
emojis: recentEmoji,
|
||||
items,
|
||||
stickers,
|
||||
stories: {
|
||||
...storiesEmptyState(),
|
||||
stories,
|
||||
},
|
||||
storyDistributionLists: generateStoryDistributionListState(
|
||||
storyDistributionLists
|
||||
),
|
||||
user: generateUserState({
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
theme,
|
||||
}: {
|
||||
badges: BadgesStateType;
|
||||
callLinks: ReadonlyArray<CallLinkType>;
|
||||
callsHistory: ReadonlyArray<CallHistoryDetails>;
|
||||
callsHistoryUnreadCount: number;
|
||||
stories: Array<StoryDataType>;
|
||||
storyDistributionLists: Array<StoryDistributionListDataType>;
|
||||
mainWindowStats: MainWindowStatsType;
|
||||
menuOptions: MenuOptionsType;
|
||||
theme: ThemeType;
|
||||
}): StateType {
|
||||
const items = window.storage.getItemsState();
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function generateConversationsState(): ConversationsStateType {
|
||||
const convoCollection = window.getConversations();
|
||||
const formattedConversations = convoCollection.map(conversation =>
|
||||
conversation.format()
|
||||
);
|
||||
|
||||
return {
|
||||
...conversationsEmptyState(),
|
||||
conversationLookup: makeLookup(formattedConversations, 'id'),
|
||||
conversationsByE164: makeLookup(formattedConversations, 'e164'),
|
||||
conversationsByServiceId: {
|
||||
...makeLookup(formattedConversations, 'serviceId'),
|
||||
...makeLookup(formattedConversations, 'pni'),
|
||||
},
|
||||
conversationsByGroupId: makeLookup(formattedConversations, 'groupId'),
|
||||
conversationsByUsername: makeLookup(formattedConversations, 'username'),
|
||||
};
|
||||
}
|
||||
|
||||
function getEmptyState(): StateType {
|
||||
return {
|
||||
accounts: accountsEmptyState(),
|
||||
app: appEmptyState(),
|
||||
audioPlayer: audioPlayerEmptyState(),
|
||||
audioRecorder: audioRecorderEmptyState(),
|
||||
badges: badgesEmptyState(),
|
||||
callHistory: callHistoryEmptyState(),
|
||||
calling: callingEmptyState(),
|
||||
composer: composerEmptyState(),
|
||||
conversations: generateConversationsState(),
|
||||
crashReports: crashReportsEmptyState(),
|
||||
emojis: emojiEmptyState(),
|
||||
expiration: expirationEmptyState(),
|
||||
globalModals: globalModalsEmptyState(),
|
||||
inbox: inboxEmptyState(),
|
||||
items: itemsEmptyState(),
|
||||
lightbox: lightboxEmptyState(),
|
||||
linkPreviews: linkPreviewsEmptyState(),
|
||||
mediaGallery: mediaGalleryEmptyState(),
|
||||
nav: navEmptyState(),
|
||||
network: networkEmptyState(),
|
||||
preferredReactions: preferredReactionsEmptyState(),
|
||||
safetyNumber: safetyNumberEmptyState(),
|
||||
search: searchEmptyState(),
|
||||
stickers: stickersEmptyState(),
|
||||
stories: storiesEmptyState(),
|
||||
storyDistributionLists: storyDistributionListsEmptyState(),
|
||||
toast: toastEmptyState(),
|
||||
updates: updatesEmptyState(),
|
||||
user: userEmptyState(),
|
||||
username: usernameEmptyState(),
|
||||
};
|
||||
}
|
||||
|
||||
export function generateStoryDistributionListState(
|
||||
storyDistributionLists: ReadonlyArray<StoryDistributionListDataType>
|
||||
): StoryDistributionListStateType {
|
||||
return {
|
||||
...storyDistributionListsEmptyState(),
|
||||
distributionLists: storyDistributionLists || [],
|
||||
};
|
||||
}
|
||||
|
||||
export function generateUserState({
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
theme,
|
||||
}: {
|
||||
mainWindowStats: MainWindowStatsType;
|
||||
menuOptions: MenuOptionsType;
|
||||
theme: ThemeType;
|
||||
}): UserStateType {
|
||||
const ourNumber = window.textsecure.storage.user.getNumber();
|
||||
const ourAci = window.textsecure.storage.user.getAci();
|
||||
const ourPni = window.textsecure.storage.user.getPni();
|
||||
|
@ -88,59 +188,7 @@ export function getInitialState({
|
|||
}
|
||||
|
||||
return {
|
||||
accounts: accounts(),
|
||||
app: app(),
|
||||
audioPlayer: audioPlayer(),
|
||||
audioRecorder: audioRecorder(),
|
||||
badges,
|
||||
callHistory: {
|
||||
...callHistory(),
|
||||
callHistoryByCallId: makeLookup(callsHistory, 'callId'),
|
||||
unreadCount: callsHistoryUnreadCount,
|
||||
},
|
||||
calling: {
|
||||
...calling(),
|
||||
callLinks: makeLookup(callLinks, 'roomId'),
|
||||
},
|
||||
composer: composer(),
|
||||
conversations: {
|
||||
...conversations(),
|
||||
conversationLookup: makeLookup(formattedConversations, 'id'),
|
||||
conversationsByE164: makeLookup(formattedConversations, 'e164'),
|
||||
conversationsByServiceId: {
|
||||
...makeLookup(formattedConversations, 'serviceId'),
|
||||
...makeLookup(formattedConversations, 'pni'),
|
||||
},
|
||||
conversationsByGroupId: makeLookup(formattedConversations, 'groupId'),
|
||||
conversationsByUsername: makeLookup(formattedConversations, 'username'),
|
||||
},
|
||||
crashReports: crashReports(),
|
||||
emojis: emojis(),
|
||||
expiration: expiration(),
|
||||
globalModals: globalModals(),
|
||||
inbox: inbox(),
|
||||
items,
|
||||
lightbox: lightbox(),
|
||||
linkPreviews: linkPreviews(),
|
||||
mediaGallery: mediaGallery(),
|
||||
nav: nav(),
|
||||
network: network(),
|
||||
preferredReactions: preferredReactions(),
|
||||
safetyNumber: safetyNumber(),
|
||||
search: search(),
|
||||
stickers: stickers(),
|
||||
stories: {
|
||||
...getStoriesEmptyState(),
|
||||
stories,
|
||||
},
|
||||
storyDistributionLists: {
|
||||
...getStoryDistributionListsEmptyState(),
|
||||
distributionLists: storyDistributionLists || [],
|
||||
},
|
||||
toast: getToastEmptyState(),
|
||||
updates: updates(),
|
||||
user: {
|
||||
...user(),
|
||||
...userEmptyState(),
|
||||
attachmentsPath: window.BasePaths.attachments,
|
||||
i18n: window.i18n,
|
||||
interactionMode: getInteractionMode(),
|
||||
|
@ -160,7 +208,5 @@ export function getInitialState({
|
|||
tempPath: window.BasePaths.temp,
|
||||
theme,
|
||||
version: window.getVersion(),
|
||||
},
|
||||
username: username(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,50 +2,37 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { actionCreators } from './actions';
|
||||
import { createStore } from './createStore';
|
||||
import { getInitialState } from './getInitialState';
|
||||
|
||||
import type { BadgesStateType } from './ducks/badges';
|
||||
import type { CallHistoryDetails } from '../types/CallDisposition';
|
||||
import type { MainWindowStatsType } from '../windows/context';
|
||||
import type { MenuOptionsType } from '../types/menu';
|
||||
import type { StoryDataType } from './ducks/stories';
|
||||
import type { StoryDistributionListDataType } from './ducks/storyDistributionLists';
|
||||
import { actionCreators } from './actions';
|
||||
import { createStore } from './createStore';
|
||||
import { getInitialState } from './getInitialState';
|
||||
import type { ThemeType } from '../types/Util';
|
||||
import type { CallLinkType } from '../types/CallLink';
|
||||
import type { RecentEmojiObjectType } from '../util/loadRecentEmojis';
|
||||
import type { StickersStateType } from './ducks/stickers';
|
||||
|
||||
export function initializeRedux({
|
||||
callLinks,
|
||||
callsHistory,
|
||||
callsHistoryUnreadCount,
|
||||
initialBadgesState,
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
stories,
|
||||
storyDistributionLists,
|
||||
theme,
|
||||
}: {
|
||||
export type ReduxInitData = {
|
||||
badgesState: BadgesStateType;
|
||||
callHistory: ReadonlyArray<CallHistoryDetails>;
|
||||
callHistoryUnreadCount: number;
|
||||
callLinks: ReadonlyArray<CallLinkType>;
|
||||
callsHistory: ReadonlyArray<CallHistoryDetails>;
|
||||
callsHistoryUnreadCount: number;
|
||||
initialBadgesState: BadgesStateType;
|
||||
mainWindowStats: MainWindowStatsType;
|
||||
menuOptions: MenuOptionsType;
|
||||
recentEmoji: RecentEmojiObjectType;
|
||||
stickers: StickersStateType;
|
||||
stories: Array<StoryDataType>;
|
||||
storyDistributionLists: Array<StoryDistributionListDataType>;
|
||||
theme: ThemeType;
|
||||
}): void {
|
||||
const initialState = getInitialState({
|
||||
badges: initialBadgesState,
|
||||
callLinks,
|
||||
callsHistory,
|
||||
callsHistoryUnreadCount,
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
stories,
|
||||
storyDistributionLists,
|
||||
theme,
|
||||
});
|
||||
};
|
||||
|
||||
export function initializeRedux(data: ReduxInitData): void {
|
||||
const initialState = getInitialState(data);
|
||||
|
||||
const store = createStore(initialState);
|
||||
window.reduxStore = store;
|
||||
|
|
57
ts/state/reinitializeRedux.ts
Normal file
57
ts/state/reinitializeRedux.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { AnyAction } from 'redux';
|
||||
|
||||
import * as log from '../logging/log';
|
||||
import { getInitialState } from './getInitialState';
|
||||
import { reducer as normalReducer } from './reducer';
|
||||
|
||||
import type { StateType } from './reducer';
|
||||
import type { ReduxInitData } from './initializeRedux';
|
||||
|
||||
const REPLACE_STATE = 'resetReducer/REPLACE';
|
||||
|
||||
export function reinitializeRedux(options: ReduxInitData): void {
|
||||
const logId = 'initializeRedux';
|
||||
const existingState = window.reduxStore.getState();
|
||||
const newInitialState = getInitialState(options, existingState);
|
||||
|
||||
const resetReducer = (
|
||||
state: StateType | undefined,
|
||||
action: AnyAction
|
||||
): StateType => {
|
||||
if (state == null) {
|
||||
log.info(
|
||||
`${logId}/resetReducer: Got null incoming state, returning newInitialState`
|
||||
);
|
||||
return newInitialState;
|
||||
}
|
||||
|
||||
const { type } = action;
|
||||
if (type === REPLACE_STATE) {
|
||||
log.info(
|
||||
`${logId}/resetReducer: Got REPLACE_STATE action, returning newInitialState`
|
||||
);
|
||||
return newInitialState;
|
||||
}
|
||||
|
||||
log.info(
|
||||
`${logId}/resetReducer: Got action with type ${type}, returning original state`
|
||||
);
|
||||
return state;
|
||||
};
|
||||
|
||||
log.info(`${logId}: installing resetReducer`);
|
||||
window.reduxStore.replaceReducer(resetReducer);
|
||||
|
||||
log.info(`${logId}: dispatching REPLACE_STATE event`);
|
||||
window.reduxStore.dispatch({
|
||||
type: REPLACE_STATE,
|
||||
});
|
||||
|
||||
log.info(`${logId}: restoring original reducer`);
|
||||
window.reduxStore.replaceReducer(normalReducer);
|
||||
|
||||
log.info(`${logId}: complete!`);
|
||||
}
|
|
@ -14,7 +14,6 @@ import { DataWriter } from '../../sql/Client';
|
|||
import { type AciString, generateAci } from '../../types/ServiceId';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||
import { setupBasics, asymmetricRoundtripHarness } from './helpers';
|
||||
import {
|
||||
AUDIO_MP3,
|
||||
|
@ -31,6 +30,7 @@ import { isVoiceMessage, type AttachmentType } from '../../types/Attachment';
|
|||
import { strictAssert } from '../../util/assert';
|
||||
import { SignalService } from '../../protobuf';
|
||||
import { getRandomBytes } from '../../Crypto';
|
||||
import { loadAll } from '../../services/allLoaders';
|
||||
|
||||
const CONTACT_A = generateAci();
|
||||
|
||||
|
@ -51,7 +51,7 @@ describe('backup/attachments', () => {
|
|||
{ systemGivenName: 'CONTACT_A' }
|
||||
);
|
||||
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
|
||||
sandbox = sinon.createSandbox();
|
||||
const getAbsoluteAttachmentPath = sandbox.stub(
|
||||
|
|
|
@ -12,7 +12,6 @@ import type { MessageAttributesType } from '../../model-types';
|
|||
import type { GroupV2ChangeType } from '../../groups';
|
||||
import { getRandomBytes } from '../../Crypto';
|
||||
import * as Bytes from '../../Bytes';
|
||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||
import { strictAssert } from '../../util/assert';
|
||||
import { DurationInSeconds } from '../../util/durations';
|
||||
import {
|
||||
|
@ -24,6 +23,7 @@ import {
|
|||
} from './helpers';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
import { loadAll } from '../../services/allLoaders';
|
||||
|
||||
// Note: this should be kept up to date with GroupV2Change.stories.tsx, to
|
||||
// maintain the comprehensive set of GroupV2 notifications we need to handle
|
||||
|
@ -114,7 +114,7 @@ describe('backup/groupv2/notifications', () => {
|
|||
name: 'Rock Enthusiasts',
|
||||
});
|
||||
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await DataWriter.removeAll();
|
||||
|
|
|
@ -13,7 +13,6 @@ import * as Bytes from '../../Bytes';
|
|||
import { generateAci } from '../../types/ServiceId';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||
import { ID_V1_LENGTH } from '../../groups';
|
||||
import { DurationInSeconds, WEEK } from '../../util/durations';
|
||||
import {
|
||||
|
@ -22,6 +21,7 @@ import {
|
|||
symmetricRoundtripHarness,
|
||||
OUR_ACI,
|
||||
} from './helpers';
|
||||
import { loadAll } from '../../services/allLoaders';
|
||||
|
||||
const CONTACT_A = generateAci();
|
||||
const CONTACT_B = generateAci();
|
||||
|
@ -67,7 +67,7 @@ describe('backup/bubble messages', () => {
|
|||
}
|
||||
);
|
||||
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
});
|
||||
|
||||
it('roundtrips incoming edited message', async () => {
|
||||
|
|
|
@ -14,7 +14,6 @@ import * as Bytes from '../../Bytes';
|
|||
import { getRandomBytes } from '../../Crypto';
|
||||
import { DataReader, DataWriter } from '../../sql/Client';
|
||||
import { generateAci } from '../../types/ServiceId';
|
||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||
import { setupBasics, symmetricRoundtripHarness } from './helpers';
|
||||
import {
|
||||
AdhocCallStatus,
|
||||
|
@ -30,6 +29,7 @@ import { fromAdminKeyBytes } from '../../util/callLinks';
|
|||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
import { deriveGroupID, deriveGroupSecretParams } from '../../util/zkgroup';
|
||||
import { loadAll } from '../../services/allLoaders';
|
||||
|
||||
const CONTACT_A = generateAci();
|
||||
const GROUP_MASTER_KEY = getRandomBytes(32);
|
||||
|
@ -78,7 +78,7 @@ describe('backup/calling', () => {
|
|||
|
||||
await DataWriter.insertCallLink(callLink);
|
||||
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
});
|
||||
after(async () => {
|
||||
await DataWriter.removeAll();
|
||||
|
@ -99,7 +99,7 @@ describe('backup/calling', () => {
|
|||
timestamp: now,
|
||||
};
|
||||
await DataWriter.saveCallHistory(callHistory);
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
|
||||
const messageUnseen: MessageAttributesType = {
|
||||
id: generateGuid(),
|
||||
|
@ -146,7 +146,7 @@ describe('backup/calling', () => {
|
|||
timestamp: now,
|
||||
};
|
||||
await DataWriter.saveCallHistory(callHistory);
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
|
||||
const messageUnseen: MessageAttributesType = {
|
||||
id: generateGuid(),
|
||||
|
@ -231,7 +231,7 @@ describe('backup/calling', () => {
|
|||
timestamp: now,
|
||||
};
|
||||
await DataWriter.saveCallHistory(callHistory);
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
|
||||
await symmetricRoundtripHarness([]);
|
||||
|
||||
|
@ -255,7 +255,7 @@ describe('backup/calling', () => {
|
|||
timestamp: now,
|
||||
};
|
||||
await DataWriter.saveCallHistory(callHistory);
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
|
||||
await symmetricRoundtripHarness([]);
|
||||
|
||||
|
|
|
@ -18,13 +18,13 @@ import { MessageRequestResponseEvent } from '../../types/MessageRequestResponseE
|
|||
import { DurationInSeconds } from '../../util/durations';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||
import {
|
||||
setupBasics,
|
||||
asymmetricRoundtripHarness,
|
||||
symmetricRoundtripHarness,
|
||||
OUR_ACI,
|
||||
} from './helpers';
|
||||
import { loadAll } from '../../services/allLoaders';
|
||||
|
||||
const CONTACT_A = generateAci();
|
||||
const GROUP_ID = Bytes.toBase64(getRandomBytes(32));
|
||||
|
@ -56,7 +56,7 @@ describe('backup/non-bubble messages', () => {
|
|||
}
|
||||
);
|
||||
|
||||
await loadCallsHistory();
|
||||
await loadAll();
|
||||
});
|
||||
|
||||
it('roundtrips END_SESSION simple update', async () => {
|
||||
|
|
|
@ -344,6 +344,11 @@ export class Bootstrap {
|
|||
}
|
||||
}
|
||||
|
||||
if (extraConfig?.ciBackupPath) {
|
||||
debug('waiting for backup import to complete');
|
||||
await app.waitForBackupImportComplete();
|
||||
}
|
||||
|
||||
await this.phone.waitForSync(this.desktop);
|
||||
this.phone.resetSyncState(this.desktop);
|
||||
|
||||
|
@ -512,7 +517,9 @@ export class Bootstrap {
|
|||
return;
|
||||
}
|
||||
|
||||
debug('screenshot difference', numPixels);
|
||||
debug(
|
||||
`screenshot difference for ${name}: ${numPixels}/${width * height}`
|
||||
);
|
||||
|
||||
const outDir = await this.getArtifactsDir(test?.fullTitle());
|
||||
if (outDir != null) {
|
||||
|
|
|
@ -114,6 +114,10 @@ export class App extends EventEmitter {
|
|||
return this.waitForEvent('app-loaded');
|
||||
}
|
||||
|
||||
public async waitForBackupImportComplete(): Promise<void> {
|
||||
return this.waitForEvent('backupImportComplete');
|
||||
}
|
||||
|
||||
public async waitForMessageSend(): Promise<MessageSendInfoType> {
|
||||
return this.waitForEvent('message:send-complete');
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import { take } from 'lodash';
|
||||
import { DataReader } from '../sql/Client';
|
||||
|
||||
type RecentEmojiObjectType = {
|
||||
export type RecentEmojiObjectType = {
|
||||
recents: Array<string>;
|
||||
};
|
||||
|
||||
|
|
|
@ -99,10 +99,10 @@ window.testUtilities = {
|
|||
await Stickers.load();
|
||||
|
||||
initializeRedux({
|
||||
badgesState: { byId: {} },
|
||||
callLinks: [],
|
||||
callsHistory: [],
|
||||
callsHistoryUnreadCount: 0,
|
||||
initialBadgesState: { byId: {} },
|
||||
callHistory: [],
|
||||
callHistoryUnreadCount: 0,
|
||||
mainWindowStats: {
|
||||
isFullScreen: false,
|
||||
isMaximized: false,
|
||||
|
@ -114,8 +114,17 @@ window.testUtilities = {
|
|||
isProduction: false,
|
||||
platform: 'test',
|
||||
},
|
||||
recentEmoji: {
|
||||
recents: [],
|
||||
},
|
||||
stories: [],
|
||||
storyDistributionLists: [],
|
||||
stickers: {
|
||||
installedPack: null,
|
||||
packs: {},
|
||||
recentStickers: [],
|
||||
blessedPacks: {},
|
||||
},
|
||||
theme: ThemeType.dark,
|
||||
});
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue