From 29caf1d09bbef23be9cba74f25ef717dc8da277e Mon Sep 17 00:00:00 2001 From: amsyarasyiq <82711525+amsyarasyiq@users.noreply.github.com> Date: Tue, 25 Jun 2024 02:28:04 +0800 Subject: [PATCH] refactor(plugins) --- src/core/commands/plugins.ts | 2 +- src/core/plugins/quickInstall/forumPost.tsx | 6 +- src/core/polyfills/vendettaObject.tsx | 12 ++-- src/core/ui/components/AddonPage.tsx | 5 +- .../ui/settings/pages/Plugins/PluginCard.tsx | 60 ++++++++++--------- src/core/ui/settings/pages/Plugins/index.tsx | 6 +- .../Plugins/sheets/PluginInfoActionSheet.tsx | 6 +- src/index.ts | 4 +- src/lib/managers/plugins.ts | 38 ++++++------ src/lib/utils/constants.ts | 1 - 10 files changed, 73 insertions(+), 67 deletions(-) diff --git a/src/core/commands/plugins.ts b/src/core/commands/plugins.ts index 5b0fce7..e7abe3f 100644 --- a/src/core/commands/plugins.ts +++ b/src/core/commands/plugins.ts @@ -1,6 +1,6 @@ import { Strings } from "@core/i18n"; import { ApplicationCommand, ApplicationCommandOptionType } from "@lib/api/commands/types"; -import { BunnyPlugin, sourceToObject as pluginStorage } from "@lib/managers/plugins"; +import { BunnyPlugin, sourceStore as pluginStorage } from "@lib/managers/plugins"; import { messageUtil } from "@metro/common"; export default () => { diff --git a/src/core/plugins/quickInstall/forumPost.tsx b/src/core/plugins/quickInstall/forumPost.tsx index 6c4e7d3..27789c5 100644 --- a/src/core/plugins/quickInstall/forumPost.tsx +++ b/src/core/plugins/quickInstall/forumPost.tsx @@ -3,7 +3,7 @@ import { requireAssetIndex } from "@lib/api/assets"; import { isThemeSupported } from "@lib/api/native/loader"; import { after } from "@lib/api/patcher"; import { useProxy } from "@lib/api/storage"; -import { installPlugin, sourceToObject, removePlugin } from "@lib/managers/plugins"; +import { installPlugin, removePlugin,sourceStore } from "@lib/managers/plugins"; import { installTheme, removeTheme, themes } from "@lib/managers/themes"; import { DISCORD_SERVER_ID, HTTP_REGEX_MULTI, PLUGINS_CHANNEL_ID, THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants"; import { lazyDestructure } from "@lib/utils/lazy"; @@ -21,7 +21,7 @@ const forumReactions = findByPropsProxy("MostCommonForumPostReaction"); const postMap = { Plugin: { - storage: sourceToObject, + storage: sourceStore, urlsFilter: (url: string) => url.startsWith(VD_PROXY_PREFIX), installOrRemove: (url: string) => { const isInstalled = postMap.Plugin.storage[url]; @@ -63,7 +63,7 @@ function useExtractThreadContent(thread: any, _firstMessage = null, actionSheet function useInstaller(thread: any, firstMessage = null, actionSheet = false): [true] | [false, PostType, boolean, boolean, () => Promise] { const [postType, url] = useExtractThreadContent(thread, firstMessage, actionSheet) ?? []; - useProxy(sourceToObject); + useProxy(sourceStore); useProxy(themes); const [isInstalling, setIsInstalling] = React.useState(false); diff --git a/src/core/polyfills/vendettaObject.tsx b/src/core/polyfills/vendettaObject.tsx index 1e3b13b..1c04509 100644 --- a/src/core/polyfills/vendettaObject.tsx +++ b/src/core/polyfills/vendettaObject.tsx @@ -170,13 +170,13 @@ export const initVendettaObject = (): any => { rawColors: color.rawColors }, plugins: { - plugins: plugins.sourceToObject, - fetchPlugin: (source: string) => plugins.fetchPlugin(source), + plugins: plugins.sourceStore, + fetchPlugin: (source: string) => plugins.fetchAndStorePlugin(source), installPlugin: (source: string, enabled = true) => plugins.installPlugin(source, enabled), - startPlugin: (id: string) => plugins.startPlugin(plugins.sourceToObject[id]!.pluginId), - stopPlugin: (id: string, disable = true) => plugins.stopPlugin(plugins.sourceToObject[id]!.pluginId, disable), - removePlugin: (id: string) => plugins.removePlugin(plugins.sourceToObject[id]!.pluginId), - getSettings: (id: string) => plugins.getSettingsComponent(plugins.sourceToObject[id]!.pluginId) + startPlugin: (id: string) => plugins.startPlugin(plugins.sourceStore[id]!.pluginId), + stopPlugin: (id: string, disable = true) => plugins.stopPlugin(plugins.sourceStore[id]!.pluginId, disable), + removePlugin: (id: string) => plugins.removePlugin(plugins.sourceStore[id]!.pluginId), + getSettings: (id: string) => plugins.getSettingsComponent(plugins.sourceStore[id]!.pluginId) }, themes: { themes: themes.themes, diff --git a/src/core/ui/components/AddonPage.tsx b/src/core/ui/components/AddonPage.tsx index f05d4fe..a132fa0 100644 --- a/src/core/ui/components/AddonPage.tsx +++ b/src/core/ui/components/AddonPage.tsx @@ -15,7 +15,7 @@ import { View } from "react-native"; type SearchKeywords = Array string)>; -interface AddonPageProps { +interface AddonPageProps { title: string; fetchFunction: (url: string) => Promise; items: Record; @@ -30,7 +30,7 @@ interface AddonPageProps { // TODO: Move to somewhere else const { FlashList } = findByProps("FlashList"); -export default function AddonPage({ card: CardComponent, ...props }: AddonPageProps) { +export default function AddonPage({ card: CardComponent, ...props }: AddonPageProps) { useProxy(settings); useProxy(props.items); @@ -67,6 +67,7 @@ export default function AddonPage({ card: CardComponent, ...props }: AddonPag data={data} estimatedItemSize={136} ListHeaderComponent={headerElement} + onLoad={console.log} contentContainerStyle={{ paddingBottom: 90, paddingHorizontal: 5 }} renderItem={({ item }: any) => ( diff --git a/src/core/ui/settings/pages/Plugins/PluginCard.tsx b/src/core/ui/settings/pages/Plugins/PluginCard.tsx index 69a733d..7d18b7c 100644 --- a/src/core/ui/settings/pages/Plugins/PluginCard.tsx +++ b/src/core/ui/settings/pages/Plugins/PluginCard.tsx @@ -7,7 +7,7 @@ import { lazyDestructure } from "@lib/utils/lazy"; import { findByProps } from "@metro"; import { NavigationNative, tokens } from "@metro/common"; import { Card, IconButton, Stack, TableSwitch, Text } from "@metro/common/components"; -import { createContext, useContext } from "react"; +import { createContext, memo, useContext } from "react"; import { Image, View } from "react-native"; import { usePluginCardStyles } from "./usePluginCardStyles"; @@ -48,14 +48,11 @@ function Title() { ); - if (!icon) return textElement; - - return ; } -export default function PluginCard({ item: plugin }: CardWrapper) { +const Actions = memo(() => { + const plugin = usePlugin(); const navigation = NavigationNative.useNavigation(); + return + navigation.push("VendettaCustomPage", { + title: plugin.manifest.name, + render: getSettingsComponent(plugin.id), + })} + /> + void showSheet( + "PluginInfoActionSheet", + import("./sheets/PluginInfoActionSheet"), + { plugin, navigation } + )} + /> + ; +}); + +export default function PluginCard({ item: plugin }: CardWrapper) { useProxy(plugin); return ( @@ -105,28 +128,7 @@ export default function PluginCard({ item: plugin }: CardWrapper) { - - navigation.push("VendettaCustomPage", { - title: plugin.manifest.name, - render: getSettingsComponent(plugin.id), - })} - /> - void showSheet( - "PluginInfoActionSheet", - import("./sheets/PluginInfoActionSheet"), - { plugin, navigation } - )} - /> - + { diff --git a/src/core/ui/settings/pages/Plugins/index.tsx b/src/core/ui/settings/pages/Plugins/index.tsx index 9a6a139..e804669 100644 --- a/src/core/ui/settings/pages/Plugins/index.tsx +++ b/src/core/ui/settings/pages/Plugins/index.tsx @@ -2,7 +2,7 @@ import { Strings } from "@core/i18n"; import AddonPage from "@core/ui/components/AddonPage"; import PluginCard from "@core/ui/settings/pages/Plugins/PluginCard"; import { useProxy } from "@lib/api/storage"; -import { BunnyPlugin, idToSource, installPlugin, sourceToObject } from "@lib/managers/plugins"; +import { BunnyPlugin, installPlugin, selectedSources, sourceStore } from "@lib/managers/plugins"; import { settings } from "@lib/settings"; import { Author } from "@lib/utils/types"; @@ -17,8 +17,8 @@ export default function Plugins() { "manifest.description", p => p.manifest.authors?.map((a: Author) => a.name).join() ]} - items={idToSource} - resolveItem={id => sourceToObject[id]} + items={selectedSources} + resolveItem={source => sourceStore[source]} fetchFunction={installPlugin} safeModeMessage={Strings.SAFE_MODE_NOTICE_PLUGINS} card={PluginCard} diff --git a/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx b/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx index 18a524f..cbc12ea 100644 --- a/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx +++ b/src/core/ui/settings/pages/Plugins/sheets/PluginInfoActionSheet.tsx @@ -1,7 +1,7 @@ import { formatString, Strings } from "@core/i18n"; import { requireAssetIndex } from "@lib/api/assets"; import { purgeStorage, useProxy } from "@lib/api/storage"; -import { BunnyPlugin, fetchPlugin, getSettingsComponent, removePlugin, startPlugin, stopPlugin } from "@lib/managers/plugins"; +import { BunnyPlugin, fetchAndStorePlugin, getSettingsComponent, removePlugin, startPlugin, stopPlugin } from "@lib/managers/plugins"; import { showConfirmationAlert } from "@lib/ui/alerts"; import { hideSheet } from "@lib/ui/sheets"; import { showToast } from "@lib/ui/toasts"; @@ -50,7 +50,7 @@ export default function PluginInfoActionSheet({ plugin, navigation }: InfoProps) if (plugin.enabled) stopPlugin(plugin.id, false); try { - await fetchPlugin(plugin.id); + await fetchAndStorePlugin(plugin.id); showToast(Strings.PLUGIN_REFETCH_SUCCESSFUL, requireAssetIndex("toast_image_saved")); } catch { showToast(Strings.PLUGIN_REFETCH_FAILED, requireAssetIndex("Small")); @@ -92,7 +92,7 @@ export default function PluginInfoActionSheet({ plugin, navigation }: InfoProps) if (plugin.enabled) stopPlugin(plugin.id, false); try { - await fetchPlugin(plugin.id); + await fetchAndStorePlugin(plugin.id); showToast(Strings.PLUGIN_REFETCH_SUCCESSFUL, requireAssetIndex("toast_image_saved")); } catch { showToast(Strings.PLUGIN_REFETCH_FAILED, requireAssetIndex("Small")); diff --git a/src/index.ts b/src/index.ts index 19fe5fd..7366561 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,7 +57,9 @@ export default async () => { window.bunny = lib; // Once done, load plugins - initPlugins().then(u => lib.unload.push(u)); + initPlugins() + .then(u => lib.unload.push(u)) + .catch(() => alert("Failed to initialize Bunny plugins")); // Update the fonts updateFonts(); diff --git a/src/lib/managers/plugins.ts b/src/lib/managers/plugins.ts index 0c3e9f2..2640c48 100644 --- a/src/lib/managers/plugins.ts +++ b/src/lib/managers/plugins.ts @@ -37,6 +37,7 @@ export interface BunnyPlugin { * Message of plugin startup error. Gone after plugin boots successfully * */ error?: string; + // TODO: Use fs to avoid unnecessary memory usage js: string; @@ -46,16 +47,16 @@ export interface BunnyPlugin { id: string; } -const BUNNY_PROXY_PREFIX = "https://bn-plugins.github.io/vd-proxy"; +export const BUNNY_PROXY_PREFIX = "https://bn-plugins.github.io/vd-proxy"; +const VD_PROXY_PREFIX = "https://vd-plugins.github.io/proxy"; const OLD_BUNNY_PROXY_PREFIX = "https://bunny-mod.github.io/plugins-proxy"; const pluginsEnabled = () => !settings.safeMode?.enabled; const _pluginInstances: Record = {}; -export const idToSource = wrapSync(createStorage>(createMMKVBackend("SELECTED_PLUGINS"))); - -export const sourceToObject = proxyLazy(() => { +export const selectedSources = wrapSync(createStorage>(createMMKVBackend("SELECTED_PLUGIN_SOURCES"))); +export const sourceStore = proxyLazy(() => { type StorageInterface = Record; const storagePromise = createStorage(createMMKVBackend("VENDETTA_PLUGINS")); @@ -70,21 +71,21 @@ export const sourceToObject = proxyLazy(() => { }); export function getPluginById(id: string) { - if (!idToSource[id]) { - for (const plugin of Object.values(sourceToObject)) { + if (!selectedSources[id]) { + for (const plugin of Object.values(sourceStore)) { if (plugin?.pluginId === id) { - idToSource[id] = plugin.source; + selectedSources[id] = plugin.source; break; } } } - return idToSource[id] ? sourceToObject[idToSource[id]!] : undefined; + return selectedSources[id] ? sourceStore[selectedSources[id]!] : undefined; } -export async function fetchPlugin(source: string) { +export async function fetchAndStorePlugin(source: string) { if (!source.endsWith("/")) source += "/"; - const existingPlugin = sourceToObject[source]; + const existingPlugin = sourceStore[source]; const fetch = (url: string) => safeFetch( url @@ -112,7 +113,7 @@ export async function fetchPlugin(source: string) { invariant(pluginJs || existingPlugin, `Failed to fetch JS from ${source}`); - return sourceToObject[source] = { + return sourceStore[source] = { id: source, source: source, pluginId: pluginManifest.name, @@ -126,9 +127,9 @@ export async function fetchPlugin(source: string) { export async function installPlugin(source: string, enabled = true) { if (!source.endsWith("/")) source += "/"; - invariant(!(source in sourceToObject), "Source was already installed"); + invariant(!(source in sourceStore), "Source was already installed"); - const plugin = await fetchPlugin(source); + const plugin = await fetchAndStorePlugin(source); if (enabled) await startPlugin(plugin.pluginId); } @@ -194,7 +195,7 @@ export async function removePlugin(id: string) { const plugin = getPluginById(id); invariant(plugin, "Removing non-existent plugin"); if (plugin.enabled) stopPlugin(id); - delete sourceToObject[plugin.source]; + delete sourceStore[plugin.source]; await purgeStorage(plugin.source); } @@ -202,29 +203,30 @@ export async function removePlugin(id: string) { * @internal */ export async function initPlugins() { - await awaitStorage(sourceToObject, idToSource, settings); + await awaitStorage(sourceStore, selectedSources, settings); // TODO: Optimize this if (pluginsEnabled()) { - const allIds = [...new Set(Object.values(sourceToObject).map(s => s!.pluginId))]; + const allIds = [...new Set(Object.values(sourceStore).map(s => s!.pluginId))]; // Loop over enabled plugins, update and start them const enabledPlugins = allIds.filter(id => getPluginById(id)?.enabled); await Promise.all(enabledPlugins.map(async pl => { if (getPluginById(pl)!.update) { try { - await fetchPlugin(pl); + await fetchAndStorePlugin(pl); } catch (e) { logger.error(e); } } + await startPlugin(pl); })); // Loop over disabled plugins that are allowed to update allIds .filter(id => !getPluginById(id)?.enabled && getPluginById(id)!.update) - .forEach(id => fetchPlugin(id)); + .forEach(id => fetchAndStorePlugin(id)); } return () => Object.keys(_pluginInstances).forEach(p => stopPlugin(p, false)); diff --git a/src/lib/utils/constants.ts b/src/lib/utils/constants.ts index 027c9d4..8afe2ba 100644 --- a/src/lib/utils/constants.ts +++ b/src/lib/utils/constants.ts @@ -1,6 +1,5 @@ export const DISCORD_SERVER = "https://discord.gg/XjYgWXHb9Q"; export const GITHUB = "https://github.com/pyoncord"; -export const VD_PROXY_PREFIX = "https://vd-plugins.github.io/proxy"; export const HTTP_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/; export const HTTP_REGEX_MULTI = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&//=]*)/g;