fix: loading plugin's on 341.3+
This commit is contained in:
parent
0dc4e8cdf7
commit
185f4ab6f3
2 changed files with 66 additions and 90 deletions
54
src/index.ts
54
src/index.ts
|
|
@ -11,13 +11,8 @@ import { injectFluxInterceptor } from "@lib/api/flux";
|
|||
import { patchJsx } from "@lib/api/react/jsx";
|
||||
import { logger } from "@lib/utils/logger";
|
||||
import { patchSettings } from "@ui/settings";
|
||||
import { updaterSettings } from "@lib/api/settings";
|
||||
import { InteractionManager } from "react-native";
|
||||
import { getDebugInfo, initDebugger } from "@lib/api/debug";
|
||||
|
||||
// Debug toggle helper (temporary runtime fallback). The helper is dynamically
|
||||
// imported when needed (to avoid bundling it permanently) and removed after use.
|
||||
|
||||
import * as lib from "./lib";
|
||||
import { timings } from "@lib/utils/timings";
|
||||
|
||||
|
|
@ -66,52 +61,19 @@ export default async () => {
|
|||
const { VdPluginManager } = await import("@core/vendetta/plugins");
|
||||
const { initPlugins, updatePlugins } = await import("@lib/addons/plugins");
|
||||
|
||||
// Initialize Vendetta plugins (may start many plugins) — do not block UI.
|
||||
await Promise.all([
|
||||
VdPluginManager.initPlugins()
|
||||
.then((u) => lib.unload.push(u))
|
||||
.catch((e) => logger.log("Vendetta init failed:", e));
|
||||
.then((u) => u && lib.unload.push(u))
|
||||
.catch((e) => logger.log("Vendetta init failed:", e)),
|
||||
initPlugins()
|
||||
.catch((e) => logger.log("initPlugins failed:", e)),
|
||||
]);
|
||||
|
||||
// Start ShiggyCord (Bunny) plugins now without forcing repository updates.
|
||||
// Plugin repository fetching is deferred so the app can finish launching first.
|
||||
// Stagger plugin startup to reduce CPU/memory spikes: use smaller batches and a small interval.
|
||||
// This keeps the UI responsive while plugins initialize in the background.
|
||||
initPlugins({ staggerInterval: 500, batchSize: 2 });
|
||||
|
||||
// Attempt a lightweight recovery toggle if some core plugins failed to start.
|
||||
try {
|
||||
// Dynamically import the helper (if present) but suppress verbose errors.
|
||||
const mod = await import("@core/debug/toggleCorePlugins").catch(
|
||||
() => null,
|
||||
);
|
||||
if (mod?.default) {
|
||||
// Run helper with minimal noise; ignore failures.
|
||||
mod.default({ offDuration: 1500 }).catch(() => {});
|
||||
}
|
||||
|
||||
// Try to remove the helper source file (best-effort, ignore failures).
|
||||
await import("@lib/api/native/fs")
|
||||
.then((fs) => fs.removeFile("src/core/debug/toggleCorePlugins.ts"))
|
||||
.catch(() => {});
|
||||
} catch {
|
||||
// suppressed
|
||||
}
|
||||
updatePlugins()
|
||||
.catch((e) => logger.log("updatePlugins failed:", e));
|
||||
|
||||
// Update fonts in background
|
||||
updateFonts().catch((e) => logger.log("updateFonts failed:", e));
|
||||
|
||||
// Schedule plugin repository update after a delay (5 minutes) so update work
|
||||
// does not impact initial launch performance.
|
||||
setTimeout(
|
||||
() => {
|
||||
updatePlugins().catch((e) =>
|
||||
logger.log("updatePlugins failed (deferred 5min):", e),
|
||||
);
|
||||
},
|
||||
5 * 60 * 1000,
|
||||
);
|
||||
|
||||
// Note: we intentionally moved the call to `updatePlugins()` above so core
|
||||
// plugins are registered prior to calling `initPlugins()`.
|
||||
};
|
||||
|
||||
// Preferred: wait until interactions finish (animations / navigation).
|
||||
|
|
|
|||
|
|
@ -752,27 +752,54 @@ export async function updatePlugins() {
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const enabledIds = [...registeredPlugins.keys()].filter(
|
||||
(id) => isPluginEnabled(id) && !pluginInstances.has(id),
|
||||
);
|
||||
await Promise.allSettled(
|
||||
enabledIds.map(async (id) => {
|
||||
try {
|
||||
await startPlugin(id).catch((e) => {
|
||||
console.error(`Failed to start plugin ${id}:`, e);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Unexpected error while starting plugin ${id}:`, error);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize plugins but stagger startup to avoid CPU spikes during app start.
|
||||
* Register all installed plugins from local storage manifests without any
|
||||
* network fetch. This lets initPlugins() start plugins immediately using
|
||||
* previously-cached scripts, keeping startup snappy.
|
||||
*
|
||||
* This replaces the original "start all enabled plugins in parallel" approach
|
||||
* with a configurable staggered startup: plugins are started in small batches and
|
||||
* we await a small interval between batches. This reduces short-lived CPU and I/O contention
|
||||
* that causes jank on low-end devices.
|
||||
*
|
||||
* Backwards-compatible: callers can still call initPlugins() with no arguments.
|
||||
*
|
||||
* Options:
|
||||
* - staggerInterval (ms) - wait time between batches (default: 100)
|
||||
* - batchSize - how many plugins to start concurrently in a single batch (default: 3)
|
||||
* Safe to call multiple times — skips already-registered plugins.
|
||||
*/
|
||||
export async function initPlugins(
|
||||
options: { staggerInterval?: number; batchSize?: number } = {},
|
||||
) {
|
||||
const { staggerInterval = 100, batchSize = 3 } = options;
|
||||
export async function registerInstalledPlugins() {
|
||||
await awaitStorage(pluginRepositories, pluginSettings);
|
||||
|
||||
const ids = Object.keys(pluginSettings ?? {});
|
||||
if (ids.length === 0) return;
|
||||
|
||||
// Load all manifest files from local storage in parallel.
|
||||
const results = await Promise.allSettled(
|
||||
ids.map(async (id) => {
|
||||
if (registeredPlugins.has(id) || isCorePlugin(id)) return;
|
||||
const loaded = await preloadStorageIfExists(`plugins/manifests/${id}.json`);
|
||||
if (loaded) {
|
||||
const manifest = getPreloadedStorage<t.BunnyPluginManifest>(
|
||||
`plugins/manifests/${id}.json`,
|
||||
);
|
||||
if (manifest) {
|
||||
registeredPlugins.set(id, manifest);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function initPlugins() {
|
||||
// Ensure core plugins are registered prior to any plugin startup logic so
|
||||
// settings pages and UI that read registered/core plugins show them.
|
||||
// registerCorePlugins is synchronous and idempotent, but call it here as a
|
||||
|
|
@ -784,6 +811,7 @@ export async function initPlugins(
|
|||
}
|
||||
|
||||
await awaitStorage(pluginRepositories, pluginSettings);
|
||||
await registerInstalledPlugins();
|
||||
|
||||
// Collect enabled plugin ids
|
||||
const enabledIds = [...registeredPlugins.keys()].filter((id) =>
|
||||
|
|
@ -792,21 +820,13 @@ export async function initPlugins(
|
|||
|
||||
if (enabledIds.length === 0) return;
|
||||
|
||||
// Helper sleep
|
||||
const sleep = (ms: number) => new Promise<void>((res) => setTimeout(res, ms));
|
||||
|
||||
// Start plugins in batches to avoid starting all at once.
|
||||
for (let i = 0; i < enabledIds.length; i += batchSize) {
|
||||
const batch = enabledIds.slice(i, i + batchSize);
|
||||
|
||||
// Start the batch in parallel but don't let exceptions bubble to halt everything.
|
||||
// Start all enabled plugins in parallel
|
||||
await Promise.allSettled(
|
||||
batch.map(async (id) => {
|
||||
enabledIds.map(async (id) => {
|
||||
try {
|
||||
// Only attempt to start if still enabled and not already started
|
||||
if (!isPluginEnabled(id) || pluginInstances.has(id)) return;
|
||||
await startPlugin(id).catch((e) => {
|
||||
// startPlugin may throw; ensure it doesn't crash the whole batch
|
||||
console.error(`Failed to start plugin ${id}:`, e);
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -814,10 +834,4 @@ export async function initPlugins(
|
|||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// If there are more plugins to start, wait before starting the next batch.
|
||||
if (i + batchSize < enabledIds.length) {
|
||||
await sleep(staggerInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue