Page MenuHomePhabricator

No OneTemporary

diff --git a/native/data/sqlite-context-provider.js b/native/data/sqlite-context-provider.js
index d5056471b..997ef7c24 100644
--- a/native/data/sqlite-context-provider.js
+++ b/native/data/sqlite-context-provider.js
@@ -1,86 +1,89 @@
// @flow
import * as React from 'react';
import { useDispatch } from 'react-redux';
+import { setMessageStoreMessages } from 'lib/actions/message-actions.js';
import { setThreadStoreActionType } from 'lib/actions/thread-actions';
import { sqliteLoadFailure } from 'lib/actions/user-actions';
import { fetchNewCookieFromNativeCredentials } from 'lib/utils/action-utils';
import { convertClientDBThreadInfosToRawThreadInfos } from 'lib/utils/thread-ops-utils';
-import { persistConfig } from '../redux/persist';
import { useSelector } from '../redux/redux-utils';
import { SQLiteContext } from './sqlite-context';
type Props = {
+children: React.Node,
};
function SQLiteContextProvider(props: Props): React.Node {
const [threadStoreLoaded, setThreadStoreLoaded] = React.useState<boolean>(
false,
);
const [messageStoreLoaded, setMessageStoreLoaded] = React.useState<boolean>(
false,
);
const dispatch = useDispatch();
const rehydrateConcluded = useSelector(
state => !!(state._persist && state._persist.rehydrated),
);
const cookie = useSelector(state => state.cookie);
const urlPrefix = useSelector(state => state.urlPrefix);
React.useEffect(() => {
if ((threadStoreLoaded && messageStoreLoaded) || !rehydrateConcluded) {
return;
}
- if (persistConfig.version < 31) {
- setMessageStoreLoaded(true);
- }
(async () => {
try {
const threads = await global.CommCoreModule.getAllThreads();
const threadInfosFromDB = convertClientDBThreadInfosToRawThreadInfos(
threads,
);
dispatch({
type: setThreadStoreActionType,
payload: { threadInfos: threadInfosFromDB },
});
+ const messages = await global.CommCoreModule.getAllMessages();
+ dispatch({
+ type: setMessageStoreMessages,
+ payload: messages,
+ });
} catch {
await fetchNewCookieFromNativeCredentials(
dispatch,
cookie,
urlPrefix,
sqliteLoadFailure,
);
} finally {
setThreadStoreLoaded(true);
+ setMessageStoreLoaded(true);
}
})();
}, [
threadStoreLoaded,
urlPrefix,
rehydrateConcluded,
cookie,
dispatch,
messageStoreLoaded,
]);
const contextValue = React.useMemo(
() => ({
threadStoreLoaded,
messageStoreLoaded,
}),
[threadStoreLoaded, messageStoreLoaded],
);
return (
<SQLiteContext.Provider value={contextValue}>
{props.children}
</SQLiteContext.Provider>
);
}
export { SQLiteContextProvider };
diff --git a/native/redux/persist.js b/native/redux/persist.js
index de1dbc746..15ae9feb5 100644
--- a/native/redux/persist.js
+++ b/native/redux/persist.js
@@ -1,420 +1,421 @@
// @flow
import AsyncStorage from '@react-native-community/async-storage';
import invariant from 'invariant';
import { Platform } from 'react-native';
import Orientation from 'react-native-orientation-locker';
import { createMigrate, createTransform } from 'redux-persist';
import type { Transform } from 'redux-persist/es/types';
import { highestLocalIDSelector } from 'lib/selectors/local-id-selectors';
import { inconsistencyResponsesToReports } from 'lib/shared/report-utils';
import { getContainingThreadID, getCommunity } from 'lib/shared/thread-utils';
import { unshimMessageStore } from 'lib/shared/unshim-utils';
import { defaultEnabledApps } from 'lib/types/enabled-apps';
import { defaultCalendarFilters } from 'lib/types/filter-types';
import { messageTypes } from 'lib/types/message-types';
import type { ClientDBMessageStoreOperation } from 'lib/types/message-types';
import { defaultConnectionInfo } from 'lib/types/socket-types';
import { translateRawMessageInfoToClientDBMessageInfo } from 'lib/utils/message-ops-utils';
import { convertThreadStoreOperationsToClientDBOperations } from 'lib/utils/thread-ops-utils';
import { defaultNotifPermissionAlertInfo } from '../push/alerts';
import { defaultDeviceCameraInfo } from '../types/camera';
import { defaultGlobalThemeInfo } from '../types/themes';
import { migrateThreadStoreForEditThreadPermissions } from './edit-thread-permission-migration';
import type { AppState } from './state-types';
const migrations = {
[1]: (state: AppState) => ({
...state,
notifPermissionAlertInfo: defaultNotifPermissionAlertInfo,
}),
[2]: (state: AppState) => ({
...state,
messageSentFromRoute: [],
}),
[3]: state => ({
currentUserInfo: state.currentUserInfo,
entryStore: state.entryStore,
threadInfos: state.threadInfos,
userInfos: state.userInfos,
messageStore: {
...state.messageStore,
currentAsOf: state.currentAsOf,
},
updatesCurrentAsOf: state.currentAsOf,
cookie: state.cookie,
deviceToken: state.deviceToken,
urlPrefix: state.urlPrefix,
customServer: state.customServer,
threadIDsToNotifIDs: state.threadIDsToNotifIDs,
notifPermissionAlertInfo: state.notifPermissionAlertInfo,
messageSentFromRoute: state.messageSentFromRoute,
_persist: state._persist,
}),
[4]: (state: AppState) => ({
...state,
pingTimestamps: undefined,
activeServerRequests: undefined,
}),
[5]: (state: AppState) => ({
...state,
calendarFilters: defaultCalendarFilters,
}),
[6]: state => ({
...state,
threadInfos: undefined,
threadStore: {
threadInfos: state.threadInfos,
inconsistencyResponses: [],
},
}),
[7]: state => ({
...state,
lastUserInteraction: undefined,
sessionID: undefined,
entryStore: {
...state.entryStore,
inconsistencyResponses: [],
},
}),
[8]: (state: AppState) => ({
...state,
pingTimestamps: undefined,
activeServerRequests: undefined,
connection: defaultConnectionInfo(Platform.OS),
watchedThreadIDs: [],
entryStore: {
...state.entryStore,
actualizedCalendarQuery: undefined,
},
}),
[9]: (state: AppState) => ({
...state,
connection: {
...state.connection,
lateResponses: [],
},
}),
[10]: (state: AppState) => ({
...state,
nextLocalID: highestLocalIDSelector(state) + 1,
connection: {
...state.connection,
showDisconnectedBar: false,
},
messageStore: {
...state.messageStore,
local: {},
},
}),
[11]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [messageTypes.IMAGES]),
}),
[12]: (state: AppState) => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
[13]: (state: AppState) => ({
...state,
deviceCameraInfo: defaultDeviceCameraInfo,
deviceOrientation: Orientation.getInitialOrientation(),
}),
[14]: (state: AppState) => state,
[15]: state => ({
...state,
threadStore: {
...state.threadStore,
inconsistencyReports: inconsistencyResponsesToReports(
state.threadStore.inconsistencyResponses,
),
inconsistencyResponses: undefined,
},
entryStore: {
...state.entryStore,
inconsistencyReports: inconsistencyResponsesToReports(
state.entryStore.inconsistencyResponses,
),
inconsistencyResponses: undefined,
},
queuedReports: [],
}),
[16]: state => {
const result = {
...state,
messageSentFromRoute: undefined,
dataLoaded: !!state.currentUserInfo && !state.currentUserInfo.anonymous,
};
if (state.navInfo) {
result.navInfo = {
...state.navInfo,
navigationState: undefined,
};
}
return result;
},
[17]: state => ({
...state,
userInfos: undefined,
userStore: {
userInfos: state.userInfos,
inconsistencyResponses: [],
},
}),
[18]: state => ({
...state,
userStore: {
userInfos: state.userStore.userInfos,
inconsistencyReports: [],
},
}),
[19]: state => {
const threadInfos = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
const { visibilityRules, ...rest } = threadInfo;
threadInfos[threadID] = rest;
}
return {
...state,
threadStore: {
...state.threadStore,
threadInfos,
},
};
},
[20]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [
messageTypes.UPDATE_RELATIONSHIP,
]),
}),
[21]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [
messageTypes.CREATE_SIDEBAR,
messageTypes.SIDEBAR_SOURCE,
]),
}),
[22]: state => {
for (const key in state.drafts) {
const value = state.drafts[key];
global.CommCoreModule.updateDraft({
key,
text: value,
});
}
return {
...state,
drafts: undefined,
};
},
[23]: state => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
[24]: state => ({
...state,
enabledApps: defaultEnabledApps,
}),
[25]: state => ({
...state,
crashReportsEnabled: __DEV__,
}),
[26]: state => {
const { currentUserInfo } = state;
if (currentUserInfo.anonymous) {
return state;
}
return {
...state,
crashReportsEnabled: undefined,
currentUserInfo: {
id: currentUserInfo.id,
username: currentUserInfo.username,
},
enabledReports: {
crashReports: __DEV__,
inconsistencyReports: __DEV__,
mediaReports: __DEV__,
},
};
},
[27]: state => ({
...state,
queuedReports: undefined,
enabledReports: undefined,
threadStore: {
...state.threadStore,
inconsistencyReports: undefined,
},
entryStore: {
...state.entryStore,
inconsistencyReports: undefined,
},
reportStore: {
enabledReports: {
crashReports: __DEV__,
inconsistencyReports: __DEV__,
mediaReports: __DEV__,
},
queuedReports: [
...state.entryStore.inconsistencyReports,
...state.threadStore.inconsistencyReports,
...state.queuedReports,
],
},
}),
[28]: state => {
const threadParentToChildren = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
const parentThreadInfo = threadInfo.parentThreadID
? state.threadStore.threadInfos[threadInfo.parentThreadID]
: null;
const parentIndex = parentThreadInfo ? parentThreadInfo.id : '-1';
if (!threadParentToChildren[parentIndex]) {
threadParentToChildren[parentIndex] = [];
}
threadParentToChildren[parentIndex].push(threadID);
}
const rootIDs = threadParentToChildren['-1'];
if (!rootIDs) {
// This should never happen, but if it somehow does we'll let the state
// check mechanism resolve it...
return state;
}
const threadInfos = {};
const stack = [...rootIDs];
while (stack.length > 0) {
const threadID = stack.shift();
const threadInfo = state.threadStore.threadInfos[threadID];
const parentThreadInfo = threadInfo.parentThreadID
? threadInfos[threadInfo.parentThreadID]
: null;
threadInfos[threadID] = {
...threadInfo,
containingThreadID: getContainingThreadID(
parentThreadInfo,
threadInfo.type,
),
community: getCommunity(parentThreadInfo),
};
const children = threadParentToChildren[threadID];
if (children) {
stack.push(...children);
}
}
return { ...state, threadStore: { ...state.threadStore, threadInfos } };
},
[29]: (state: AppState) => {
const updatedThreadInfos = migrateThreadStoreForEditThreadPermissions(
state.threadStore.threadInfos,
);
return {
...state,
threadStore: {
...state.threadStore,
threadInfos: updatedThreadInfos,
},
};
},
[30]: (state: AppState) => {
const threadInfos = state.threadStore.threadInfos;
const operations = [
{
type: 'remove_all',
},
...Object.keys(threadInfos).map((id: string) => ({
type: 'replace',
payload: { id, threadInfo: threadInfos[id] },
})),
];
const processingResult: boolean = global.CommCoreModule.processThreadStoreOperationsSync(
convertThreadStoreOperationsToClientDBOperations(operations),
);
if (!processingResult) {
return { ...state, cookie: null };
}
return state;
},
[31]: (state: AppState) => {
const messages = state.messageStore.messages;
const operations: $ReadOnlyArray<ClientDBMessageStoreOperation> = [
{
type: 'remove_all',
},
...Object.keys(messages).map((id: string) => ({
type: 'replace',
payload: translateRawMessageInfoToClientDBMessageInfo(messages[id]),
})),
];
const processingResult: boolean = global.CommCoreModule.processMessageStoreOperationsSync(
operations,
);
if (!processingResult) {
return { ...state, cookie: null };
}
return state;
},
};
// After migration 31, we'll no longer want to persist `messageStore.messages`
// via redux-persist. However, we DO want to continue persisting everything in
// `messageStore` EXCEPT for `messages`. The `blacklist` property in
// `persistConfig` allows us to specify top-level keys that shouldn't be
// persisted. However, we aren't able to specify nested keys in `blacklist`.
// As a result, if we want to prevent nested keys from being persisted we'll
// need to use `createTransform(...)` to specify an `inbound` function that
// allows us to modify the `state` object before it's passed through
// `JSON.stringify(...)` and written to disk. We specify the keys for which
// this transformation should be executed in the `whitelist` property of the
// `config` object that's passed to `createTransform(...)`.
// eslint-disable-next-line no-unused-vars
const messageStoreMessagesBlocklistTransform: Transform = createTransform(
state => {
const { messages, ...messageStoreSansMessages } = state;
return messageStoreSansMessages;
},
null,
{ whitelist: ['messageStore'] },
);
const persistConfig = {
key: 'root',
storage: AsyncStorage,
blacklist: [
'loadingStatuses',
'lifecycleState',
'dimensions',
'connectivity',
'deviceOrientation',
'frozen',
'threadStore',
],
debug: __DEV__,
- version: 30,
+ version: 31,
+ transforms: [messageStoreMessagesBlocklistTransform],
migrate: (createMigrate(migrations, { debug: __DEV__ }): any),
timeout: ((__DEV__ ? 0 : undefined): number | void),
};
const codeVersion: number = global.CommCoreModule.getCodeVersion();
// This local exists to avoid a circular dependency where redux-setup needs to
// import all the navigation and screen stuff, but some of those screens want to
// access the persistor to purge its state.
let storedPersistor = null;
function setPersistor(persistor: *) {
storedPersistor = persistor;
}
function getPersistor(): empty {
invariant(storedPersistor, 'should be set');
return storedPersistor;
}
export { persistConfig, codeVersion, setPersistor, getPersistor };

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 5:40 AM (18 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2690415
Default Alt Text
(15 KB)

Event Timeline