fix(metro): more checks for the event the cache got faulty (hopefully)

This commit is contained in:
amsyarasyiq 2024-05-29 09:26:27 +08:00
parent 9bd47d28a4
commit 4cca972185
4 changed files with 43 additions and 20 deletions

View file

@ -1,7 +1,7 @@
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
import { throttle } from "@lib/utils/throttle";
const CACHE_VERSION = 24;
const CACHE_VERSION = 29;
const BUNNY_METRO_CACHE_KEY = `__bunny_metro_cache_key_v${CACHE_VERSION}__`;
export enum ExportsFlags {
@ -9,9 +9,13 @@ export enum ExportsFlags {
BLACKLISTED = 1 << 1
}
export enum ModulesMapInternal {
FULL_LOOKUP,
NOT_FOUND
}
type ModulesMap = {
_?: 1;
[id: number]: number;
[flag in number | `_${ModulesMapInternal}`]?: 0 | ExportsFlags | undefined;
};
let _metroCache = null as unknown as ReturnType<typeof buildInitCache>;
@ -22,6 +26,7 @@ function buildInitCache() {
const cache = {
_v: CACHE_VERSION,
_buildNumber: ClientInfoManager.Build as number,
_modulesCount: Object.keys(window.modules).length,
exportsIndex: {} as Record<string, number>,
findIndex: {} as Record<string, ModulesMap | undefined>,
polyfillIndex: {} as Record<string, ModulesMap | undefined>,
@ -50,6 +55,10 @@ export async function initMetroCache() {
_metroCache = null!;
throw "cache invalidated; version mismatch";
}
if (_metroCache._modulesCount !== Object.keys(window.modules).length) {
_metroCache = null!;
throw "cache invalidated; modules count mismatch";
}
} catch {
buildInitCache();
}
@ -78,33 +87,32 @@ export function indexBlacklistFlag(id: number) {
}
export function getCacherForUniq(uniq: string, allFind: boolean) {
let indexObject = _metroCache.findIndex[uniq];
const indexObject = _metroCache.findIndex[uniq] ??= {};
return {
cacheId(moduleId: number, exports: any) {
indexObject ??= _metroCache.findIndex[uniq] ??= {};
// TODO: A log here perhaps
indexObject[moduleId] ??= extractExportsFlags(exports);
saveCache();
},
finish() {
indexObject ??= _metroCache.findIndex[uniq] ??= {};
if (allFind) indexObject._ = 1;
// Finish may not be called by single find
finish(notFound: boolean) {
if (allFind) indexObject[`_${ModulesMapInternal.FULL_LOOKUP}`] = 1;
if (notFound) indexObject[`_${ModulesMapInternal.NOT_FOUND}`] = 1;
saveCache();
}
};
}
export function getPolyfillModuleCacher(name: string) {
let indexObject = _metroCache.polyfillIndex[name];
const indexObject = _metroCache.polyfillIndex[name] ??= {};
return {
getModules() {
return require("@metro/modules").getCachedPolyfillModules(name);
},
cacheId(moduleId: number) {
indexObject ??= _metroCache.polyfillIndex[name] ??= {};
indexObject[moduleId] = 1;
saveCache();
}

View file

@ -33,7 +33,7 @@ export function findModule<A extends unknown[]>(filter: FilterFn<A>) {
}
}
finish();
finish(true);
return [];
}
@ -71,7 +71,7 @@ export function findAllModule<A extends unknown[]>(filter: FilterFn<A>) {
}
}
finish();
finish(foundExports.length === 0);
return foundExports;
}

View file

@ -1,4 +1,4 @@
import { ExportsFlags, getMetroCache, indexBlacklistFlag, indexExportsFlags } from "@metro/caches";
import { ExportsFlags, getMetroCache, indexBlacklistFlag, indexExportsFlags, ModulesMapInternal } from "@metro/caches";
import { Metro } from "@metro/types";
import { before, instead } from "spitroast";
@ -166,7 +166,7 @@ export function requireModule(id: Metro.ModuleID) {
if (!metroModules[0]?.isInitialized) metroRequire(0);
if (blacklistedIds.has(id)) return undefined;
if (Number(id) === -1) return require("@metro/polyfills/redesign").default;
if (Number(id) === -1) return require("@metro/polyfills/redesign");
if (metroModules[id]?.isInitialized && !metroModules[id]?.hasError) {
return metroRequire(id);
@ -191,12 +191,20 @@ export function requireModule(id: Metro.ModuleID) {
}
export function* getModules(uniq: string, all = false) {
yield [-1, require("@metro/polyfills/redesign").default];
yield [-1, require("@metro/polyfills/redesign")];
let cache = getMetroCache().findIndex[uniq];
if (all && !cache?._) cache = undefined;
if (all && !cache?.[`_${ModulesMapInternal.FULL_LOOKUP}`]) cache = undefined;
if (cache?.[`_${ModulesMapInternal.NOT_FOUND}`]) return;
for (const id in cache ?? metroModules) {
for (const id in cache) {
if (id[0] === "_") continue;
const exports = requireModule(Number(id));
if (isBadExports(exports)) continue;
yield [id, exports];
}
for (const id in metroModules) {
const exports = requireModule(Number(id));
if (isBadExports(exports)) continue;
yield [id, exports];
@ -205,7 +213,14 @@ export function* getModules(uniq: string, all = false) {
export function* getCachedPolyfillModules(name: string) {
const cache = getMetroCache().polyfillIndex[name];
for (const id in cache ?? metroModules) {
for (const id in cache) {
const exports = requireModule(Number(id));
if (isBadExports(exports)) continue;
yield [id, exports];
}
for (const id in metroModules) {
const exports = requireModule(Number(id));
if (isBadExports(exports)) continue;
yield [id, exports];

View file

@ -20,7 +20,7 @@ interface FindProxyContext<A extends unknown[]> {
function getIndexedSingleFind<A extends unknown[]>(filter: FilterFn<A>) {
const modulesMap = getMetroCache().findIndex[filter.uniq];
if (!modulesMap) return;
const id = Object.keys(modulesMap).filter(k => k !== "_")[0];
const id = Object.keys(modulesMap).filter(k => k[0] !== "_")[0];
return id ? Number(id) : void 0;
}