cacheMetaDataByClassId method

Future<void> cacheMetaDataByClassId(
  1. String classId,
  2. String token,
  3. CacheMetadataListener listener, {
  4. bool force = false,
  5. 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);
  }
}