cacheMetaDataByClassId method
Future<void>
cacheMetaDataByClassId(
- String classId,
- String token,
- CacheMetadataListener listener, {
- bool force = false,
- PlayBackEnvEnum env = PlayBackEnvEnum.production,
拉取回放元数据并以 classId.json 保存到本地
Implementation
Future<void> cacheMetaDataByClassId(
String classId,
String token,
CacheMetadataListener listener, {
bool force = false,
PlayBackEnvEnum env = PlayBackEnvEnum.production,
}) async {
classId = _trimClassId(classId);
if (classId.isEmpty) {
listener.onError(classId, -1, 'classId 为空');
return;
}
cacheMetadataListeners[classId] = listener;
// 在任何 await 之前同步恢复缓存进度,避免 HTTP GET 等待期间 UI 停留在 0
_restoreCachedProgress(classId);
cacheMetadataListeners[classId]?.onCacheStarted(classId);
// 判断是否正在缓存中,如果缓存中,则返回
final status = await getCachedMetaDataStatus(classId);
if (status == CacheStatusEnum.caching && !force) {
cacheMetadataListeners[classId]?.onError(classId, 1000, '正在缓存中,请勿重复缓存');
return;
}
if (status == CacheStatusEnum.cachedSuccess && !force) {
final localPaths = await _localPathsPayloadForCachedClass(classId);
cacheMetadataListeners[classId]?.onCacheSuccess(classId, localPaths);
return;
}
// 全新下载(从未缓存过)时清除进度下界,使进度从 0 正确开始,不沿用旧进度缓存
if (status == CacheStatusEnum.notCached) {
_cachedProgressCurrentBytes.remove(classId);
_cachedProgressTotalBytes.remove(classId);
}
final baseUrl =
env == PlayBackEnvEnum.production
? TCICConst.playBackApiBaseUrl
: TCICConst.playBackApiBaseUrlTest;
// JWT 中含 + / = 等字符,必须编码后放入 query,否则会被解析错误导致服务端收到错误 token 返回 401
final url =
'$baseUrl/metadata/$classId?token=${Uri.encodeComponent(token)}';
try {
final response = await _dio.get(url);
final data = response.data;
if (data['error_code'] != 0) {
cacheMetadataListeners[classId]?.onCacheFailed(
classId,
data['error_code'],
data['error_message'],
);
return;
}
final cacheDir = await _ensureCacheDir();
final file = File(p.join(cacheDir.path, '${_safeId(classId)}.json'));
final dataData = data['data'] as Map<String, dynamic>;
await file.writeAsString(
jsonEncode({
'document_pages': List<Map<String, dynamic>>.from(
dataData['document_pages'] ?? [],
),
'im_messages': List<Map<String, dynamic>>.from(
dataData['im_messages'] ?? [],
),
'screen_shares': List<Map<String, dynamic>>.from(
dataData['screen_shares'] ?? [],
),
'video_url': dataData['video_url'] ?? '',
'whiteboard_url': dataData['whiteboard_url'] ?? '',
'class_name': dataData['class_name'] ?? '',
'teacher_name': dataData['teacher_name'] ?? '',
'video_duration': dataData['video_duration'],
'video_start_time': dataData['video_start_time'],
'video_start_relative': dataData['video_start_relative'],
'whiteboard_duration': dataData['whiteboard_duration'],
'whiteboard_start_time': dataData['whiteboard_start_time'],
'whiteboard_start_relative': dataData['whiteboard_start_relative'],
}),
);
_pausedClassIds.remove(classId);
_downloadingClassIds.add(classId);
downloadMetaData(classId, token);
} on DioException catch (e, st) {
final code = e.response?.statusCode ?? -1;
final full = _formatPlaybackCacheError(e, st);
TCICLog.error(
'[PlayBackCache] GET metadata failed classId=$classId code=$code\n$full',
actionModule: ActionModule.playBackController.name,
actionName: 'cacheMetaDataByClassId',
);
cacheMetadataListeners[classId]?.onError(classId, code, full);
} catch (e, st) {
final full = _formatPlaybackCacheError(e, st);
TCICLog.error(
'[PlayBackCache] metadata unexpected classId=$classId\n$full',
actionModule: ActionModule.playBackController.name,
actionName: 'cacheMetaDataByClassId',
);
cacheMetadataListeners[classId]?.onError(classId, -1, full);
}
}