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

View file

@ -33,7 +33,7 @@ export function findModule<A extends unknown[]>(filter: FilterFn<A>) {
} }
} }
finish(); finish(true);
return []; return [];
} }
@ -71,7 +71,7 @@ export function findAllModule<A extends unknown[]>(filter: FilterFn<A>) {
} }
} }
finish(); finish(foundExports.length === 0);
return foundExports; 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 { Metro } from "@metro/types";
import { before, instead } from "spitroast"; import { before, instead } from "spitroast";
@ -166,7 +166,7 @@ export function requireModule(id: Metro.ModuleID) {
if (!metroModules[0]?.isInitialized) metroRequire(0); if (!metroModules[0]?.isInitialized) metroRequire(0);
if (blacklistedIds.has(id)) return undefined; 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) { if (metroModules[id]?.isInitialized && !metroModules[id]?.hasError) {
return metroRequire(id); return metroRequire(id);
@ -191,12 +191,20 @@ export function requireModule(id: Metro.ModuleID) {
} }
export function* getModules(uniq: string, all = false) { 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]; 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)); const exports = requireModule(Number(id));
if (isBadExports(exports)) continue; if (isBadExports(exports)) continue;
yield [id, exports]; yield [id, exports];
@ -205,7 +213,14 @@ export function* getModules(uniq: string, all = false) {
export function* getCachedPolyfillModules(name: string) { export function* getCachedPolyfillModules(name: string) {
const cache = getMetroCache().polyfillIndex[name]; 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)); const exports = requireModule(Number(id));
if (isBadExports(exports)) continue; if (isBadExports(exports)) continue;
yield [id, exports]; yield [id, exports];

View file

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