MarketCache
MarketCache
Section titled “MarketCache”MarketCache 管理四种市场数据的缓存,每种有不同 TTL 和存储位置。数据层只查缓存和存缓存,TTL 逻辑全在这里。
文件:lib/core/market/market_cache.dart
TTL 常量
Section titled “TTL 常量”const Duration kMarketDirTtl = Duration(minutes: 5); // 目录列表const Duration kMarketMetaTtl = Duration(hours: 1); // .meta.jsonconst Duration kMarketImageTtl = Duration(days: 7); // 预览图// 插件包:永久(无 TTL)class MarketCache { final Directory diskRoot;
MarketCache(this.diskRoot);}diskRoot 是磁盘缓存根目录。客户端用 <appSupportDir>/moodpet/market-cache/。构造时自动创建目录。
MarketPluginRef
Section titled “MarketPluginRef”class MarketPluginRef { final String id; final MarketDir dir;}目录列表缓存的元素——只有插件 id 和所在目录,足够用来后续拉完整元数据。
目录列表(内存,5 分钟)
Section titled “目录列表(内存,5 分钟)”getDirectory(MarketDir dir) → List?
Section titled “getDirectory(MarketDir dir) → List?”final cached = cache.getDirectory(MarketDir.friend);if (cached != null) { // 5 分钟内的缓存,直接用 return cached;}// 未命中,走网络...putDirectory(MarketDir dir, List entries)
Section titled “putDirectory(MarketDir dir, List entries)”final refs = await fetchDirectoryListing(MarketDir.friend);cache.putDirectory(MarketDir.friend, refs);invalidateDirectory(MarketDir dir)
Section titled “invalidateDirectory(MarketDir dir)”删一个目录的缓存(下拉刷新用):
cache.invalidateDirectory(MarketDir.friend);invalidateAllDirectories()
Section titled “invalidateAllDirectories()”删所有目录缓存:
cache.invalidateAllDirectories();元数据(内存,1 小时)
Section titled “元数据(内存,1 小时)”存原始 JSON Map<String, Object?>,避免和 MarketPlugin 模型产生循环依赖。MarketRepository 在读时解析。
getMeta(MarketDir dir, String id) → Map<String, Object?>?
Section titled “getMeta(MarketDir dir, String id) → Map<String, Object?>?”final cached = cache.getMeta(MarketDir.friend, 'moodpet.friend.default_smiley');if (cached != null) { return MarketPlugin.fromJson(cached, dir: MarketDir.friend);}putMeta(MarketDir dir, String id, Map<String, Object?> json)
Section titled “putMeta(MarketDir dir, String id, Map<String, Object?> json)”final json = await fetchMetaJson(dir, id);cache.putMeta(dir, id, json);invalidateMeta(MarketDir dir, String id)
Section titled “invalidateMeta(MarketDir dir, String id)”cache.invalidateMeta(MarketDir.friend, 'moodpet.friend.default_smiley');预览图(磁盘,7 天)
Section titled “预览图(磁盘,7 天)”存为 <diskRoot>/image/<dir>/<id>.png。新鲜度看文件 mtime。
getImage(MarketDir dir, String id) → File?
Section titled “getImage(MarketDir dir, String id) → File?”final file = cache.getImage(MarketDir.friend, 'moodpet.friend.default_smiley');if (file != null) { // 文件存在且 < 7 天,直接用 return Image.file(file);}putImage(MarketDir dir, String id, List bytes) → File
Section titled “putImage(MarketDir dir, String id, List bytes) → File”final bytes = await downloadImage(dir, id);final file = cache.putImage(dir, id, bytes);return Image.file(file);插件包(磁盘,永久)
Section titled “插件包(磁盘,永久)”存为 <diskRoot>/package/<dir>/<id>.mood*。无 TTL——装一次就永久缓存,卸载时才删。
getPackage(MarketDir dir, String id) → File?
Section titled “getPackage(MarketDir dir, String id) → File?”final file = cache.getPackage(MarketDir.friend, 'moodpet.friend.default_smiley');if (file != null) { // 已下载过,直接用 return file;}putPackage(MarketDir dir, String id, List bytes) → File
Section titled “putPackage(MarketDir dir, String id, List bytes) → File”final bytes = await downloadPackage(dir, id);final file = cache.putPackage(dir, id, bytes);removePackage(MarketDir dir, String id)
Section titled “removePackage(MarketDir dir, String id)”卸载插件时清缓存:
cache.removePackage(MarketDir.friend, 'moodpet.friend.default_smiley');<appSupportDir>/moodpet/market-cache/├── image/│ ├── friend/│ │ └── moodpet.friend.default_smiley.png│ ├── application/│ └── packs/└── package/ ├── friend/ │ └── moodpet.friend.default_smiley.moodfriend ├── application/ └── packs/完整用法示例
Section titled “完整用法示例”final cache = MarketCache(rootDir);
// 目录列表var refs = cache.getDirectory(MarketDir.friend);if (refs == null) { refs = await fetchFromGithub(MarketDir.friend); cache.putDirectory(MarketDir.friend, refs);}
// 元数据for (final ref in refs) { var meta = cache.getMeta(ref.dir, ref.id); if (meta == null) { meta = await fetchMetaFromGithub(ref.dir, ref.id); cache.putMeta(ref.dir, ref.id, meta); } yield MarketPlugin.fromJson(meta, dir: ref.dir);}