fix?(metro): handle faulty assets cache

This commit is contained in:
amsyarasyiq 2024-06-16 18:04:48 +08:00
parent bf21e98c5b
commit 5f3c982a5e
3 changed files with 17 additions and 11 deletions

View file

@ -1,11 +1,11 @@
import { after } from "@lib/api/patcher";
import { getMetroCache, registerAssetCacheId } from "@metro/caches";
import { getMetroCache, indexAssetName } from "@metro/caches";
import { getImportingModuleId, requireModule } from "@metro/modules";
// TODO: Deprecate this map, make another that maps to an array of assets (Asset[]) instead
/**
* Pitfall: Multiple assets may have the same name, this is fine if we require the asset only for display,\
* but not when used to get the registered id/index. In some condition, this would break some plugins like HideGiftButton that gets id by name.\
* but not when used to get the registered id/index. In some condition, this would break some plugins like HideGiftButton that gets id by name for patching.\
*/
export const assetsMap: Record<string, Asset> = new Proxy<any>({}, {
get(cache, p) {
@ -13,13 +13,13 @@ export const assetsMap: Record<string, Asset> = new Proxy<any>({}, {
if (cache[p]) return cache[p];
const moduleIds = getMetroCache().assetsIndex[p];
if (moduleIds == null || Object.keys(moduleIds).length === 0) return undefined;
if (moduleIds == null) return undefined;
for (const id in moduleIds) {
const assetIndex = requireModule(Number(id));
const assetDefinition = assetsModule.getAssetByID(assetIndex);
if (typeof assetIndex !== "number") continue;
// TODO: we shouldn't need this, this should never happen (unreproducible)
const assetDefinition = assetsModule.getAssetByID(assetIndex);
if (!assetDefinition) continue;
assetDefinition.index ??= assetDefinition.id ??= assetIndex;
@ -34,8 +34,11 @@ export const assetsMap: Record<string, Asset> = new Proxy<any>({}, {
return cache[p];
},
ownKeys(cache) {
const keys = Reflect.ownKeys(getMetroCache().assetsIndex);
for (const key of keys) cache[key] = this.get!(cache, key, {});
const keys = [] as Array<string>;
for (const key in getMetroCache().assetsIndex) {
cache[key] = this.get!(cache, key, {});
if (cache[key]) keys.push(key);
}
return keys;
},
});
@ -64,7 +67,7 @@ export function patchAssets(module: AssetModule) {
const unpatch = after("registerAsset", assetsModule, ([asset]: Asset[]) => {
const moduleId = getImportingModuleId();
if (moduleId !== -1) registerAssetCacheId(asset.name, moduleId);
if (moduleId !== -1) indexAssetName(asset.name, moduleId);
});
return unpatch;

View file

@ -1,7 +1,7 @@
import { ClientInfoManager, MMKVManager } from "@lib/api/native/modules";
import { throttle } from "@lib/utils/throttle";
const CACHE_VERSION = 33;
const CACHE_VERSION = 34;
const BUNNY_METRO_CACHE_KEY = "__bunny_metro_cache_key__";
export enum ExportsFlags {
@ -45,6 +45,7 @@ function buildInitCache() {
return cache;
}
// Store in file system
export async function initMetroCache() {
const rawCache = await MMKVManager.getItem(BUNNY_METRO_CACHE_KEY);
if (rawCache == null) return void buildInitCache();
@ -123,7 +124,7 @@ export function getPolyfillModuleCacher(name: string) {
};
}
export function registerAssetCacheId(name: string, moduleId: number) {
export function indexAssetName(name: string, moduleId: number) {
if (!isNaN(moduleId)) {
(_metroCache.assetsIndex[name] ??= {})[moduleId] = 1;
saveCache();

View file

@ -27,7 +27,9 @@ for (const key in metroModules) {
if (metroModule!.factory) {
instead("factory", metroModule, ((args: Parameters<Metro.FactoryFn>, origFunc: Metro.FactoryFn) => {
const originalImportingId = _importingModuleId;
_importingModuleId = id;
const { 1: metroRequire, 4: moduleObject } = args;
args[2 /* metroImportDefault */] = id => {
@ -52,7 +54,7 @@ for (const key in metroModules) {
blacklistModule(id);
}
_importingModuleId = -1;
_importingModuleId = originalImportingId;
}) as any); // If only spitroast had better types
}
}