mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-15 20:42:00 +00:00
Optimize uploads during media composition.
By uploading in advance (when on unmetered connections), media messages can send almost instantly.
This commit is contained in:
@@ -341,7 +341,8 @@ public class SignalServiceMessageSender {
|
||||
dataStream,
|
||||
ciphertextLength,
|
||||
new AttachmentCipherOutputStreamFactory(attachmentKey),
|
||||
attachment.getListener());
|
||||
attachment.getListener(),
|
||||
attachment.getCancelationSignal());
|
||||
|
||||
AttachmentUploadAttributes uploadAttributes = null;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -39,16 +40,17 @@ public abstract class SignalServiceAttachment {
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private InputStream inputStream;
|
||||
private String contentType;
|
||||
private String fileName;
|
||||
private long length;
|
||||
private ProgressListener listener;
|
||||
private boolean voiceNote;
|
||||
private int width;
|
||||
private int height;
|
||||
private String caption;
|
||||
private String blurHash;
|
||||
private InputStream inputStream;
|
||||
private String contentType;
|
||||
private String fileName;
|
||||
private long length;
|
||||
private ProgressListener listener;
|
||||
private CancelationSignal cancelationSignal;
|
||||
private boolean voiceNote;
|
||||
private int width;
|
||||
private int height;
|
||||
private String caption;
|
||||
private String blurHash;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
@@ -77,6 +79,11 @@ public abstract class SignalServiceAttachment {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCancelationSignal(CancelationSignal cancelationSignal) {
|
||||
this.cancelationSignal = cancelationSignal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withVoiceNote(boolean voiceNote) {
|
||||
this.voiceNote = voiceNote;
|
||||
return this;
|
||||
@@ -117,7 +124,8 @@ public abstract class SignalServiceAttachment {
|
||||
height,
|
||||
Optional.fromNullable(caption),
|
||||
Optional.fromNullable(blurHash),
|
||||
listener);
|
||||
listener,
|
||||
cancelationSignal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -15,33 +16,47 @@ import java.io.InputStream;
|
||||
*/
|
||||
public class SignalServiceAttachmentStream extends SignalServiceAttachment {
|
||||
|
||||
private final InputStream inputStream;
|
||||
private final long length;
|
||||
private final Optional<String> fileName;
|
||||
private final ProgressListener listener;
|
||||
private final Optional<byte[]> preview;
|
||||
private final boolean voiceNote;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final Optional<String> caption;
|
||||
private final Optional<String> blurHash;
|
||||
private final InputStream inputStream;
|
||||
private final long length;
|
||||
private final Optional<String> fileName;
|
||||
private final ProgressListener listener;
|
||||
private final CancelationSignal cancelationSignal;
|
||||
private final Optional<byte[]> preview;
|
||||
private final boolean voiceNote;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final Optional<String> caption;
|
||||
private final Optional<String> blurHash;
|
||||
|
||||
public SignalServiceAttachmentStream(InputStream inputStream, String contentType, long length, Optional<String> fileName, boolean voiceNote, ProgressListener listener) {
|
||||
this(inputStream, contentType, length, fileName, voiceNote, Optional.<byte[]>absent(), 0, 0, Optional.<String>absent(), Optional.<String>absent(), listener);
|
||||
public SignalServiceAttachmentStream(InputStream inputStream, String contentType, long length, Optional<String> fileName, boolean voiceNote, ProgressListener listener, CancelationSignal cancelationSignal) {
|
||||
this(inputStream, contentType, length, fileName, voiceNote, Optional.<byte[]>absent(), 0, 0, Optional.<String>absent(), Optional.<String>absent(), listener, cancelationSignal);
|
||||
}
|
||||
|
||||
public SignalServiceAttachmentStream(InputStream inputStream, String contentType, long length, Optional<String> fileName, boolean voiceNote, Optional<byte[]> preview, int width, int height, Optional<String> caption, Optional<String> blurHash, ProgressListener listener) {
|
||||
public SignalServiceAttachmentStream(InputStream inputStream,
|
||||
String contentType,
|
||||
long length,
|
||||
Optional<String> fileName,
|
||||
boolean voiceNote,
|
||||
Optional<byte[]> preview,
|
||||
int width,
|
||||
int height,
|
||||
Optional<String> caption,
|
||||
Optional<String> blurHash,
|
||||
ProgressListener listener,
|
||||
CancelationSignal cancelationSignal)
|
||||
{
|
||||
super(contentType);
|
||||
this.inputStream = inputStream;
|
||||
this.length = length;
|
||||
this.fileName = fileName;
|
||||
this.listener = listener;
|
||||
this.voiceNote = voiceNote;
|
||||
this.preview = preview;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.caption = caption;
|
||||
this.blurHash = blurHash;
|
||||
this.inputStream = inputStream;
|
||||
this.length = length;
|
||||
this.fileName = fileName;
|
||||
this.listener = listener;
|
||||
this.voiceNote = voiceNote;
|
||||
this.preview = preview;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.caption = caption;
|
||||
this.blurHash = blurHash;
|
||||
this.cancelationSignal = cancelationSignal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,6 +85,10 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public CancelationSignal getCancelationSignal() {
|
||||
return cancelationSignal;
|
||||
}
|
||||
|
||||
public Optional<byte[]> getPreview() {
|
||||
return preview;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class DeviceContactsInputStream extends ChunkedInputStream {
|
||||
InputStream avatarStream = new LimitedInputStream(in, avatarLength);
|
||||
String avatarContentType = details.getAvatar().getContentType();
|
||||
|
||||
avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.<String>absent(), false, null));
|
||||
avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.<String>absent(), false, null, null));
|
||||
}
|
||||
|
||||
if (details.hasVerified()) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DeviceGroupsInputStream extends ChunkedInputStream{
|
||||
InputStream avatarStream = new ChunkedInputStream.LimitedInputStream(in, avatarLength);
|
||||
String avatarContentType = details.getAvatar().getContentType();
|
||||
|
||||
avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.<String>absent(), false, null));
|
||||
avatar = Optional.of(new SignalServiceAttachmentStream(avatarStream, avatarContentType, avatarLength, Optional.<String>absent(), false, null, null));
|
||||
}
|
||||
|
||||
if (details.hasExpireTimer() && details.getExpireTimer() > 0) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package org.whispersystems.signalservice.internal.push;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener;
|
||||
import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
|
||||
import org.whispersystems.signalservice.internal.push.http.OutputStreamFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
@@ -18,15 +19,18 @@ public class PushAttachmentData {
|
||||
private final long dataSize;
|
||||
private final OutputStreamFactory outputStreamFactory;
|
||||
private final ProgressListener listener;
|
||||
private final CancelationSignal cancelationSignal;
|
||||
|
||||
public PushAttachmentData(String contentType, InputStream data, long dataSize,
|
||||
OutputStreamFactory outputStreamFactory, ProgressListener listener)
|
||||
OutputStreamFactory outputStreamFactory, ProgressListener listener,
|
||||
CancelationSignal cancelationSignal)
|
||||
{
|
||||
this.contentType = contentType;
|
||||
this.data = data;
|
||||
this.dataSize = dataSize;
|
||||
this.outputStreamFactory = outputStreamFactory;
|
||||
this.listener = listener;
|
||||
this.cancelationSignal = cancelationSignal;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
@@ -48,4 +52,8 @@ public class PushAttachmentData {
|
||||
public ProgressListener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public CancelationSignal getCancelationSignal() {
|
||||
return cancelationSignal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.whispersystems.signalservice.internal.contacts.entities.KeyBackupResp
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException;
|
||||
import org.whispersystems.signalservice.internal.push.exceptions.StaleDevicesException;
|
||||
import org.whispersystems.signalservice.internal.push.http.CancelationSignal;
|
||||
import org.whispersystems.signalservice.internal.push.http.DigestingRequestBody;
|
||||
import org.whispersystems.signalservice.internal.push.http.OutputStreamFactory;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ReadOperation;
|
||||
@@ -577,7 +578,7 @@ public class PushServiceSocket {
|
||||
formAttributes.getCredential(), formAttributes.getDate(),
|
||||
formAttributes.getSignature(), profileAvatar.getData(),
|
||||
profileAvatar.getContentType(), profileAvatar.getDataLength(),
|
||||
profileAvatar.getOutputStreamFactory(), null);
|
||||
profileAvatar.getOutputStreamFactory(), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +764,8 @@ public class PushServiceSocket {
|
||||
uploadAttributes.getCredential(), uploadAttributes.getDate(),
|
||||
uploadAttributes.getSignature(), attachment.getData(),
|
||||
"application/octet-stream", attachment.getDataSize(),
|
||||
attachment.getOutputStreamFactory(), attachment.getListener());
|
||||
attachment.getOutputStreamFactory(), attachment.getListener(),
|
||||
attachment.getCancelationSignal());
|
||||
|
||||
return new Pair<>(id, digest);
|
||||
}
|
||||
@@ -851,7 +853,8 @@ public class PushServiceSocket {
|
||||
private byte[] uploadToCdn(String path, String acl, String key, String policy, String algorithm,
|
||||
String credential, String date, String signature,
|
||||
InputStream data, String contentType, long length,
|
||||
OutputStreamFactory outputStreamFactory, ProgressListener progressListener)
|
||||
OutputStreamFactory outputStreamFactory, ProgressListener progressListener,
|
||||
CancelationSignal cancelationSignal)
|
||||
throws PushNetworkException, NonSuccessfulResponseCodeException
|
||||
{
|
||||
ConnectionHolder connectionHolder = getRandom(cdnClients, random);
|
||||
@@ -861,7 +864,7 @@ public class PushServiceSocket {
|
||||
.readTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
DigestingRequestBody file = new DigestingRequestBody(data, outputStreamFactory, contentType, length, progressListener);
|
||||
DigestingRequestBody file = new DigestingRequestBody(data, outputStreamFactory, contentType, length, progressListener, cancelationSignal);
|
||||
|
||||
RequestBody requestBody = new MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.whispersystems.signalservice.internal.push.http;
|
||||
|
||||
/**
|
||||
* Used to communicate to observers whether or not something is canceled.
|
||||
*/
|
||||
public interface CancelationSignal {
|
||||
boolean isCanceled();
|
||||
}
|
||||
@@ -18,19 +18,22 @@ public class DigestingRequestBody extends RequestBody {
|
||||
private final String contentType;
|
||||
private final long contentLength;
|
||||
private final ProgressListener progressListener;
|
||||
private final CancelationSignal cancelationSignal;
|
||||
|
||||
private byte[] digest;
|
||||
|
||||
public DigestingRequestBody(InputStream inputStream,
|
||||
OutputStreamFactory outputStreamFactory,
|
||||
String contentType, long contentLength,
|
||||
ProgressListener progressListener)
|
||||
ProgressListener progressListener,
|
||||
CancelationSignal cancelationSignal)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
this.outputStreamFactory = outputStreamFactory;
|
||||
this.contentType = contentType;
|
||||
this.contentLength = contentLength;
|
||||
this.progressListener = progressListener;
|
||||
this.cancelationSignal = cancelationSignal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,6 +50,10 @@ public class DigestingRequestBody extends RequestBody {
|
||||
long total = 0;
|
||||
|
||||
while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
|
||||
if (cancelationSignal != null && cancelationSignal.isCanceled()) {
|
||||
throw new IOException("Canceled!");
|
||||
}
|
||||
|
||||
outputStream.write(buffer, 0, read);
|
||||
total += read;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user