[Global] Major refactors, allow unloading!
This commit is contained in:
parent
0be8cdac05
commit
0ba9ee600c
10 changed files with 137 additions and 116 deletions
|
@ -3,10 +3,15 @@ import { findByProps } from "@metro/filters";
|
|||
import { after } from "@lib/patcher";
|
||||
|
||||
const commandsModule = findByProps("getBuiltInCommands")
|
||||
|
||||
let commands: ApplicationCommand[] = [];
|
||||
|
||||
after("getBuiltInCommands", commandsModule, (args, res) => res.concat(commands));
|
||||
export function patchCommands() {
|
||||
const unpatch = after("getBuiltInCommands", commandsModule, (args, res) => res.concat(commands));
|
||||
return () => {
|
||||
commands = [];
|
||||
unpatch();
|
||||
}
|
||||
}
|
||||
|
||||
export function registerCommand(command: ApplicationCommand): () => void {
|
||||
// Get built in commands
|
||||
|
|
|
@ -34,14 +34,16 @@ export function connectToDebugger(url: string) {
|
|||
});
|
||||
}
|
||||
|
||||
export function patchLogHook() {
|
||||
after("nativeLoggingHook", globalThis, (args, ret) => {
|
||||
if (socket?.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify({ message: args[0], level: args[1] }));
|
||||
}
|
||||
|
||||
export function patchLogHook() {
|
||||
const unpatch = after("nativeLoggingHook", globalThis, (args) => {
|
||||
if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify({ message: args[0], level: args[1] }));
|
||||
logger.log(args[0]);
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket && socket.close();
|
||||
unpatch();
|
||||
}
|
||||
}
|
||||
|
||||
export const versionHash = "__vendettaVersion";
|
||||
|
|
|
@ -26,7 +26,7 @@ for (const key in window.modules) {
|
|||
}
|
||||
|
||||
// Function to filter through modules
|
||||
export const filterModules = (modules: MetroModules, single = false) => (filter: (m: any) => boolean) => {
|
||||
const filterModules = (modules: MetroModules, single = false) => (filter: (m: any) => boolean) => {
|
||||
const found = [];
|
||||
|
||||
// Get the previous moment locale
|
||||
|
@ -53,7 +53,7 @@ export const filterModules = (modules: MetroModules, single = false) => (filter:
|
|||
found.push(module.default);
|
||||
}
|
||||
|
||||
if(filter(module)) {
|
||||
if (filter(module)) {
|
||||
if (single) return module;
|
||||
else found.push(module);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import { awaitSyncWrapper, createStorage, wrapSync } from "@lib/storage";
|
|||
import logger from "@lib/logger";
|
||||
import Subpage from "@ui/settings/components/Subpage";
|
||||
|
||||
// TODO: Properly implement hash-based updating
|
||||
|
||||
type EvaledPlugin = {
|
||||
onLoad?(): void;
|
||||
onUnload(): void;
|
||||
|
@ -20,7 +22,7 @@ export async function fetchPlugin(id: string, enabled = true) {
|
|||
let pluginManifest: PluginManifest;
|
||||
|
||||
try {
|
||||
pluginManifest = await (await fetch(new URL("manifest.json", id), { cache: "no-store" })).json();
|
||||
pluginManifest = await (await fetch(id + "manifest.json", { cache: "no-store" })).json();
|
||||
} catch {
|
||||
throw new Error(`Failed to fetch manifest for ${id}`);
|
||||
}
|
||||
|
@ -30,7 +32,7 @@ export async function fetchPlugin(id: string, enabled = true) {
|
|||
// TODO: Remove duplicate error if possible
|
||||
try {
|
||||
// by polymanifest spec, plugins should always specify their main file, but just in case
|
||||
pluginJs = await (await fetch(new URL(pluginManifest.main || "index.js", id), { cache: "no-store" })).text();
|
||||
pluginJs = await (await fetch(id + (pluginManifest.main || "index.js"), { cache: "no-store" })).text();
|
||||
} catch {
|
||||
throw new Error(`Failed to fetch JS for ${id}`);
|
||||
}
|
||||
|
@ -49,7 +51,6 @@ export async function fetchPlugin(id: string, enabled = true) {
|
|||
}
|
||||
|
||||
export async function evalPlugin(plugin: Plugin) {
|
||||
// TODO: Refactor to not depend on own window object
|
||||
const vendettaForPlugins = {
|
||||
...window.vendetta,
|
||||
plugin: {
|
||||
|
@ -89,7 +90,7 @@ export async function startPlugin(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
export function stopPlugin(id: string) {
|
||||
export function stopPlugin(id: string, disable = true) {
|
||||
const plugin = plugins[id];
|
||||
const pluginRet = loadedPlugins[id];
|
||||
if (!plugin) throw new Error("Attempted to stop non-existent plugin");
|
||||
|
@ -102,7 +103,7 @@ export function stopPlugin(id: string) {
|
|||
}
|
||||
|
||||
delete loadedPlugins[id];
|
||||
plugin.enabled = false;
|
||||
disable && (plugin.enabled = false);
|
||||
}
|
||||
|
||||
export function removePlugin(id: string) {
|
||||
|
@ -111,15 +112,18 @@ export function removePlugin(id: string) {
|
|||
delete plugins[id];
|
||||
}
|
||||
|
||||
export async function initializePlugins() {
|
||||
export async function initPlugins() {
|
||||
await awaitSyncWrapper(plugins);
|
||||
|
||||
const allIds = Object.keys(plugins);
|
||||
await Promise.allSettled(allIds.map((pl) => fetchPlugin(pl, false)));
|
||||
for (const pl of allIds.filter((pl) => plugins[pl].enabled))
|
||||
startPlugin(pl);
|
||||
for (const pl of allIds.filter((pl) => plugins[pl].enabled)) startPlugin(pl);
|
||||
|
||||
return stopAllPlugins;
|
||||
}
|
||||
|
||||
const stopAllPlugins = () => Object.keys(plugins).forEach(p => stopPlugin(p, false));
|
||||
|
||||
export const getSettings = (id: string) => loadedPlugins[id]?.settings;
|
||||
|
||||
export function showSettings(plugin: Plugin) {
|
||||
|
|
54
src/lib/windowObject.ts
Normal file
54
src/lib/windowObject.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { VendettaObject } from "@types";
|
||||
import patcher from "@lib/patcher";
|
||||
import logger from "@lib/logger";
|
||||
import settings from "@lib/settings";
|
||||
import copyText from "@utils/copyText";
|
||||
import findInReactTree from "@utils/findInReactTree";
|
||||
import findInTree from "@utils/findInTree";
|
||||
import * as constants from "@lib/constants";
|
||||
import * as debug from "@lib/debug";
|
||||
import * as plugins from "@lib/plugins";
|
||||
import * as commands from "@lib/commands";
|
||||
import * as storage from "@lib/storage";
|
||||
import * as metro from "@metro/filters";
|
||||
import * as common from "@metro/common";
|
||||
import * as components from "@ui/components";
|
||||
import * as toasts from "@ui/toasts";
|
||||
import * as assets from "@ui/assets";
|
||||
|
||||
function without<T extends Record<string, any>>(object: T, ...keys: string[]) {
|
||||
const cloned = { ...object };
|
||||
keys.forEach((k) => delete cloned[k]);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
// I wish Hermes let me do async arrow functions
|
||||
export default async function windowObject(unloads: any[]): Promise<VendettaObject> {
|
||||
return {
|
||||
patcher: without(patcher, "unpatchAll"),
|
||||
metro: { ...metro, common: { ...common } },
|
||||
constants: { ...constants },
|
||||
utils: {
|
||||
copyText: copyText,
|
||||
findInReactTree: findInReactTree,
|
||||
findInTree: findInTree,
|
||||
},
|
||||
debug: without(debug, "versionHash", "patchLogHook"),
|
||||
ui: {
|
||||
components,
|
||||
toasts,
|
||||
assets,
|
||||
},
|
||||
plugins: without(plugins, "initPlugins"),
|
||||
commands: without(commands, "patchCommands"),
|
||||
storage,
|
||||
settings,
|
||||
logger,
|
||||
version: debug.versionHash,
|
||||
unload: () => {
|
||||
unloads.filter(i => typeof i === "function").forEach(p => p());
|
||||
// @ts-expect-error explode
|
||||
delete window.vendetta;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue