feat(lib/assets): improve caching
This commit is contained in:
parent
2c56aa87c1
commit
123bc83640
3 changed files with 46 additions and 38 deletions
|
|
@ -1,6 +1,9 @@
|
|||
import { createLogger } from '@revenge-mod/utils/logger'
|
||||
import type { Metro } from '@revenge-mod/modules/types'
|
||||
import type { Asset, AssetId } from './types'
|
||||
|
||||
export const _logger = createLogger('revenge.assets')
|
||||
|
||||
export const _customs = new Set<Asset>()
|
||||
export const _overrides = new WeakMap<Asset, Asset>()
|
||||
export const _metas = new WeakMap<
|
||||
|
|
|
|||
|
|
@ -1,59 +1,52 @@
|
|||
// TODO(lib/assets): do not depend on Discord's ClientInfoModule for versioning, use native interop
|
||||
import { ClientInfoModule } from '@revenge-mod/discord/native'
|
||||
import { getStorage } from '@revenge-mod/storage'
|
||||
// import { debounce } from '@revenge-mod/utils/callbacks'
|
||||
import { createLogger } from '@revenge-mod/utils/logger'
|
||||
import { debounce } from '@revenge-mod/utils/callbacks'
|
||||
import { mergeDeep } from '@revenge-mod/utils/objects'
|
||||
import { proxify } from '@revenge-mod/utils/proxy'
|
||||
import { _logger } from './_internal'
|
||||
import type { Metro } from '@revenge-mod/modules/types'
|
||||
import type { Asset } from './types'
|
||||
|
||||
const logger = createLogger('revenge.assets.caches')
|
||||
|
||||
const Version = 1
|
||||
const CurrentKey = `${Version}.${ClientInfoModule.Build}`
|
||||
const Key = `${Version}.${ClientInfoModule.Build}`
|
||||
|
||||
const CacheStorage = getStorage<Cache>('revenge/assets', {
|
||||
default: { k: CurrentKey, c: {} },
|
||||
// In-memory cache
|
||||
export const cache: Cache = {}
|
||||
|
||||
const CacheStorage = getStorage<Cache>(`revenge/assets.${Key}`, {
|
||||
default: cache,
|
||||
directory: 'cache',
|
||||
})
|
||||
|
||||
export const cache: Cache['c'] = proxify(
|
||||
() => {
|
||||
if (CacheStorage.cache) return CacheStorage.cache.c
|
||||
},
|
||||
{ hint: 'object' },
|
||||
)!
|
||||
_logger.log(`[${performance.now()}] CacheStorage instance created`)
|
||||
|
||||
// biome-ignore lint/complexity/useArrowFunction: Arrow functions are not supported
|
||||
CacheStorage.get().then(async function (cache) {
|
||||
CacheStorage.get().then(async function (cache_) {
|
||||
// TODO(lib/assets/caches): This loads way too late and requires native interop to load earlier
|
||||
logger.log(`Loaded cache version: ${cache.k}`)
|
||||
if (cache.k !== CurrentKey) {
|
||||
await CacheStorage.delete()
|
||||
await CacheStorage.set({ k: CurrentKey, c: {} })
|
||||
|
||||
// If we are not using the default value, merge it into the in-memory cache, then point the storage cache to the in-memory cache.
|
||||
if (cache_ !== cache) {
|
||||
_logger.log(`[${performance.now()}] CacheStorage loaded`)
|
||||
Object.assign(cache, cache_)
|
||||
CacheStorage.cache = cache
|
||||
}
|
||||
})
|
||||
|
||||
export interface Cache {
|
||||
k: string
|
||||
c: {
|
||||
[key: Asset['name']]: {
|
||||
[key: Asset['type']]: Metro.ModuleID
|
||||
}
|
||||
[key: Asset['name']]: {
|
||||
[key: Asset['type']]: Metro.ModuleID
|
||||
}
|
||||
}
|
||||
|
||||
// const save = debounce(() => CacheStorage.set({}), 1000)
|
||||
const save = debounce(() => CacheStorage.set({}), 1000)
|
||||
|
||||
export async function cacheAsset(asset: Asset, moduleId: Metro.ModuleID) {
|
||||
// Merge directly into the cache, only debouncing actual writes
|
||||
mergeDeep(CacheStorage.cache!.c, {
|
||||
mergeDeep(cache, {
|
||||
[asset.name]: {
|
||||
[asset.type]: moduleId,
|
||||
},
|
||||
})
|
||||
|
||||
// Commented out because caching currently does not work properly because it is loaded too late
|
||||
// await save()
|
||||
await save()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { _initing, _uninits } from '@revenge-mod/modules/_/metro'
|
|||
import { byName, byProps } from '@revenge-mod/modules/finders/filters'
|
||||
import { waitForModules } from '@revenge-mod/modules/finders/wait'
|
||||
import { getModuleDependencies } from '@revenge-mod/modules/metro/utils'
|
||||
import { _metas, _overrides } from './_internal'
|
||||
import { cacheAsset } from './caches'
|
||||
import { _logger, _metas, _overrides } from './_internal'
|
||||
import { cache, cacheAsset } from './caches'
|
||||
import type { ReactNative } from '@revenge-mod/react/types'
|
||||
import type { Asset, ReactNativeAsset } from './types'
|
||||
|
||||
|
|
@ -25,15 +25,27 @@ const unsubAR = waitForModules(
|
|||
if (getModuleDependencies(id)!.length) {
|
||||
unsubAR()
|
||||
|
||||
// TODO(assets/patches): conditionally run this if cache does not exist
|
||||
// More fragile way, but also more performant:
|
||||
// There is exactly one asset before the reexported asset registry :/
|
||||
const firstAssetModuleId = id - 1
|
||||
for (const mId of _uninits) {
|
||||
if (mId < firstAssetModuleId) continue
|
||||
_logger.log(`[${performance.now()}] Registry found: ${id}`)
|
||||
|
||||
const deps = getModuleDependencies(mId)!
|
||||
if (deps.length === 1 && deps[0] === id) __r(mId)
|
||||
// Make sure we don't try to recache assets if it is already cached.
|
||||
let uncached = true
|
||||
for (const _ in cache) {
|
||||
uncached = false
|
||||
break
|
||||
}
|
||||
|
||||
if (uncached) {
|
||||
_logger.log('Caching assets...')
|
||||
|
||||
// More fragile way, but also more performant:
|
||||
// There is exactly one asset before the reexported asset registry :/
|
||||
const firstAssetModuleId = id - 1
|
||||
for (const mId of _uninits) {
|
||||
if (mId < firstAssetModuleId) continue
|
||||
|
||||
const deps = getModuleDependencies(mId)!
|
||||
if (deps.length === 1 && deps[0] === id) __r(mId)
|
||||
}
|
||||
}
|
||||
|
||||
// We already patched the original asset registry, so we don't need to patch again.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue