Skip to content

Commit

Permalink
feat: Store sending attachment in temporary file storage
Browse files Browse the repository at this point in the history
This could make retrying to send
files more easy as the file is
stored in the file storage.

This just replaces the current approach to store
the file in the memory instead so they are gone
on the next session.
For this we need a deleteFile() method for the
database.
  • Loading branch information
krille-chan committed Oct 21, 2024
1 parent b6945e7 commit f89f01d
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 12 deletions.
2 changes: 2 additions & 0 deletions lib/src/database/database_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ abstract class DatabaseApi {

Future storeFile(Uri mxcUri, Uint8List bytes, int time);

Future<bool> deleteFile(Uri mxcUri);

Future storeSyncFilterId(
String syncFilterId,
);
Expand Down
14 changes: 14 additions & 0 deletions lib/src/database/database_file_storage_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ mixin DatabaseFileStorage {
return null;
}

Future<bool> deleteFile(Uri mxcUri) async {
final fileStorageLocation = this.fileStorageLocation;
if (!supportsFileStoring || fileStorageLocation == null) return false;

final dir = Directory.fromUri(fileStorageLocation);

final file = File('${dir.path}/${mxcUri.toString().split('/').last}');

if (await file.exists() == false) return false;

await file.delete();
return true;
}

Future<void> deleteOldFiles(int savedAt) async {
final dirUri = fileStorageLocation;
final deleteFilesAfterDuration = this.deleteFilesAfterDuration;
Expand Down
2 changes: 2 additions & 0 deletions lib/src/database/database_file_storage_stub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ mixin DatabaseFileStorage {
Future<void> deleteOldFiles(int savedAt) async {
return;
}

Future<bool> deleteFile(Uri mxcUri) async => false;
}
5 changes: 5 additions & 0 deletions lib/src/database/hive_collections_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,11 @@ class HiveCollectionsDatabase extends DatabaseApi {
return null;
}

@override
Future<bool> deleteFile(Uri mxcUri) async {
return false;
}

@override
Future<StoredInboundGroupSession?> getInboundGroupSession(
String roomId,
Expand Down
5 changes: 5 additions & 0 deletions lib/src/database/hive_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,11 @@ class FamedlySdkHiveDatabase extends DatabaseApi with ZoneTransactionMixin {
return null;
}

@override
Future<bool> deleteFile(Uri mxcUri) async {
return false;
}

@override
Future<StoredInboundGroupSession?> getInboundGroupSession(
String roomId,
Expand Down
31 changes: 28 additions & 3 deletions lib/src/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,29 @@ class Event extends MatrixEvent {
MessageTypes.Audio,
MessageTypes.File,
}.contains(messageType)) {
final file = room.sendingFilePlaceholders[eventId];
final bytes = await room.client.database?.getFile(
Uri.parse('com.famedly.sendingAttachment://file/$eventId'),
);
final file = bytes == null
? null
: MatrixImageFile(
bytes: bytes,
name: content.tryGet<String>('filename') ?? 'image',
);
if (file == null) {
await cancelSend();
throw Exception('Can not try to send again. File is no longer cached.');
}
final thumbnail = room.sendingFileThumbnails[eventId];
final thumbnailBytes = await room.client.database?.getFile(
Uri.parse('com.famedly.sendingAttachment://thumbnail/$txid'),
);
final thumbnail = thumbnailBytes == null
? null
: MatrixImageFile(
bytes: thumbnailBytes,
name:
'thumbnail_${content.tryGet<String>('filename') ?? 'image'}',
);
final credentials = FileSendRequestCredentials.fromJson(unsigned ?? {});
final inReplyTo = credentials.inReplyTo == null
? null
Expand Down Expand Up @@ -688,7 +705,15 @@ class Event extends MatrixEvent {
throw ("This event has the type '$type' and so it can't contain an attachment.");
}
if (status.isSending) {
final localFile = room.sendingFilePlaceholders[eventId];
final bytes = await room.client.database?.getFile(
Uri.parse('com.famedly.sendingAttachment://file/$eventId'),
);
final localFile = bytes == null
? null
: MatrixImageFile(
bytes: bytes,
name: content.tryGet<String>('filename') ?? 'image',
);
if (localFile != null) return localFile;
}
final database = room.client.database;
Expand Down
42 changes: 33 additions & 9 deletions lib/src/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -665,9 +665,6 @@ class Room {
return sendEvent(event, txid: txid);
}

final Map<String, MatrixFile> sendingFilePlaceholders = {};
final Map<String, MatrixImageFile> sendingFileThumbnails = {};

/// Sends a [file] to this room after uploading it. Returns the mxc uri of
/// the uploaded file. If [waitUntilSent] is true, the future will wait until
/// the message event has received the server. Otherwise the future will only
Expand All @@ -691,10 +688,6 @@ class Room {
String? threadLastEventId,
}) async {
txid ??= client.generateUniqueTransactionId();
sendingFilePlaceholders[txid] = file;
if (thumbnail != null) {
sendingFileThumbnails[txid] = thumbnail;
}

// Create a fake Event object as a placeholder for the uploading file:
final syncUpdate = SyncUpdate(
Expand Down Expand Up @@ -731,6 +724,22 @@ class Room {
},
),
);
await _handleFakeSync(syncUpdate);

if (client.database?.supportsFileStoring == true) {
await client.database?.storeFile(
Uri.parse('com.famedly.sendingAttachment://file/$txid'),
file.bytes,
DateTime.now().millisecondsSinceEpoch,
);
if (thumbnail != null) {
await client.database?.storeFile(
Uri.parse('com.famedly.sendingAttachment://thumbnail/$txid'),
file.bytes,
DateTime.now().millisecondsSinceEpoch,
);
}
}

MatrixFile uploadFile = file; // ignore: omit_local_variable_types
// computing the thumbnail in case we can
Expand Down Expand Up @@ -816,12 +825,22 @@ class Room {
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
await _handleFakeSync(syncUpdate);

if (client.database?.supportsFileStoring != true) {
final sendEvent = await getEventById(txid);
await sendEvent?.cancelSend();
}
rethrow;
} catch (_) {
if (DateTime.now().isAfter(timeoutDate)) {
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
await _handleFakeSync(syncUpdate);

if (client.database?.supportsFileStoring != true) {
final sendEvent = await getEventById(txid);
await sendEvent?.cancelSend();
}
rethrow;
}
Logs().v('Send File into room failed. Try again...');
Expand Down Expand Up @@ -885,8 +904,13 @@ class Room {
threadRootEventId: threadRootEventId,
threadLastEventId: threadLastEventId,
);
sendingFilePlaceholders.remove(txid);
sendingFileThumbnails.remove(txid);
await client.database?.deleteFile(
Uri.parse('com.famedly.sendingAttachment://file/$txid'),
);
await client.database?.deleteFile(
Uri.parse('com.famedly.sendingAttachment://thumbnail/$txid'),
);

return eventId;
}

Expand Down

0 comments on commit f89f01d

Please sign in to comment.