service: Allow sending multiple files

This commit is contained in:
PapaTutuWawa 2022-07-24 14:38:13 +02:00
parent 0acd812a60
commit 660c56e27a
4 changed files with 93 additions and 69 deletions

View File

@ -220,13 +220,13 @@ files:
quotedMessage: quotedMessage:
type: Message? type: Message?
deserialise: true deserialise: true
- name: SendFileCommand - name: SendFilesCommand
extends: BackgroundCommand extends: BackgroundCommand
implements: implements:
- JsonImplementation - JsonImplementation
attributes: attributes:
jid: String jid: String
path: String paths: List<String>
- name: BlockJidCommand - name: BlockJidCommand
extends: BackgroundCommand extends: BackgroundCommand
implements: implements:

View File

@ -49,7 +49,7 @@ void setupBackgroundEventHandler() {
EventTypeMatcher<SendChatStateCommand>(performSendChatState), EventTypeMatcher<SendChatStateCommand>(performSendChatState),
EventTypeMatcher<GetFeaturesCommand>(performGetFeatures), EventTypeMatcher<GetFeaturesCommand>(performGetFeatures),
EventTypeMatcher<SignOutCommand>(performSignOut), EventTypeMatcher<SignOutCommand>(performSignOut),
EventTypeMatcher<SendFileCommand>(performSendFile), EventTypeMatcher<SendFilesCommand>(performSendFiles),
]); ]);
GetIt.I.registerSingleton<EventHandler>(handler); GetIt.I.registerSingleton<EventHandler>(handler);
@ -409,6 +409,6 @@ Future<void> performSignOut(SignOutCommand command, { dynamic extra }) async {
); );
} }
Future<void> performSendFile(SendFileCommand command, { dynamic extra }) async { Future<void> performSendFiles(SendFilesCommand command, { dynamic extra }) async {
await GetIt.I.get<XmppService>().sendFile(command.path, command.jid); await GetIt.I.get<XmppService>().sendFiles(command.paths, command.jid);
} }

View File

@ -321,69 +321,90 @@ class XmppService {
return GetIt.I.get<XmppConnection>().connectAwaitable(lastResource: lastResource); return GetIt.I.get<XmppConnection>().connectAwaitable(lastResource: lastResource);
} }
Future<void> sendFile(String path, String recipient) async { Future<void> sendFiles(List<String> paths, String recipient) async {
// Create a new message // Create a new message
final ms = GetIt.I.get<MessageService>(); final ms = GetIt.I.get<MessageService>();
final cs = GetIt.I.get<ConversationService>(); final cs = GetIt.I.get<ConversationService>();
final us = GetIt.I.get<UploadService>(); final us = GetIt.I.get<UploadService>();
final conn = GetIt.I.get<XmppConnection>(); final conn = GetIt.I.get<XmppConnection>();
final httpManager = conn.getManagerById<HttpFileUploadManager>(httpFileUploadManager)!; final httpManager = conn.getManagerById<HttpFileUploadManager>(httpFileUploadManager)!;
final sid = conn.generateId();
final originId = conn.generateId();
_log.finest('Requesting upload slot'); // Path -> Message
final stat = File(path).statSync(); final messages = <String, Message>{};
final result = await httpManager.requestUploadSlot(pathlib.basename(path), stat.size);
if (result.isError()) {
_log.severe('Failed to request slot');
// TODO(PapaTutuWawa): Do not let it end here
return;
}
final slot = result.getValue(); // Create the messages
final fileMime = lookupMimeType(path); for (final path in paths) {
var msg = await ms.addMessageFromData( final msg = await ms.addMessageFromData(
'', '',
DateTime.now().millisecondsSinceEpoch, DateTime.now().millisecondsSinceEpoch,
conn.getConnectionSettings().jid.toString(), conn.getConnectionSettings().jid.toString(),
recipient, recipient,
true, true,
true, true,
sid, conn.generateId(),
srcUrl: slot.getUrl, // TODO(Unknown): Maybe don't have the UI depend on srcUrl if we sent it.
srcUrl: 'https://server.example',
mediaUrl: path, mediaUrl: path,
mediaType: fileMime, mediaType: lookupMimeType(path),
originId: originId, originId: conn.generateId(),
); );
// Notify the UI messages[path] = msg;
msg = msg.copyWith(isUploading: true); sendEvent(MessageAddedEvent(message: msg.copyWith(isUploading: true)));
sendEvent(MessageAddedEvent(message: msg)); }
final uploadResult = await us.uploadFile(path, slot.putUrl, slot.headers, msg.id); // Requesting Upload slots and uploading
msg = msg.copyWith(isUploading: false);
sendEvent(MessageUpdatedEvent(message: msg)); final conversationId = (await cs.getConversationByJid(recipient))!.id;
for (final path in paths) {
_log.finest('Requesting upload slot for $path');
final stat = File(path).statSync();
final result = await httpManager.requestUploadSlot(pathlib.basename(path), stat.size);
if (result.isError()) {
_log.severe('Failed to request slot for $path!');
// TODO(PapaTutuWawa): Do not let it end here
return;
}
final slot = result.getValue();
final fileMime = lookupMimeType(path);
final uploadResult = await us.uploadFile(
path,
slot.putUrl,
slot.headers,
messages[path]!.id,
);
if (!uploadResult) { if (!uploadResult) {
_log.severe('Upload failed'); _log.severe('Upload failed for $path!');
// TODO(PapaTutuWawa): Do not abort here // TODO(PapaTutuWawa): Do not abort here
return; return;
} }
final id = (await cs.getConversationByJid(recipient))!.id; // Notify UI of upload completion
sendEvent(
MessageUpdatedEvent(
message: messages[path]!.copyWith(isUploading: false),
),
);
// Update conversation
final updatedConversation = await cs.updateConversation( final updatedConversation = await cs.updateConversation(
id, conversationId,
lastMessageBody: mimeTypeToConversationBody(fileMime), lastMessageBody: mimeTypeToConversationBody(fileMime),
lastChangeTimestamp: DateTime.now().millisecondsSinceEpoch, lastChangeTimestamp: DateTime.now().millisecondsSinceEpoch,
); );
sendEvent(ConversationUpdatedEvent(conversation: updatedConversation)); sendEvent(ConversationUpdatedEvent(conversation: updatedConversation));
// Send the url to the recipient
final message = messages[path]!;
conn.getManagerById<MessageManager>(messageManager)!.sendMessage( conn.getManagerById<MessageManager>(messageManager)!.sendMessage(
MessageDetails( MessageDetails(
to: recipient, to: recipient,
body: slot.getUrl, body: slot.getUrl,
requestDeliveryReceipt: true, requestDeliveryReceipt: true,
id: sid, id: message.sid,
originId: originId, originId: message.originId,
sfs: StatelessFileSharingData( sfs: StatelessFileSharingData(
url: slot.getUrl, url: slot.getUrl,
metadata: FileMetadataData( metadata: FileMetadataData(
@ -395,7 +416,10 @@ class XmppService {
), ),
), ),
); );
_log.finest('Sent message with file upload'); _log.finest('Sent message with file upload for $path');
}
_log.finest('File upload done');
} }
Future<void> _onConnectionStateChanged(ConnectionStateChangedEvent event, { dynamic extra }) async { Future<void> _onConnectionStateChanged(ConnectionStateChangedEvent event, { dynamic extra }) async {

View File

@ -290,12 +290,12 @@ class ConversationBloc extends Bloc<ConversationEvent, ConversationState> {
} }
Future<void> _onFileUploadRequested(FileUploadRequestedEvent event, Emitter<ConversationState> emit) async { Future<void> _onFileUploadRequested(FileUploadRequestedEvent event, Emitter<ConversationState> emit) async {
final result = await FilePicker.platform.pickFiles(type: FileType.image); final result = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
if (result != null) { if (result != null) {
await MoxplatformPlugin.handler.getDataSender().sendData( await MoxplatformPlugin.handler.getDataSender().sendData(
SendFileCommand( SendFilesCommand(
path: result.files.single.path!, paths: result.files.map((PlatformFile file) => file.path!).toList(),
jid: state.conversation!.jid, jid: state.conversation!.jid,
), ),
awaitable: false, awaitable: false,