Files
lnreader/src/services/backup/utils.ts
T
nyagami ad2412eb62 Zip backup (#933)
* add remote zip/unzip

* reimplement: remote backup

* fix: close backup request

* get response for remote zip

* add zip drive backup

* add zip drive restore

* fix: categories are not restored

* change scope to drive.file

* add description for backup action

* refactor: Backup types
2024-01-31 19:19:30 +07:00

141 lines
3.7 KiB
TypeScript

import RNFS from 'react-native-fs';
import { SELF_HOST_BACKUP } from '@hooks/persisted/useSelfHost';
import { TRACKER } from '@hooks/persisted/useTracker';
import { LAST_UPDATE_TIME } from '@hooks/persisted/useUpdates';
import { BACKGROUND_ACTION } from '@services/constants';
import { MMKVStorage } from '@utils/mmkv/mmkv';
import { appVersion } from '@utils/versionUtils';
import {
_restoreNovelAndChapters,
getAllNovels,
} from '@database/queries/NovelQueries';
import { getChapters } from '@database/queries/ChapterQueries';
import {
_restoreCategory,
getAllNovelCategories,
getCategoriesFromDb,
} from '@database/queries/CategoryQueries';
import { BackupCategory } from '@database/types';
import { BackupEntryName } from './types';
export const CACHE_DIR_PATH = RNFS.ExternalCachesDirectoryPath + '/BackupData';
const backupMMKVData = () => {
const excludeKeys = [
BACKGROUND_ACTION,
TRACKER,
SELF_HOST_BACKUP,
LAST_UPDATE_TIME,
];
const keys = MMKVStorage.getAllKeys().filter(
key => !excludeKeys.includes(key),
);
const data = {} as any;
for (let key of keys) {
let value: number | string | boolean | undefined =
MMKVStorage.getString(key);
if (!value) {
value = MMKVStorage.getBoolean(key);
}
if (key && value) {
data[key] = value;
}
}
return data;
};
const restoreMMKVData = (data: any) => {
for (let key in data) {
MMKVStorage.set(key, data[key]);
}
};
export const prepareBackupData = async (cacheDirPath: string) => {
const novelDirPath = cacheDirPath + '/' + BackupEntryName.NOVEL_AND_CHAPTERS;
if (await RNFS.exists(novelDirPath)) {
await RNFS.unlink(novelDirPath);
}
await RNFS.mkdir(novelDirPath); // this also creates cacheDirPath
// version
await RNFS.writeFile(
cacheDirPath + '/' + BackupEntryName.VERSION,
JSON.stringify({ version: appVersion }),
);
// novels
await getAllNovels().then(async novels => {
for (const novel of novels) {
const chapters = await getChapters(novel.id);
await RNFS.writeFile(
novelDirPath + '/' + novel.id + '.json',
JSON.stringify({
chapters: chapters,
...novel,
}),
);
}
});
// categories
await getCategoriesFromDb().then(categories => {
return getAllNovelCategories().then(async novelCategories => {
await RNFS.writeFile(
cacheDirPath + '/' + BackupEntryName.CATEGORY,
JSON.stringify(
categories.map(category => {
return {
...category,
novelIds: novelCategories
.filter(nc => nc.categoryId === category.id)
.map(nc => nc.novelId),
};
}),
),
);
});
});
// settings
await RNFS.writeFile(
cacheDirPath + '/' + BackupEntryName.SETTING,
JSON.stringify(backupMMKVData()),
);
};
export const restoreData = async (cacheDirPath: string) => {
const novelDirPath = cacheDirPath + '/' + BackupEntryName.NOVEL_AND_CHAPTERS;
// version
// nothing to do
// novels
await RNFS.readDir(novelDirPath).then(async items => {
for (const item of items) {
if (item.isFile()) {
await RNFS.readFile(item.path).then(content =>
_restoreNovelAndChapters(JSON.parse(content)),
);
}
}
});
// categories
await RNFS.readFile(cacheDirPath + '/' + BackupEntryName.CATEGORY).then(
async content => {
const categories: BackupCategory[] = JSON.parse(content);
for (const category of categories) {
await _restoreCategory(category);
}
},
);
// settings
await RNFS.readFile(cacheDirPath + '/' + BackupEntryName.SETTING).then(
content => {
restoreMMKVData(JSON.parse(content));
},
);
};