| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- import * as fs from 'expo-file-system/legacy';
- import { createMMKV } from 'react-native-mmkv';
- import type { MMKV } from 'react-native-mmkv';
- const TTL_KEY = '$__$t_';
- const LAST_CLEAR_KEY = '$__last_clear_time$_';
- const CLEAR_INTERVAL = 86400 * 3 * 1000; // 3 天扫一次过期项
- const CLEAR_TICK = 60 * 15 * 1000; // 每 15 分钟检查一次
- function fixPath(path: string) {
- if (path.startsWith('file:///')) return path.substring(7);
- if (path.startsWith('file:/')) return path.replace(/^file:\//, '/');
- return path;
- }
- export type KVDB = MMKV & {
- getObject: <T = any>(key: string) => T | undefined;
- setObject: (key: string, value: any, ttlSeconds: number) => void;
- };
- function attachObjectMethods(mmkv: MMKV): KVDB {
- const db = mmkv as KVDB;
- db.setObject = (key, value, ttlSeconds) => {
- db.set(
- key,
- JSON.stringify({ [TTL_KEY]: Date.now() + ttlSeconds * 1000, v: value })
- );
- };
- db.getObject = <T>(key: string) => {
- const raw = db.getString(key);
- if (!raw) return undefined;
- try {
- const obj = JSON.parse(raw) as { [TTL_KEY]: number; v: T };
- if (Date.now() > obj[TTL_KEY]) {
- db.remove(key);
- return undefined;
- }
- return obj.v;
- } catch {
- db.remove(key);
- return undefined;
- }
- };
- return db;
- }
- function makeStore(id: string) {
- let instance: KVDB | null = null;
- return () => {
- if (!instance) {
- instance = attachObjectMethods(
- createMMKV({ id, path: fixPath(fs.cacheDirectory ?? '') })
- );
- }
- return instance;
- };
- }
- export const getGlobalStorage = makeStore('global');
- export const getCaches = makeStore('caches');
- export const getApiCache = makeStore('api_cache');
- // 启动后定期扫一遍缓存,清理过期项
- setTimeout(() => {
- const tick = () => {
- const global = getGlobalStorage();
- const last = parseInt(global.getString(LAST_CLEAR_KEY) || '0', 10);
- const now = Date.now();
- if (now - last < CLEAR_INTERVAL) return;
- for (const db of [getCaches(), getApiCache(), global]) {
- for (const key of db.getAllKeys()) db.getObject(key);
- }
- global.set(LAST_CLEAR_KEY, now);
- };
- tick();
- setInterval(tick, CLEAR_TICK);
- }, 3000);
|