[Storage] Proper persist implementation

This commit is contained in:
Beef 2023-01-10 08:05:03 +00:00
parent 564a427971
commit a46c9c8828
3 changed files with 55 additions and 40 deletions

View file

@ -12,7 +12,7 @@ import { patchAssets, all, find, getAssetByID, getAssetByName, getAssetIDByName
import initSettings from "@ui/settings"; import initSettings from "@ui/settings";
import { fixTheme } from "@ui/fixTheme"; import { fixTheme } from "@ui/fixTheme";
import { connectToDebugger, patchLogHook } from "@lib/debug"; import { connectToDebugger, patchLogHook } from "@lib/debug";
import { initPlugins, plugins, fetchPlugin, evalPlugin, stopPlugin, removePlugin, getSettings } from "@lib/plugins"; import { plugins, fetchPlugin, evalPlugin, stopPlugin, removePlugin, getSettings } from "@lib/plugins";
console.log("Hello from Vendetta!"); console.log("Hello from Vendetta!");
@ -58,7 +58,6 @@ async function init() {
patchAssets(); patchAssets();
patchLogHook(); patchLogHook();
fixTheme(); fixTheme();
initPlugins();
} catch (e: Error | any) { } catch (e: Error | any) {
erroredOnLoad = true; erroredOnLoad = true;
alert(`Vendetta failed to initialize... ${e.stack || e.toString()}`); alert(`Vendetta failed to initialize... ${e.stack || e.toString()}`);

View file

@ -1,6 +1,6 @@
import { Indexable, PluginManifest, Plugin } from "@types"; import { Indexable, PluginManifest, Plugin } from "@types";
import { AsyncStorage } from "@metro/common";
import logger from "@lib/logger"; import logger from "@lib/logger";
import createStorage from "./storage";
type EvaledPlugin = { type EvaledPlugin = {
onLoad?(): void; onLoad?(): void;
@ -8,31 +8,19 @@ type EvaledPlugin = {
settings: JSX.Element; settings: JSX.Element;
}; };
const proxyValidator = { export const plugins = createStorage<Indexable<Plugin>>("VENDETTA_PLUGINS", async function(parsed) {
get(target: object, key: string | symbol): any { for (let p of Object.keys(parsed)) {
const orig = Reflect.get(target, key); const plugin: Plugin = parsed[p];
if (typeof orig === "object" && orig !== null) { if (parsed[p].update) {
return new Proxy(orig, proxyValidator); await fetchPlugin(plugin.id);
} else { } else {
return orig; plugins[p] = parsed[p];
} }
},
set(target: object, key: string | symbol, value: any) { if (parsed[p].enabled && plugins[p]) startPlugin(p);
Reflect.set(target, key, value);
AsyncStorage.setItem("VENDETTA_PLUGINS", JSON.stringify(plugins));
return true;
},
deleteProperty(target: object, key: string | symbol) {
Reflect.deleteProperty(target, key);
AsyncStorage.setItem("VENDETTA_PLUGINS", JSON.stringify(plugins));
return true;
} }
} });
export const plugins: Indexable<Plugin> = new Proxy({}, proxyValidator);
const loadedPlugins: Indexable<EvaledPlugin> = {}; const loadedPlugins: Indexable<EvaledPlugin> = {};
export async function fetchPlugin(id: string) { export async function fetchPlugin(id: string) {
@ -124,20 +112,3 @@ export function removePlugin(id: string) {
} }
export const getSettings = (id: string) => loadedPlugins[id]?.settings; export const getSettings = (id: string) => loadedPlugins[id]?.settings;
export const initPlugins = () => AsyncStorage.getItem("VENDETTA_PLUGINS").then(async function (v) {
if (!v) return;
const parsedPlugins: Indexable<Plugin> = JSON.parse(v);
for (let p of Object.keys(parsedPlugins)) {
const plugin = parsedPlugins[p]
if (parsedPlugins[p].update) {
await fetchPlugin(plugin.id);
} else {
plugins[p] = parsedPlugins[p];
}
if (parsedPlugins[p].enabled && plugins[p]) startPlugin(p);
}
})

45
src/lib/storage.ts Normal file
View file

@ -0,0 +1,45 @@
import { Indexable } from "@types";
import { AsyncStorage } from "@metro/common";
// TODO: React hook?
// TODO: Clean up types, if necessary
export default function createStorage<T>(storeName: string, onRestore?: (parsed: T) => void): T {
const internalStore: Indexable<any> = {};
const proxyValidator = {
get(target: object, key: string | symbol): any {
const orig = Reflect.get(target, key);
if (typeof orig === "object" && orig !== null) {
return new Proxy(orig, proxyValidator);
} else {
return orig;
}
},
set(target: object, key: string | symbol, value: any) {
Reflect.set(target, key, value);
AsyncStorage.setItem(storeName, JSON.stringify(internalStore));
return true;
},
deleteProperty(target: object, key: string | symbol) {
Reflect.deleteProperty(target, key);
AsyncStorage.setItem(storeName, JSON.stringify(internalStore));
return true;
}
}
AsyncStorage.getItem(storeName).then(async function (v) {
if (!v) return;
const parsed: T & Indexable<any> = JSON.parse(v);
if (onRestore && typeof onRestore === "function") {
onRestore(parsed);
} else {
for (let p of Object.keys(parsed)) internalStore[p] = parsed[p];
}
})
return new Proxy(internalStore, proxyValidator) as T;
}