Skip to content

Commit

Permalink
TW-1578: Enable cancel token when download attachments on web
Browse files Browse the repository at this point in the history
  • Loading branch information
nqhhdev authored and hoangdat committed Apr 8, 2024
1 parent 5429082 commit 93deff6
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 195 deletions.
2 changes: 1 addition & 1 deletion lib/data/network/media/media_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class MediaAPI {
);
}

Future<Uint8List> downloadAttachmentWeb({
Future<Uint8List> downloadFileWeb({
required Uri uri,
CancelToken? cancelToken,
ProgressCallback? onReceiveProgress,
Expand Down
10 changes: 10 additions & 0 deletions lib/utils/exception/download_file_web_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class DownloadFileWebException implements Exception {
final dynamic error;

DownloadFileWebException({
this.error,
});

@override
String toString() => error;
}
6 changes: 2 additions & 4 deletions lib/utils/manager/download_manager/download_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:fluffychat/utils/manager/download_manager/download_file_info.dar
import 'package:fluffychat/utils/manager/download_manager/download_file_state.dart';
import 'package:fluffychat/utils/manager/download_manager/downloading_worker_queue.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/download_file_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/download_file_web_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/task_queue/task.dart';
import 'package:matrix/matrix.dart';
Expand Down Expand Up @@ -141,7 +142,6 @@ class DownloadManager {
_addTaskToWorkerQueueWeb(
event: event,
streamController: streamController,
getThumbnail: getThumbnail,
cancelToken: cancelToken,
);
return;
Expand Down Expand Up @@ -188,16 +188,14 @@ class DownloadManager {
void _addTaskToWorkerQueueWeb({
required Event event,
required StreamController<Either<Failure, Success>> streamController,
getThumbnail = false,
required CancelToken cancelToken,
}) {
workingQueue.addTask(
Task(
id: event.eventId,
runnable: () async {
try {
await event.downloadAttachmentWeb(
getThumbnail: getThumbnail,
await event.downloadFileWeb(
downloadStreamController: streamController,
cancelToken: cancelToken,
);
Expand Down
188 changes: 0 additions & 188 deletions lib/utils/matrix_sdk_extensions/download_file_extension.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
Expand Down Expand Up @@ -287,193 +286,6 @@ extension DownloadFileExtension on Event {
);
}

Future<MatrixFile?> downloadAttachmentWeb({
getThumbnail = false,
required StreamController<Either<Failure, Success>>
downloadStreamController,
CancelToken? cancelToken,
}) async {
if (!canContainAttachment()) {
throw (
"downloadAttachmentWeb: This event has the type '$type' and so it can't contain an attachment.",
);
}

if (isSending()) {
final localFile = room.sendingFilePlaceholders[eventId];
if (localFile != null) return localFile;
}

final mxcUrl = getAttachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
if (mxcUrl == null) {
throw "downloadAttachmentWeb: This event hasn't any attachment or thumbnail.";
}

final isFileEncrypted =
getThumbnail ? isThumbnailEncrypted : isAttachmentEncrypted;
if (isEncryptionDisabled(isFileEncrypted)) {
throw (
'downloadAttachmentWeb: Encryption is not enabled in your Client.',
);
}

final storeable = isFileStoreable(getThumbnail: getThumbnail);

Uint8List? uint8list;

if (storeable) {
uint8list = await room.client.database?.getFile(mxcUrl);
}

if (uint8list != null) {
return MatrixFile(
bytes: await _decryptAttachmentWeb(uint8list: uint8list),
name: body,
);
}

return await _handleDownloadAttachmentWeb(
mxcUrl: mxcUrl,
downloadStreamController: downloadStreamController,
getThumbnail: getThumbnail,
cancelToken: cancelToken,
storeable: storeable,
);
}

Future<MatrixFile?> _handleDownloadAttachmentWeb({
required Uri mxcUrl,
required StreamController<Either<Failure, Success>>
downloadStreamController,
bool getThumbnail = false,
CancelToken? cancelToken,
bool storeable = true,
}) async {
try {
final database = room.client.database;
final mediaAPI = getIt<MediaAPI>();
final downloadLink = mxcUrl.getDownloadLink(room.client);
final uint8List = await mediaAPI.downloadAttachmentWeb(
uri: downloadLink,
onReceiveProgress: (receive, total) {
downloadStreamController.add(
Right(
DownloadingFileState(
receive: receive,
total: total,
),
),
);
},
cancelToken: cancelToken,
);
if (database != null &&
storeable &&
uint8List.lengthInBytes < database.maxFileSize) {
await database.storeFile(
mxcUrl,
uint8List,
DateTime.now().millisecondsSinceEpoch,
);
}

await _handleDownloadAttachmentWebSuccess(
uint8List,
downloadStreamController,
);
return MatrixFile(name: body);
} catch (e) {
if (e is CancelRequestException) {
Logs().i("_handleDownloadAttachmentWeb: user cancel the download");
}
Logs().e("_handleDownloadAttachmentWeb: $e");
}
return null;
}

Future<void> _handleDownloadAttachmentWebSuccess(
Uint8List uint8list,
StreamController<Either<Failure, Success>> streamController,
) async {
if (isAttachmentEncrypted) {
await _handleDecryptedAttachmentWeb(
streamController: streamController,
uint8list: uint8list,
);
} else {
streamController.add(
Right(
DownloadMatrixFileSuccessState(
matrixFile: MatrixFile(bytes: uint8list, name: body),
),
),
);
}
return;
}

Future<void> _handleDecryptedAttachmentWeb({
required StreamController<Either<Failure, Success>> streamController,
required Uint8List uint8list,
bool getThumbnail = false,
}) async {
streamController.add(
const Right(
DecryptingFileState(),
),
);
try {
final decryptedFile = await _decryptAttachmentWeb(
uint8list: uint8list,
getThumbnail: getThumbnail,
);
if (decryptedFile == null) {
throw Exception(
'_handleDownloadAttachmentWeb:: decryptedFile is null',
);
}
streamController.add(
Right(
DownloadMatrixFileSuccessState(
matrixFile: MatrixFile(bytes: decryptedFile, name: body),
),
),
);
} catch (e) {
Logs().e(
'_handleDownloadAttachmentWeb:: $e',
);
streamController.add(
Left(
DownloadFileFailureState(exception: e),
),
);
}
}

Future<Uint8List?> _decryptAttachmentWeb({
required Uint8List uint8list,
bool getThumbnail = false,
}) async {
final fileMap = getThumbnail ? infoMap['thumbnail_file'] : content['file'];
if (!fileMap['key']['key_ops'].contains('decrypt')) {
throw ("Missing 'decrypt' in 'key_ops'.");
}
final encryptedFile = EncryptedFile(
data: uint8list,
iv: fileMap['iv'],
k: fileMap['key']['k'],
sha256: fileMap['hashes']['sha256'],
);
final decryptAttachment =
await room.client.nativeImplementations.decryptFile(encryptedFile);
if (decryptAttachment == null) {
throw ('Unable to decrypt file');
}

return decryptAttachment;
}

Future<FileInfo?> getMediaFileInfo({
getThumbnail = false,
ProgressCallback? progressCallback,
Expand Down
Loading

0 comments on commit 93deff6

Please sign in to comment.