Page MenuHomePhabricator

D11043.id37440.diff
No OneTemporary

D11043.id37440.diff

diff --git a/lib/facts/backup-service.js b/lib/facts/backup-service.js
new file mode 100644
--- /dev/null
+++ b/lib/facts/backup-service.js
@@ -0,0 +1,15 @@
+// @flow
+
+import { isDev } from '../utils/dev-utils.js';
+
+type BackupServiceConfig = {
+ +url: string,
+};
+
+const config: BackupServiceConfig = {
+ url: isDev
+ ? 'https://backup.staging.commtechnologies.org'
+ : 'https://backup.commtechnologies.org',
+};
+
+export default config;
diff --git a/web/database/utils/constants.js b/web/database/utils/constants.js
--- a/web/database/utils/constants.js
+++ b/web/database/utils/constants.js
@@ -16,6 +16,8 @@
export const DEFAULT_OLM_FILENAME = 'olm.wasm';
export const COMM_SQLITE_DATABASE_PATH = 'comm.sqlite';
+export const COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH =
+ 'comm_backup_restore.sqlite';
export const NOTIFICATIONS_OLM_DATA_CONTENT = 'notificationsOlmDataContent';
diff --git a/web/database/worker/backup.js b/web/database/worker/backup.js
new file mode 100644
--- /dev/null
+++ b/web/database/worker/backup.js
@@ -0,0 +1,64 @@
+// @flow
+
+import backupService from 'lib/facts/backup-service.js';
+import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
+
+import { getProcessingStoreOpsExceptionMessage } from './process-operations.js';
+import {
+ BackupClient,
+ RequestedData,
+} from '../../backup-client-wasm/wasm/backup-client-wasm.js';
+import { completeRootKey } from '../../redux/persist-constants.js';
+import type { EmscriptenModule } from '../types/module.js';
+import type { SQLiteQueryExecutor } from '../types/sqlite-query-executor.js';
+import { COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH } from '../utils/constants.js';
+import { importDatabaseContent } from '../utils/db-utils.js';
+
+async function restoreBackup(
+ sqliteQueryExecutor: SQLiteQueryExecutor,
+ dbModule: EmscriptenModule,
+ authMetadata: AuthMetadata,
+ backupID: string,
+ backupDataKey: string,
+) {
+ const { userID, deviceID, accessToken } = authMetadata;
+ if (!userID || !deviceID || !accessToken) {
+ throw new Error('Backup restore requires full authMetadata');
+ }
+ const userIdentity = { userID, deviceID, accessToken };
+
+ const client = new BackupClient(backupService.url);
+ const result = await client.downloadBackupData(
+ {
+ type: 'BackupID',
+ backupID,
+ userIdentity,
+ },
+ RequestedData.UserData,
+ );
+
+ importDatabaseContent(
+ result,
+ dbModule,
+ COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH,
+ );
+
+ try {
+ const reduxPersistData =
+ sqliteQueryExecutor.getPersistStorageItem(completeRootKey);
+
+ sqliteQueryExecutor.restoreFromMainCompaction(
+ COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH,
+ backupDataKey,
+ );
+
+ sqliteQueryExecutor.setPersistStorageItem(
+ completeRootKey,
+ reduxPersistData,
+ );
+ } catch (err) {
+ throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule));
+ }
+}
+
+export { restoreBackup };
diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js
--- a/web/database/worker/db-worker.js
+++ b/web/database/worker/db-worker.js
@@ -2,6 +2,7 @@
import localforage from 'localforage';
+import { restoreBackup } from './backup.js';
import {
getClientStoreFromQueryExecutor,
processDBStoreOperations,
@@ -246,6 +247,14 @@
message.type === workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM
) {
sqliteQueryExecutor.removePersistStorageItem(message.key);
+ } else if (message.type === workerRequestMessageTypes.BACKUP_RESTORE) {
+ await restoreBackup(
+ sqliteQueryExecutor,
+ dbModule,
+ message.authMetadata,
+ message.backupID,
+ message.backupDataKey,
+ );
}
persistNeeded = true;
diff --git a/web/database/worker/process-operations.js b/web/database/worker/process-operations.js
--- a/web/database/worker/process-operations.js
+++ b/web/database/worker/process-operations.js
@@ -220,4 +220,8 @@
};
}
-export { processDBStoreOperations, getClientStoreFromQueryExecutor };
+export {
+ processDBStoreOperations,
+ getProcessingStoreOpsExceptionMessage,
+ getClientStoreFromQueryExecutor,
+};
diff --git a/web/redux/persist-constants.js b/web/redux/persist-constants.js
new file mode 100644
--- /dev/null
+++ b/web/redux/persist-constants.js
@@ -0,0 +1,7 @@
+// @flow
+
+const rootKey = 'root';
+const rootKeyPrefix = 'persist:';
+const completeRootKey = `${rootKeyPrefix}${rootKey}`;
+
+export { rootKey, rootKeyPrefix, completeRootKey };
diff --git a/web/redux/persist.js b/web/redux/persist.js
--- a/web/redux/persist.js
+++ b/web/redux/persist.js
@@ -32,6 +32,7 @@
import commReduxStorageEngine from './comm-redux-storage-engine.js';
import { defaultWebState } from './default-state.js';
+import { rootKey, rootKeyPrefix } from './persist-constants.js';
import type { AppState } from './redux-setup.js';
import { nonUserSpecificFieldsWeb } from './redux-setup.js';
import { getDatabaseModule } from '../database/database-module-provider.js';
@@ -263,8 +264,6 @@
},
};
-const rootKey = 'root';
-
const migrateStorageToSQLite: StorageMigrationFunction = async debug => {
const databaseModule = await getDatabaseModule();
const isSupported = await databaseModule.isDatabaseSupported();
@@ -297,6 +296,7 @@
};
const persistConfig: PersistConfig = {
+ keyPrefix: rootKeyPrefix,
key: rootKey,
storage: commReduxStorageEngine,
whitelist: isSQLiteSupported()
diff --git a/web/types/worker-types.js b/web/types/worker-types.js
--- a/web/types/worker-types.js
+++ b/web/types/worker-types.js
@@ -1,5 +1,6 @@
// @flow
+import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
import type {
ClientDBStore,
ClientDBStoreOperations,
@@ -18,6 +19,7 @@
SET_PERSIST_STORAGE_ITEM: 8,
REMOVE_PERSIST_STORAGE_ITEM: 9,
CLEAR_SENSITIVE_DATA: 10,
+ BACKUP_RESTORE: 11,
});
export const workerWriteRequests: $ReadOnlyArray<number> = [
@@ -25,6 +27,7 @@
workerRequestMessageTypes.SET_CURRENT_USER_ID,
workerRequestMessageTypes.SET_PERSIST_STORAGE_ITEM,
workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM,
+ workerRequestMessageTypes.BACKUP_RESTORE,
];
export type PingWorkerRequestMessage = {
@@ -82,6 +85,13 @@
+type: 10,
};
+export type BackupRestoreRequestMessage = {
+ +type: 11,
+ +authMetadata: AuthMetadata,
+ +backupID: string,
+ +backupDataKey: string,
+};
+
export type WorkerRequestMessage =
| PingWorkerRequestMessage
| InitWorkerRequestMessage
@@ -93,7 +103,8 @@
| GetPersistStorageItemRequestMessage
| SetPersistStorageItemRequestMessage
| RemovePersistStorageItemRequestMessage
- | ClearSensitiveDataRequestMessage;
+ | ClearSensitiveDataRequestMessage
+ | BackupRestoreRequestMessage;
export type WorkerRequestProxyMessage = {
+id: number,

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 28, 12:55 PM (21 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2594043
Default Alt Text
D11043.id37440.diff (6 KB)

Event Timeline