Skip to content

MarketCache

MarketCache 管理四种市场数据的缓存,每种有不同 TTL 和存储位置。数据层只查缓存和存缓存,TTL 逻辑全在这里。

文件:lib/core/market/market_cache.dart

const Duration kMarketDirTtl = Duration(minutes: 5); // 目录列表
const Duration kMarketMetaTtl = Duration(hours: 1); // .meta.json
const Duration kMarketImageTtl = Duration(days: 7); // 预览图
// 插件包:永久(无 TTL)
class MarketCache {
final Directory diskRoot;
MarketCache(this.diskRoot);
}

diskRoot 是磁盘缓存根目录。客户端用 <appSupportDir>/moodpet/market-cache/。构造时自动创建目录。

class MarketPluginRef {
final String id;
final MarketDir dir;
}

目录列表缓存的元素——只有插件 id 和所在目录,足够用来后续拉完整元数据。

final cached = cache.getDirectory(MarketDir.friend);
if (cached != null) {
// 5 分钟内的缓存,直接用
return cached;
}
// 未命中,走网络...
final refs = await fetchDirectoryListing(MarketDir.friend);
cache.putDirectory(MarketDir.friend, refs);

删一个目录的缓存(下拉刷新用):

cache.invalidateDirectory(MarketDir.friend);

删所有目录缓存:

cache.invalidateAllDirectories();

存原始 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);
cache.invalidateMeta(MarketDir.friend, 'moodpet.friend.default_smiley');

存为 <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);

存为 <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);

卸载插件时清缓存:

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/
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);
}