[Lib > Storage] Move from MMKVManager to FS (#206)
* init migration * fixes
This commit is contained in:
parent
c58530080e
commit
80efe7026c
4 changed files with 68 additions and 14 deletions
2
src/def.d.ts
vendored
2
src/def.d.ts
vendored
|
@ -292,11 +292,13 @@ interface FileManager {
|
||||||
* @returns Promise that resolves to path of the file once it got written
|
* @returns Promise that resolves to path of the file once it got written
|
||||||
*/
|
*/
|
||||||
writeFile(storageDir: "cache" | "documents", path: string, data: string, encoding: "base64" | "utf8"): Promise<string>;
|
writeFile(storageDir: "cache" | "documents", path: string, data: string, encoding: "base64" | "utf8"): Promise<string>;
|
||||||
|
removeFile(storageDir: "cache" | "documents", path: string): Promise<unknown>;
|
||||||
getConstants: () => {
|
getConstants: () => {
|
||||||
/**
|
/**
|
||||||
* The path the `documents` storage dir (see {@link writeFile}) represents.
|
* The path the `documents` storage dir (see {@link writeFile}) represents.
|
||||||
*/
|
*/
|
||||||
DocumentsDirPath: string;
|
DocumentsDirPath: string;
|
||||||
|
CacheDirPath: string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Will apparently cease to exist some time in the future so please use {@link getConstants} instead.
|
* Will apparently cease to exist some time in the future so please use {@link getConstants} instead.
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const constants = findByProps("Fonts", "Permissions");
|
||||||
export const channels = findByProps("getVoiceChannelId");
|
export const channels = findByProps("getVoiceChannelId");
|
||||||
export const i18n = findByProps("Messages");
|
export const i18n = findByProps("Messages");
|
||||||
export const url = findByProps("openURL", "openDeeplink");
|
export const url = findByProps("openURL", "openDeeplink");
|
||||||
export const toasts = find(m => m.open && m.close && !m.startDrag && !m.init && !m.openReplay && !m.setAlwaysOnTop);
|
export const toasts = find(m => m.open && m.close && !m.startDrag && !m.init && !m.openReplay && !m.setAlwaysOnTop && !m.setAccountFlag);
|
||||||
|
|
||||||
// Compatible with pre-204201 versions since createThemedStyleSheet is undefined.
|
// Compatible with pre-204201 versions since createThemedStyleSheet is undefined.
|
||||||
export const stylesheet = {
|
export const stylesheet = {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PluginManifest, Plugin } from "@types";
|
import { PluginManifest, Plugin } from "@types";
|
||||||
import { safeFetch } from "@lib/utils";
|
import { safeFetch } from "@lib/utils";
|
||||||
import { awaitSyncWrapper, createMMKVBackend, createStorage, wrapSync } from "@lib/storage";
|
import { awaitSyncWrapper, createMMKVBackend, createStorage, purgeStorage, wrapSync } from "@lib/storage";
|
||||||
import { MMKVManager } from "@lib/native";
|
import { MMKVManager } from "@lib/native";
|
||||||
import { allSettled } from "@lib/polyfills";
|
import { allSettled } from "@lib/polyfills";
|
||||||
import logger, { logModule } from "@lib/logger";
|
import logger, { logModule } from "@lib/logger";
|
||||||
|
@ -117,12 +117,12 @@ export function stopPlugin(id: string, disable = true) {
|
||||||
disable && (plugin.enabled = false);
|
disable && (plugin.enabled = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removePlugin(id: string) {
|
export async function removePlugin(id: string) {
|
||||||
if (!id.endsWith("/")) id += "/";
|
if (!id.endsWith("/")) id += "/";
|
||||||
const plugin = plugins[id];
|
const plugin = plugins[id];
|
||||||
if (plugin.enabled) stopPlugin(id);
|
if (plugin.enabled) stopPlugin(id);
|
||||||
MMKVManager.removeItem(id);
|
|
||||||
delete plugins[id];
|
delete plugins[id];
|
||||||
|
await purgeStorage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initPlugins() {
|
export async function initPlugins() {
|
||||||
|
|
|
@ -1,25 +1,77 @@
|
||||||
import { StorageBackend } from "@types";
|
import { StorageBackend } from "@types";
|
||||||
import { ReactNative as RN } from "@metro/common";
|
|
||||||
import { MMKVManager, FileManager } from "@lib/native";
|
import { MMKVManager, FileManager } from "@lib/native";
|
||||||
|
import { ReactNative as RN } from "@metro/common";
|
||||||
|
|
||||||
export const createMMKVBackend = (store: string): StorageBackend => ({
|
const ILLEGAL_CHARS_REGEX = /[<>:"\/\\|?*]/g;
|
||||||
get: async () => JSON.parse((await MMKVManager.getItem(store)) ?? "{}"),
|
|
||||||
set: (data) => MMKVManager.setItem(store, JSON.stringify(data)),
|
const filePathFixer = (file: string): string => RN.Platform.select({
|
||||||
|
default: file,
|
||||||
|
ios: FileManager.saveFileToGallery ? file : `Documents/${file}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const createFileBackend = (file: string): StorageBackend => {
|
const getMMKVPath = (name: string): string => {
|
||||||
const filePathFixer: (file: string) => string = RN.Platform.select({
|
if (ILLEGAL_CHARS_REGEX.test(name)) {
|
||||||
default: (f) => f,
|
// Replace forbidden characters with hyphens
|
||||||
ios: (f) => FileManager.saveFileToGallery ? f : `Documents/${f}`,
|
name = name.replace(ILLEGAL_CHARS_REGEX, '-').replace(/-+/g, '-');
|
||||||
});
|
}
|
||||||
|
|
||||||
|
return `vd_mmkv/${name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const purgeStorage = async (store: string) => {
|
||||||
|
if (await MMKVManager.getItem(store)) {
|
||||||
|
MMKVManager.removeItem(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mmkvPath = getMMKVPath(store);
|
||||||
|
if (await FileManager.fileExists(`${FileManager.getConstants().DocumentsDirPath}/${mmkvPath}`)) {
|
||||||
|
await FileManager.removeFile?.("documents", mmkvPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createMMKVBackend = (store: string) => {
|
||||||
|
const mmkvPath = getMMKVPath(store);
|
||||||
|
return createFileBackend(mmkvPath, (async () => {
|
||||||
|
try {
|
||||||
|
const path = `${FileManager.getConstants().DocumentsDirPath}/${mmkvPath}`;
|
||||||
|
if (await FileManager.fileExists(path)) return;
|
||||||
|
|
||||||
|
let oldData = await MMKVManager.getItem(store) ?? "{}";
|
||||||
|
|
||||||
|
// From the testing on Android, it seems to return this if the data is too large
|
||||||
|
if (oldData === "!!LARGE_VALUE!!") {
|
||||||
|
const cachePath = `${FileManager.getConstants().CacheDirPath}/mmkv/${store}`;
|
||||||
|
if (await FileManager.fileExists(cachePath)) {
|
||||||
|
oldData = await FileManager.readFile(cachePath, "utf8")
|
||||||
|
} else {
|
||||||
|
console.log(`${store}: Experienced data loss :(`);
|
||||||
|
oldData = "{}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await FileManager.writeFile("documents", filePathFixer(mmkvPath), oldData, "utf8");
|
||||||
|
if (await MMKVManager.getItem(store) !== null) {
|
||||||
|
MMKVManager.removeItem(store);
|
||||||
|
console.log(`Successfully migrated ${store} store from MMKV storage to fs`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to migrate to fs from MMKVManager ", err)
|
||||||
|
}
|
||||||
|
})());
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createFileBackend = (file: string, migratePromise?: Promise<void>): StorageBackend => {
|
||||||
let created: boolean;
|
let created: boolean;
|
||||||
return {
|
return {
|
||||||
get: async () => {
|
get: async () => {
|
||||||
|
await migratePromise;
|
||||||
const path = `${FileManager.getConstants().DocumentsDirPath}/${file}`;
|
const path = `${FileManager.getConstants().DocumentsDirPath}/${file}`;
|
||||||
if (!created && !(await FileManager.fileExists(path))) return (created = true), FileManager.writeFile("documents", filePathFixer(file), "{}", "utf8");
|
if (!created && !(await FileManager.fileExists(path))) return (created = true), FileManager.writeFile("documents", filePathFixer(file), "{}", "utf8");
|
||||||
return JSON.parse(await FileManager.readFile(path, "utf8"));
|
return JSON.parse(await FileManager.readFile(path, "utf8"));
|
||||||
},
|
},
|
||||||
set: async (data) => void await FileManager.writeFile("documents", filePathFixer(file), JSON.stringify(data), "utf8"),
|
set: async (data) => {
|
||||||
|
await migratePromise;
|
||||||
|
await FileManager.writeFile("documents", filePathFixer(file), JSON.stringify(data), "utf8");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue