fix: Retry sending a file event
This commit is contained in:
parent
c6393c67d6
commit
2f4d455eee
|
|
@ -22,6 +22,7 @@ import 'dart:typed_data';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:matrix/src/utils/file_send_request_credentials.dart';
|
||||||
|
|
||||||
import '../matrix.dart';
|
import '../matrix.dart';
|
||||||
import 'utils/event_localizations.dart';
|
import 'utils/event_localizations.dart';
|
||||||
|
|
@ -136,6 +137,18 @@ class Event extends MatrixEvent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is failed to send and the file is no longer cached, it should be removed!
|
||||||
|
if (!status.isSent &&
|
||||||
|
{
|
||||||
|
MessageTypes.Image,
|
||||||
|
MessageTypes.Video,
|
||||||
|
MessageTypes.Audio,
|
||||||
|
MessageTypes.File,
|
||||||
|
}.contains(messageType) &&
|
||||||
|
!room.sendingFilePlaceholders.containsKey(eventId)) {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, dynamic> getMapFromPayload(dynamic payload) {
|
static Map<String, dynamic> getMapFromPayload(dynamic payload) {
|
||||||
|
|
@ -327,12 +340,34 @@ class Event extends MatrixEvent {
|
||||||
/// Try to send this event again. Only works with events of status -1.
|
/// Try to send this event again. Only works with events of status -1.
|
||||||
Future<String?> sendAgain({String? txid}) async {
|
Future<String?> sendAgain({String? txid}) async {
|
||||||
if (!status.isError) return null;
|
if (!status.isError) return null;
|
||||||
// If this is a failed file sending event, try to fetch the file from the
|
|
||||||
// database first.
|
// Retry sending a file:
|
||||||
final url = getAttachmentUrl();
|
if ({
|
||||||
if (url?.scheme == 'local') {
|
MessageTypes.Image,
|
||||||
final file = await downloadAndDecryptAttachment();
|
MessageTypes.Video,
|
||||||
return await room.sendFileEvent(file, extraContent: content);
|
MessageTypes.Audio,
|
||||||
|
MessageTypes.File,
|
||||||
|
}.contains(messageType)) {
|
||||||
|
final file = room.sendingFilePlaceholders[eventId];
|
||||||
|
if (file == null) {
|
||||||
|
await remove();
|
||||||
|
throw Exception('Can not try to send again. File is no longer cached.');
|
||||||
|
}
|
||||||
|
final thumbnail = room.sendingFileThumbnails[eventId];
|
||||||
|
final credentials = FileSendRequestCredentials.fromJson(unsigned ?? {});
|
||||||
|
final inReplyTo = credentials.inReplyTo == null
|
||||||
|
? null
|
||||||
|
: await room.getEventById(credentials.inReplyTo!);
|
||||||
|
txid ??= unsigned?.tryGet<String>('transaction_id');
|
||||||
|
return await room.sendFileEvent(
|
||||||
|
file,
|
||||||
|
txid: txid,
|
||||||
|
thumbnail: thumbnail,
|
||||||
|
inReplyTo: inReplyTo,
|
||||||
|
editEventId: credentials.editEventId,
|
||||||
|
shrinkImageMaxDimension: credentials.shrinkImageMaxDimension,
|
||||||
|
extraContent: credentials.extraContent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we do not remove the event here. It will automatically be updated
|
// we do not remove the event here. It will automatically be updated
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import 'dart:typed_data';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:html_unescape/html_unescape.dart';
|
import 'package:html_unescape/html_unescape.dart';
|
||||||
import 'package:matrix/src/utils/crypto/crypto.dart';
|
import 'package:matrix/src/utils/crypto/crypto.dart';
|
||||||
|
import 'package:matrix/src/utils/file_send_request_credentials.dart';
|
||||||
import 'package:matrix/src/utils/space_child.dart';
|
import 'package:matrix/src/utils/space_child.dart';
|
||||||
import 'package:matrix/widget.dart';
|
import 'package:matrix/widget.dart';
|
||||||
|
|
||||||
|
|
@ -683,6 +684,7 @@ class Room {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, MatrixFile> sendingFilePlaceholders = {};
|
final Map<String, MatrixFile> sendingFilePlaceholders = {};
|
||||||
|
final Map<String, MatrixImageFile> sendingFileThumbnails = {};
|
||||||
|
|
||||||
/// Sends a [file] to this room after uploading it. Returns the mxc uri of
|
/// 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 uploaded file. If [waitUntilSent] is true, the future will wait until
|
||||||
|
|
@ -706,6 +708,9 @@ class Room {
|
||||||
}) async {
|
}) async {
|
||||||
txid ??= client.generateUniqueTransactionId();
|
txid ??= client.generateUniqueTransactionId();
|
||||||
sendingFilePlaceholders[txid] = file;
|
sendingFilePlaceholders[txid] = file;
|
||||||
|
if (thumbnail != null) {
|
||||||
|
sendingFileThumbnails[txid] = thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a fake Event object as a placeholder for the uploading file:
|
// Create a fake Event object as a placeholder for the uploading file:
|
||||||
final syncUpdate = SyncUpdate(
|
final syncUpdate = SyncUpdate(
|
||||||
|
|
@ -728,6 +733,12 @@ class Room {
|
||||||
unsigned: {
|
unsigned: {
|
||||||
messageSendingStatusKey: EventStatus.sending.intValue,
|
messageSendingStatusKey: EventStatus.sending.intValue,
|
||||||
'transaction_id': txid,
|
'transaction_id': txid,
|
||||||
|
...FileSendRequestCredentials(
|
||||||
|
inReplyTo: inReplyTo?.eventId,
|
||||||
|
editEventId: editEventId,
|
||||||
|
shrinkImageMaxDimension: shrinkImageMaxDimension,
|
||||||
|
extraContent: extraContent,
|
||||||
|
).toJson(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -805,14 +816,12 @@ class Room {
|
||||||
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
||||||
await _handleFakeSync(syncUpdate);
|
await _handleFakeSync(syncUpdate);
|
||||||
sendingFilePlaceholders.remove(txid);
|
|
||||||
rethrow;
|
rethrow;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
if (DateTime.now().isAfter(timeoutDate)) {
|
if (DateTime.now().isAfter(timeoutDate)) {
|
||||||
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
||||||
await _handleFakeSync(syncUpdate);
|
await _handleFakeSync(syncUpdate);
|
||||||
sendingFilePlaceholders.remove(txid);
|
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
Logs().v('Send File into room failed. Try again...');
|
Logs().v('Send File into room failed. Try again...');
|
||||||
|
|
@ -875,6 +884,7 @@ class Room {
|
||||||
editEventId: editEventId,
|
editEventId: editEventId,
|
||||||
);
|
);
|
||||||
sendingFilePlaceholders.remove(txid);
|
sendingFilePlaceholders.remove(txid);
|
||||||
|
sendingFileThumbnails.remove(txid);
|
||||||
return eventId;
|
return eventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Famedly Matrix SDK
|
||||||
|
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FileSendRequestCredentials {
|
||||||
|
final String? inReplyTo;
|
||||||
|
final String? editEventId;
|
||||||
|
final int? shrinkImageMaxDimension;
|
||||||
|
final Map<String, dynamic>? extraContent;
|
||||||
|
|
||||||
|
const FileSendRequestCredentials({
|
||||||
|
this.inReplyTo,
|
||||||
|
this.editEventId,
|
||||||
|
this.shrinkImageMaxDimension,
|
||||||
|
this.extraContent,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory FileSendRequestCredentials.fromJson(Map<String, dynamic> json) =>
|
||||||
|
FileSendRequestCredentials(
|
||||||
|
inReplyTo: json['in_reply_to'],
|
||||||
|
editEventId: json['edit_event_id'],
|
||||||
|
shrinkImageMaxDimension: json['shrink_image_max_dimension'],
|
||||||
|
extraContent: json['extra_content'],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
if (inReplyTo != null) 'in_reply_to': inReplyTo,
|
||||||
|
if (editEventId != null) 'edit_event_id': editEventId,
|
||||||
|
if (shrinkImageMaxDimension != null)
|
||||||
|
'shrink_image_max_dimension': shrinkImageMaxDimension,
|
||||||
|
if (extraContent != null) 'extra_content': extraContent,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue