1
0
Fork 1

Send attachments in order

Not perfect. It means we lose paralellism of uploads which is maybe bad?
If any one errors the subsequent ones stay queued I think. If you're
offline or similar then it all gets written to the db and we stil lose
ordering.

May still be worth it, worth testing.

(cherry picked from commit 0683b065f5a99d214e343fa92aa468b62e1cada8)
This commit is contained in:
Stephen Paul Weber 2024-11-20 05:49:39 +01:00 committed by Arne
parent 1b57462cdb
commit 2d76569b9f
5 changed files with 116 additions and 87 deletions

View file

@ -111,6 +111,10 @@ public class HttpConnectionManager extends AbstractConnectionManager {
} }
public void createNewUploadConnection(final Message message, boolean delay) { public void createNewUploadConnection(final Message message, boolean delay) {
createNewUploadConnection(message, delay, null);
}
public void createNewUploadConnection(final Message message, boolean delay, final Runnable cb) {
synchronized (this.uploadConnections) { synchronized (this.uploadConnections) {
for (HttpUploadConnection connection : this.uploadConnections) { for (HttpUploadConnection connection : this.uploadConnections) {
if (connection.getMessage() == message) { if (connection.getMessage() == message) {
@ -118,7 +122,7 @@ public class HttpConnectionManager extends AbstractConnectionManager {
return; return;
} }
} }
HttpUploadConnection connection = new HttpUploadConnection(message, Method.determine(message.getConversation().getAccount()), this); HttpUploadConnection connection = new HttpUploadConnection(message, Method.determine(message.getConversation().getAccount()), this, cb);
connection.init(delay); connection.init(delay);
this.uploadConnections.add(connection); this.uploadConnections.add(connection);
} }

View file

@ -52,12 +52,14 @@ public class HttpUploadConnection implements Transferable, AbstractConnectionMan
private long transmitted = 0; private long transmitted = 0;
private Call mostRecentCall; private Call mostRecentCall;
private ListenableFuture<SlotRequester.Slot> slotFuture; private ListenableFuture<SlotRequester.Slot> slotFuture;
private Runnable cb;
public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager) { public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager, Runnable cb) {
this.message = message; this.message = message;
this.method = method; this.method = method;
this.mHttpConnectionManager = httpConnectionManager; this.mHttpConnectionManager = httpConnectionManager;
this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService(); this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
this.cb = cb;
} }
@Override @Override
@ -104,6 +106,7 @@ public class HttpUploadConnection implements Transferable, AbstractConnectionMan
final Future<SlotRequester.Slot> slotFuture = this.slotFuture; final Future<SlotRequester.Slot> slotFuture = this.slotFuture;
final boolean cancelled = (call != null && call.isCanceled()) || (slotFuture != null && slotFuture.isCancelled()); final boolean cancelled = (call != null && call.isCanceled()) || (slotFuture != null && slotFuture.isCancelled());
mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage); mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
if (cb != null) cb.run();
} }
private void finish() { private void finish() {
@ -191,7 +194,7 @@ public class HttpUploadConnection implements Transferable, AbstractConnectionMan
if (!message.isPrivateMessage()) { if (!message.isPrivateMessage()) {
message.setCounterpart(message.getConversation().getJid().asBareJid()); message.setCounterpart(message.getConversation().getJid().asBareJid());
} }
mXmppConnectionService.resendMessage(message, delayed); mXmppConnectionService.resendMessage(message, delayed, cb);
} else { } else {
Log.d(Config.LOGTAG, "http upload failed because response code was " + code); Log.d(Config.LOGTAG, "http upload failed because response code was " + code);
fail("http upload failed because response code was " + code); fail("http upload failed because response code was " + code);

View file

@ -63,8 +63,7 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
final int encryption = message.getEncryption(); final int encryption = message.getEncryption();
mXmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, false, (file) -> { mXmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, false, (file) -> {
message.setEncryption(encryption); message.setEncryption(encryption);
mXmppConnectionService.sendMessage(message); mXmppConnectionService.sendMessage(message, () -> callback.success(message));
callback.success(message);
}); });
} else if (path != null && !FileBackend.isPathBlacklisted(path)) { } else if (path != null && !FileBackend.isPathBlacklisted(path)) {
message.setRelativeFilePath(path); message.setRelativeFilePath(path);
@ -72,8 +71,7 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
mXmppConnectionService.getPgpEngine().encrypt(message, callback); mXmppConnectionService.getPgpEngine().encrypt(message, callback);
} else { } else {
mXmppConnectionService.sendMessage(message); mXmppConnectionService.sendMessage(message, () -> callback.success(message));
callback.success(message);
} }
} else { } else {
try { try {
@ -87,8 +85,7 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
callback.error(R.string.unable_to_connect_to_keychain, null); callback.error(R.string.unable_to_connect_to_keychain, null);
} }
} else { } else {
mXmppConnectionService.sendMessage(message); mXmppConnectionService.sendMessage(message, () -> callback.success(message));
callback.success(message);
} }
} catch (FileBackend.FileCopyException e) { } catch (FileBackend.FileCopyException e) {
callback.error(e.getResId(), message); callback.error(e.getResId(), message);
@ -163,8 +160,7 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
mXmppConnectionService.getPgpEngine().encrypt(message, callback); mXmppConnectionService.getPgpEngine().encrypt(message, callback);
} else { } else {
mXmppConnectionService.sendMessage(message); mXmppConnectionService.sendMessage(message, () -> callback.success(message));
callback.success(message);
} }
} }

View file

@ -747,8 +747,7 @@ public class XmppConnectionService extends Service {
callback.error(R.string.unable_to_connect_to_keychain, null); callback.error(R.string.unable_to_connect_to_keychain, null);
} }
} else { } else {
sendMessage(message); sendMessage(message, false, false, false, () -> callback.success(message));
callback.success(message);
} }
}); });
} }
@ -1912,22 +1911,27 @@ public class XmppConnectionService extends Service {
} }
} }
private void sendFileMessage(final Message message, final boolean delay) { private void sendFileMessage(final Message message, final boolean delay, final Runnable cb) {
Log.d(Config.LOGTAG, "send file message"); Log.d(Config.LOGTAG, "send file message");
final Account account = message.getConversation().getAccount(); final Account account = message.getConversation().getAccount();
if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize()) if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize())
|| message.getConversation().getMode() == Conversation.MODE_MULTI) { || message.getConversation().getMode() == Conversation.MODE_MULTI) {
mHttpConnectionManager.createNewUploadConnection(message, delay); mHttpConnectionManager.createNewUploadConnection(message, delay, cb);
} else { } else {
mJingleConnectionManager.startJingleFileTransfer(message); mJingleConnectionManager.startJingleFileTransfer(message);
if (cb != null) cb.run();
} }
} }
public void sendMessage(final Message message) { public void sendMessage(final Message message) {
sendMessage(message, false, false, false); sendMessage(message, false, false, false, null);
} }
private void sendMessage(final Message message, final boolean resend, final boolean previewedLinks, final boolean delay) { public void sendMessage(final Message message, final Runnable cb) {
sendMessage(message, false, false, false, cb);
}
private void sendMessage(final Message message, final boolean resend, final boolean previewedLinks, final boolean delay, final Runnable cb) {
final Account account = message.getConversation().getAccount(); final Account account = message.getConversation().getAccount();
if (account.setShowErrorNotification(true)) { if (account.setShowErrorNotification(true)) {
databaseBackend.updateAccount(account); databaseBackend.updateAccount(account);
@ -1936,7 +1940,6 @@ public class XmppConnectionService extends Service {
final Conversation conversation = (Conversation) message.getConversation(); final Conversation conversation = (Conversation) message.getConversation();
account.deactivateGracePeriod(); account.deactivateGracePeriod();
if (QuickConversationsService.isQuicksy() && conversation.getMode() == Conversation.MODE_SINGLE) { if (QuickConversationsService.isQuicksy() && conversation.getMode() == Conversation.MODE_SINGLE) {
final Contact contact = conversation.getContact(); final Contact contact = conversation.getContact();
if (!contact.showInRoster() && contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) { if (!contact.showInRoster() && contact.getOption(Contact.Options.SYNCED_VIA_OTHER)) {
@ -2014,7 +2017,7 @@ public class XmppConnectionService extends Service {
getHttpConnectionManager().createNewDownloadConnection(message, false, (file) -> { getHttpConnectionManager().createNewDownloadConnection(message, false, (file) -> {
message.setEncryption(encryption); message.setEncryption(encryption);
synchronized (message.getConversation()) { synchronized (message.getConversation()) {
if (message.getStatus() == Message.STATUS_WAITING) sendMessage(message, true, true, false); if (message.getStatus() == Message.STATUS_WAITING) sendMessage(message, true, true, false, cb);
} }
}); });
return; return;
@ -2068,13 +2071,14 @@ public class XmppConnectionService extends Service {
} }
} }
synchronized (message.getConversation()) { synchronized (message.getConversation()) {
if (message.getStatus() == Message.STATUS_WAITING) sendMessage(message, true, true, false); if (message.getStatus() == Message.STATUS_WAITING) sendMessage(message, true, true, false, cb);
} }
}); });
} }
} }
} }
boolean passedCbOn = false;
if (account.isOnlineAndConnected() && !inProgressJoin && !waitForPreview && message.getTimeSent() <= System.currentTimeMillis()) { if (account.isOnlineAndConnected() && !inProgressJoin && !waitForPreview && message.getTimeSent() <= System.currentTimeMillis()) {
switch (message.getEncryption()) { switch (message.getEncryption()) {
case Message.ENCRYPTION_NONE: case Message.ENCRYPTION_NONE:
@ -2082,7 +2086,8 @@ public class XmppConnectionService extends Service {
if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize()) if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize())
|| conversation.getMode() == Conversation.MODE_MULTI || conversation.getMode() == Conversation.MODE_MULTI
|| message.fixCounterpart()) { || message.fixCounterpart()) {
this.sendFileMessage(message, delay); this.sendFileMessage(message, delay, cb);
passedCbOn = true;
} else { } else {
break; break;
} }
@ -2096,7 +2101,8 @@ public class XmppConnectionService extends Service {
if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize()) if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize())
|| conversation.getMode() == Conversation.MODE_MULTI || conversation.getMode() == Conversation.MODE_MULTI
|| message.fixCounterpart()) { || message.fixCounterpart()) {
this.sendFileMessage(message, delay); this.sendFileMessage(message, delay, cb);
passedCbOn = true;
} else { } else {
break; break;
} }
@ -2134,7 +2140,8 @@ public class XmppConnectionService extends Service {
if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize()) if (account.httpUploadAvailable(fileBackend.getFile(message, false).getSize())
|| conversation.getMode() == Conversation.MODE_MULTI || conversation.getMode() == Conversation.MODE_MULTI
|| message.fixCounterpart()) { || message.fixCounterpart()) {
this.sendFileMessage(message, delay); this.sendFileMessage(message, delay, cb);
passedCbOn = true;
} else { } else {
break; break;
} }
@ -2172,6 +2179,7 @@ public class XmppConnectionService extends Service {
Log.e(Config.LOGTAG, "error updated message in DB after edit"); Log.e(Config.LOGTAG, "error updated message in DB after edit");
} }
updateConversationUi(); updateConversationUi();
if (!waitForPreview && cb != null) cb.run();
return; return;
} else { } else {
databaseBackend.createMessage(message); databaseBackend.createMessage(message);
@ -2242,6 +2250,7 @@ public class XmppConnectionService extends Service {
if (message.getConversation() instanceof Conversation) presenceToMuc((Conversation) message.getConversation()); if (message.getConversation() instanceof Conversation) presenceToMuc((Conversation) message.getConversation());
} }
} }
if (!waitForPreview && !passedCbOn && cb != null) { Log.d("WUT cb", message.getRawBody()); cb.run(); }
} }
private boolean isJoinInProgress(final Conversation conversation) { private boolean isJoinInProgress(final Conversation conversation) {
@ -2268,11 +2277,15 @@ public class XmppConnectionService extends Service {
} }
public void resendMessage(final Message message, final boolean delay) { public void resendMessage(final Message message, final boolean delay) {
sendMessage(message, true, false, delay); sendMessage(message, true, false, delay, null);
}
public void resendMessage(final Message message, final boolean delay, final Runnable cb) {
sendMessage(message, true, false, delay, cb);
} }
public void resendMessage(final Message message, final boolean delay, final boolean previewedLinks) { public void resendMessage(final Message message, final boolean delay, final boolean previewedLinks) {
sendMessage(message, true, previewedLinks, delay); sendMessage(message, true, previewedLinks, delay, null);
} }
public Pair<Account,Account> onboardingIncomplete() { public Pair<Account,Account> onboardingIncomplete() {

View file

@ -1076,7 +1076,7 @@ public class ConversationFragment extends XmppFragment
}); });
} }
private void attachFileToConversation(Conversation conversation, Uri uri, String type) { private void attachFileToConversation(Conversation conversation, Uri uri, String type, Runnable next) {
if (conversation == null) { if (conversation == null) {
return; return;
} }
@ -1100,10 +1100,14 @@ public class ConversationFragment extends XmppFragment
@Override @Override
public void success(Message message) { public void success(Message message) {
runOnUiThread(() -> { if (next == null) {
activity.hideToast(); runOnUiThread(() -> {
messageSent(); activity.hideToast();
}); messageSent();
});
} else {
runOnUiThread(next);
}
hidePrepareFileToast(prepareFileToast); hidePrepareFileToast(prepareFileToast);
} }
@ -1126,7 +1130,7 @@ public class ConversationFragment extends XmppFragment
toggleInputMethod(); toggleInputMethod();
} }
private void attachImageToConversation(Conversation conversation, Uri uri, String type) { private void attachImageToConversation(Conversation conversation, Uri uri, String type, Runnable next) {
if (conversation == null) { if (conversation == null) {
return; return;
} }
@ -1150,7 +1154,11 @@ public class ConversationFragment extends XmppFragment
@Override @Override
public void success(Message message) { public void success(Message message) {
hidePrepareFileToast(prepareFileToast); hidePrepareFileToast(prepareFileToast);
runOnUiThread(() -> messageSent()); if (next == null) {
runOnUiThread(() -> messageSent());
} else {
runOnUiThread(next);
}
} }
@Override @Override
@ -1506,26 +1514,31 @@ public class ConversationFragment extends XmppFragment
} }
final PresenceSelector.OnPresenceSelected callback = final PresenceSelector.OnPresenceSelected callback =
() -> { () -> {
for (Iterator<Attachment> i = attachments.iterator(); i.hasNext(); i.remove()) { final Iterator<Attachment> i = attachments.iterator();
final Attachment attachment = i.next(); final Runnable next = new Runnable() {
if (attachment.getType() == Attachment.Type.LOCATION) { @Override
attachLocationToConversation(conversation, attachment.getUri()); public void run() {
} else if (attachment.getType() == Attachment.Type.IMAGE) { final Attachment attachment = i.next();
Log.d( if (attachment.getType() == Attachment.Type.LOCATION) {
Config.LOGTAG, attachLocationToConversation(conversation, attachment.getUri());
"ConversationsActivity.commitAttachments() - attaching image to conversations. CHOOSE_IMAGE"); if (i.hasNext()) runOnUiThread(this);
attachImageToConversation( } else if (attachment.getType() == Attachment.Type.IMAGE) {
conversation, attachment.getUri(), attachment.getMime()); Log.d(
} else { Config.LOGTAG,
Log.d( "ConversationsActivity.commitAttachments() - attaching image to conversations. CHOOSE_IMAGE");
Config.LOGTAG, attachImageToConversation(conversation, attachment.getUri(), attachment.getMime(), i.hasNext() ? this : null);
"ConversationsActivity.commitAttachments() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE/RECORD_VIDEO"); } else {
attachFileToConversation( Log.d(
conversation, attachment.getUri(), attachment.getMime()); Config.LOGTAG,
"ConversationsActivity.commitAttachments() - attaching file to conversations. CHOOSE_FILE/RECORD_VOICE/RECORD_VIDEO");
attachFileToConversation(conversation, attachment.getUri(), attachment.getMime(), i.hasNext() ? this : null);
}
i.remove();
mediaPreviewAdapter.notifyDataSetChanged();
toggleInputMethod();
} }
} };
mediaPreviewAdapter.notifyDataSetChanged(); next.run();
toggleInputMethod();
}; };
if (conversation == null if (conversation == null
|| conversation.getMode() == Conversation.MODE_MULTI || conversation.getMode() == Conversation.MODE_MULTI
@ -1856,42 +1869,42 @@ public class ConversationFragment extends XmppFragment
}))); })));
} }
@Override @Override
protected AutocompletePresenter.PopupDimensions getPopupDimensions() { protected AutocompletePresenter.PopupDimensions getPopupDimensions() {
final var dim = new AutocompletePresenter.PopupDimensions(); final var dim = new AutocompletePresenter.PopupDimensions();
dim.width = displayMetrics.widthPixels * 4 / 5; dim.width = displayMetrics.widthPixels * 4/5;
return dim; return dim;
} }
}) })
.with(new AutocompleteCallback<MucOptions.User>() { .with(new AutocompleteCallback<MucOptions.User>() {
@Override @Override
public boolean onPopupItemClicked(Editable editable, MucOptions.User user) { public boolean onPopupItemClicked(Editable editable, MucOptions.User user) {
int[] range = com.otaliastudios.autocomplete.CharPolicy.getQueryRange(editable); int[] range = com.otaliastudios.autocomplete.CharPolicy.getQueryRange(editable);
if (range == null) return false; if (range == null) return false;
range[0] -= 1; range[0] -= 1;
if ("\0attention".equals(user.getOccupantId())) { if ("\0attention".equals(user.getOccupantId())) {
editable.delete(Math.max(0, range[0]), Math.min(editable.length(), range[1])); editable.delete(Math.max(0, range[0]), Math.min(editable.length(), range[1]));
editable.insert(0, "@here "); editable.insert(0, "@here ");
return true; return true;
} }
int colon = editable.toString().indexOf(':'); int colon = editable.toString().indexOf(':');
final var beforeColon = range[0] < colon; final var beforeColon = range[0] < colon;
String prefix = ""; String prefix = "";
String suffix = " "; String suffix = " ";
if (beforeColon) suffix = ", "; if (beforeColon) suffix = ", ";
if (colon < 0 && range[0] == 0) suffix = ": "; if (colon < 0 && range[0] == 0) suffix = ": ";
if (colon > 0 && colon == range[0] - 2) { if (colon > 0 && colon == range[0] - 2) {
prefix = ", "; prefix = ", ";
suffix = ": "; suffix = ": ";
range[0] -= 2; range[0] -= 2;
} }
var insert = user.getNick(); var insert = user.getNick();
if ("\0role:moderator".equals(user.getOccupantId())) { if ("\0role:moderator".equals(user.getOccupantId())) {
insert = conversation.getMucOptions().getUsersByRole(MucOptions.Role.MODERATOR).stream().map(MucOptions.User::getNick).collect(Collectors.joining(", ")); insert = conversation.getMucOptions().getUsersByRole(MucOptions.Role.MODERATOR).stream().map(MucOptions.User::getNick).collect(Collectors.joining(", "));
} }
editable.replace(Math.max(0, range[0]), Math.min(editable.length(), range[1]), prefix + insert + suffix); editable.replace(Math.max(0, range[0]), Math.min(editable.length(), range[1]), prefix + insert + suffix);
return true; return true;
} }
@Override @Override
public void onPopupVisibilityChanged(boolean shown) { public void onPopupVisibilityChanged(boolean shown) {