mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-04 23:18:44 +08:00
test(media): cover cards and virtual slides (#558)
This commit is contained in:
@@ -3,75 +3,132 @@ type StatusCacheEntry = {
|
||||
value: boolean
|
||||
}
|
||||
|
||||
type StatusCacheState = {
|
||||
entries: Map<string, StatusCacheEntry>
|
||||
explicitValues: Map<string, boolean>
|
||||
generation: number
|
||||
requests: Map<string, Promise<boolean>>
|
||||
versions: Map<string, number>
|
||||
}
|
||||
|
||||
const STATUS_CACHE_TTL = 3 * 60 * 1000
|
||||
|
||||
const existsStatusCache = new Map<string, StatusCacheEntry>()
|
||||
const existsStatusRequests = new Map<string, Promise<boolean>>()
|
||||
const subscribeStatusCache = new Map<string, StatusCacheEntry>()
|
||||
const subscribeStatusRequests = new Map<string, Promise<boolean>>()
|
||||
const existsStatusState: StatusCacheState = {
|
||||
entries: new Map(),
|
||||
explicitValues: new Map(),
|
||||
generation: 0,
|
||||
requests: new Map(),
|
||||
versions: new Map(),
|
||||
}
|
||||
|
||||
function getCachedValue(cache: Map<string, StatusCacheEntry>, key: string): boolean | undefined {
|
||||
const entry = cache.get(key)
|
||||
const subscribeStatusState: StatusCacheState = {
|
||||
entries: new Map(),
|
||||
explicitValues: new Map(),
|
||||
generation: 0,
|
||||
requests: new Map(),
|
||||
versions: new Map(),
|
||||
}
|
||||
|
||||
function getCachedValue(state: StatusCacheState, key: string): boolean | undefined {
|
||||
const entry = state.entries.get(key)
|
||||
if (!entry) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (entry.expiresAt <= Date.now()) {
|
||||
cache.delete(key)
|
||||
state.entries.delete(key)
|
||||
return undefined
|
||||
}
|
||||
|
||||
return entry.value
|
||||
}
|
||||
|
||||
function setCachedValue(cache: Map<string, StatusCacheEntry>, key: string, value: boolean) {
|
||||
cache.set(key, {
|
||||
function writeCachedValue(state: StatusCacheState, key: string, value: boolean) {
|
||||
state.entries.set(key, {
|
||||
expiresAt: Date.now() + STATUS_CACHE_TTL,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
function setCachedValue(state: StatusCacheState, key: string, value: boolean) {
|
||||
if (state.requests.has(key)) {
|
||||
state.versions.set(key, (state.versions.get(key) ?? 0) + 1)
|
||||
state.explicitValues.set(key, value)
|
||||
}
|
||||
writeCachedValue(state, key, value)
|
||||
}
|
||||
|
||||
async function resolveCachedStatus(
|
||||
cache: Map<string, StatusCacheEntry>,
|
||||
requests: Map<string, Promise<boolean>>,
|
||||
state: StatusCacheState,
|
||||
key: string,
|
||||
loader: () => Promise<boolean>,
|
||||
): Promise<boolean> {
|
||||
const cachedValue = getCachedValue(cache, key)
|
||||
const cachedValue = getCachedValue(state, key)
|
||||
if (cachedValue !== undefined) {
|
||||
return cachedValue
|
||||
}
|
||||
|
||||
const currentRequest = requests.get(key)
|
||||
const currentRequest = state.requests.get(key)
|
||||
if (currentRequest) {
|
||||
return currentRequest
|
||||
}
|
||||
|
||||
const requestGeneration = state.generation
|
||||
const requestVersion = state.versions.get(key) ?? 0
|
||||
const requestRef: { current?: Promise<boolean> } = {}
|
||||
const request = loader()
|
||||
.then(value => {
|
||||
setCachedValue(cache, key, value)
|
||||
// 显式状态写入或会话切换发生后,旧请求只能返回当前状态,不能回写过期结果。
|
||||
if (state.generation !== requestGeneration) {
|
||||
const currentRequest = state.requests.get(key)
|
||||
if (currentRequest && currentRequest !== requestRef.current) {
|
||||
return currentRequest
|
||||
}
|
||||
|
||||
return getCachedValue(state, key) ?? false
|
||||
}
|
||||
|
||||
if ((state.versions.get(key) ?? 0) !== requestVersion) {
|
||||
return state.explicitValues.get(key) ?? value
|
||||
}
|
||||
|
||||
writeCachedValue(state, key, value)
|
||||
return value
|
||||
})
|
||||
.finally(() => {
|
||||
requests.delete(key)
|
||||
if (state.requests.get(key) === requestRef.current) {
|
||||
state.requests.delete(key)
|
||||
state.versions.delete(key)
|
||||
state.explicitValues.delete(key)
|
||||
}
|
||||
})
|
||||
|
||||
requests.set(key, request)
|
||||
requestRef.current = request
|
||||
state.requests.set(key, request)
|
||||
return request
|
||||
}
|
||||
|
||||
export function getCachedMediaExistsStatus(key: string, loader: () => Promise<boolean>) {
|
||||
return resolveCachedStatus(existsStatusCache, existsStatusRequests, key, loader)
|
||||
return resolveCachedStatus(existsStatusState, key, loader)
|
||||
}
|
||||
|
||||
export function setCachedMediaExistsStatus(key: string, value: boolean) {
|
||||
setCachedValue(existsStatusCache, key, value)
|
||||
setCachedValue(existsStatusState, key, value)
|
||||
}
|
||||
|
||||
export function getCachedMediaSubscribeStatus(key: string, loader: () => Promise<boolean>) {
|
||||
return resolveCachedStatus(subscribeStatusCache, subscribeStatusRequests, key, loader)
|
||||
return resolveCachedStatus(subscribeStatusState, key, loader)
|
||||
}
|
||||
|
||||
export function setCachedMediaSubscribeStatus(key: string, value: boolean) {
|
||||
setCachedValue(subscribeStatusCache, key, value)
|
||||
setCachedValue(subscribeStatusState, key, value)
|
||||
}
|
||||
|
||||
/** 清理当前登录会话拥有的订阅状态,并隔离仍在执行的旧会话请求。 */
|
||||
export function clearCachedMediaSubscribeStatuses() {
|
||||
subscribeStatusState.generation += 1
|
||||
subscribeStatusState.entries.clear()
|
||||
subscribeStatusState.explicitValues.clear()
|
||||
subscribeStatusState.requests.clear()
|
||||
subscribeStatusState.versions.clear()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user