use of org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer in project Signal-Android by WhisperSystems.
the class AttachmentDownloadJob method retrieveAttachment.
private void retrieveAttachment(long messageId, final AttachmentId attachmentId, final Attachment attachment) throws IOException, RetryLaterException {
AttachmentDatabase database = SignalDatabase.attachments();
File attachmentFile = database.getOrCreateTransferFile(attachmentId);
try {
SignalServiceMessageReceiver messageReceiver = ApplicationDependencies.getSignalServiceMessageReceiver();
SignalServiceAttachmentPointer pointer = createAttachmentPointer(attachment);
InputStream stream = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress)));
database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream);
} catch (RangeException e) {
Log.w(TAG, "Range exception, file size " + attachmentFile.length(), e);
if (attachmentFile.delete()) {
Log.i(TAG, "Deleted temp download file to recover");
throw new RetryLaterException(e);
} else {
throw new IOException("Failed to delete temp download file following range exception");
}
} catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException | MissingConfigurationException e) {
Log.w(TAG, "Experienced exception while trying to download an attachment.", e);
markFailed(messageId, attachmentId);
}
}
use of org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer in project Signal-Android by WhisperSystems.
the class AttachmentUploadJob method onRun.
@Override
public void onRun() throws Exception {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
Data inputData = getInputData();
ResumableUploadSpec resumableUploadSpec;
if (forceV2) {
Log.d(TAG, "Forcing utilization of V2");
resumableUploadSpec = null;
} else if (inputData != null && inputData.hasString(ResumableUploadSpecJob.KEY_RESUME_SPEC)) {
Log.d(TAG, "Using attachments V3");
resumableUploadSpec = ResumableUploadSpec.deserialize(inputData.getString(ResumableUploadSpecJob.KEY_RESUME_SPEC));
} else {
Log.d(TAG, "Using attachments V2");
resumableUploadSpec = null;
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
AttachmentDatabase database = SignalDatabase.attachments();
DatabaseAttachment databaseAttachment = database.getAttachment(attachmentId);
if (databaseAttachment == null) {
throw new InvalidAttachmentException("Cannot find the specified attachment.");
}
long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.getUploadTimestamp();
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.getLocation())) {
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded " + timeSinceUpload + " ms ago. Skipping.");
return;
} else if (databaseAttachment.getUploadTimestamp() > 0) {
Log.i(TAG, "This file was previously-uploaded, but too long ago to be re-used. Age: " + timeSinceUpload + " ms");
}
Log.i(TAG, "Uploading attachment for message " + databaseAttachment.getMmsId() + " with ID " + databaseAttachment.getAttachmentId());
try (NotificationController notification = getNotificationForAttachment(databaseAttachment)) {
SignalServiceAttachment localAttachment = getAttachmentFor(databaseAttachment, notification, resumableUploadSpec);
SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment.asStream());
Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.getFastPreflightId()).get();
database.updateAttachmentAfterUpload(databaseAttachment.getAttachmentId(), attachment, remoteAttachment.getUploadTimestamp());
} catch (NonSuccessfulResumableUploadResponseCodeException e) {
if (e.getCode() == 400) {
Log.w(TAG, "Failed to upload due to a 400 when getting resumable upload information. Downgrading to attachments v2", e);
forceV2 = true;
}
}
}
use of org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer in project Signal-Android by WhisperSystems.
the class SignalServiceMessageSender method uploadAttachmentV2.
private SignalServiceAttachmentPointer uploadAttachmentV2(SignalServiceAttachmentStream attachment, byte[] attachmentKey, PushAttachmentData attachmentData) throws NonSuccessfulResponseCodeException, PushNetworkException, MalformedResponseException {
AttachmentV2UploadAttributes v2UploadAttributes = null;
Log.d(TAG, "Using pipe to retrieve attachment upload attributes...");
try {
v2UploadAttributes = new AttachmentService.AttachmentAttributesResponseProcessor<>(attachmentService.getAttachmentV2UploadAttributes().blockingGet()).getResultOrThrow();
} catch (WebSocketUnavailableException e) {
Log.w(TAG, "[uploadAttachmentV2] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
} catch (IOException e) {
Log.w(TAG, "Failed to retrieve attachment upload attributes using pipe. Falling back...");
}
if (v2UploadAttributes == null) {
Log.d(TAG, "Not using pipe to retrieve attachment upload attributes...");
v2UploadAttributes = socket.getAttachmentV2UploadAttributes();
}
Pair<Long, byte[]> attachmentIdAndDigest = socket.uploadAttachment(attachmentData, v2UploadAttributes);
return new SignalServiceAttachmentPointer(0, new SignalServiceAttachmentRemoteId(attachmentIdAndDigest.first()), attachment.getContentType(), attachmentKey, Optional.of(Util.toIntExact(attachment.getLength())), attachment.getPreview(), attachment.getWidth(), attachment.getHeight(), Optional.of(attachmentIdAndDigest.second()), attachment.getFileName(), attachment.getVoiceNote(), attachment.isBorderless(), attachment.isGif(), attachment.getCaption(), attachment.getBlurHash(), attachment.getUploadTimestamp());
}
use of org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer in project libsignal-service-java by signalapp.
the class SignalServiceMessageSender method uploadAttachment.
public SignalServiceAttachmentPointer uploadAttachment(SignalServiceAttachmentStream attachment) throws IOException {
byte[] attachmentKey = Util.getSecretBytes(64);
long paddedLength = PaddingInputStream.getPaddedSize(attachment.getLength());
InputStream dataStream = new PaddingInputStream(attachment.getInputStream(), attachment.getLength());
long ciphertextLength = AttachmentCipherOutputStream.getCiphertextLength(paddedLength);
PushAttachmentData attachmentData = new PushAttachmentData(attachment.getContentType(), dataStream, ciphertextLength, new AttachmentCipherOutputStreamFactory(attachmentKey), attachment.getListener());
AttachmentUploadAttributes uploadAttributes = null;
if (pipe.get().isPresent()) {
Log.d(TAG, "Using pipe to retrieve attachment upload attributes...");
try {
uploadAttributes = pipe.get().get().getAttachmentUploadAttributes();
} catch (IOException e) {
Log.w(TAG, "Failed to retrieve attachment upload attributes using pipe. Falling back...");
}
}
if (uploadAttributes == null) {
Log.d(TAG, "Not using pipe to retrieve attachment upload attributes...");
uploadAttributes = socket.getAttachmentUploadAttributes();
}
Pair<Long, byte[]> attachmentIdAndDigest = socket.uploadAttachment(attachmentData, uploadAttributes);
return new SignalServiceAttachmentPointer(attachmentIdAndDigest.first(), attachment.getContentType(), attachmentKey, Optional.of(Util.toIntExact(attachment.getLength())), attachment.getPreview(), attachment.getWidth(), attachment.getHeight(), Optional.of(attachmentIdAndDigest.second()), attachment.getFileName(), attachment.getVoiceNote(), attachment.getCaption(), attachment.getBlurHash());
}
use of org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer in project Signal-Android by signalapp.
the class AttachmentUploadJob method onRun.
@Override
public void onRun() throws Exception {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
Data inputData = getInputData();
ResumableUploadSpec resumableUploadSpec;
if (forceV2) {
Log.d(TAG, "Forcing utilization of V2");
resumableUploadSpec = null;
} else if (inputData != null && inputData.hasString(ResumableUploadSpecJob.KEY_RESUME_SPEC)) {
Log.d(TAG, "Using attachments V3");
resumableUploadSpec = ResumableUploadSpec.deserialize(inputData.getString(ResumableUploadSpecJob.KEY_RESUME_SPEC));
} else {
Log.d(TAG, "Using attachments V2");
resumableUploadSpec = null;
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
AttachmentDatabase database = SignalDatabase.attachments();
DatabaseAttachment databaseAttachment = database.getAttachment(attachmentId);
if (databaseAttachment == null) {
throw new InvalidAttachmentException("Cannot find the specified attachment.");
}
long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.getUploadTimestamp();
if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.getLocation())) {
Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded " + timeSinceUpload + " ms ago. Skipping.");
return;
} else if (databaseAttachment.getUploadTimestamp() > 0) {
Log.i(TAG, "This file was previously-uploaded, but too long ago to be re-used. Age: " + timeSinceUpload + " ms");
}
Log.i(TAG, "Uploading attachment for message " + databaseAttachment.getMmsId() + " with ID " + databaseAttachment.getAttachmentId());
try (NotificationController notification = getNotificationForAttachment(databaseAttachment)) {
SignalServiceAttachment localAttachment = getAttachmentFor(databaseAttachment, notification, resumableUploadSpec);
SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment.asStream());
Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.getFastPreflightId()).get();
database.updateAttachmentAfterUpload(databaseAttachment.getAttachmentId(), attachment, remoteAttachment.getUploadTimestamp());
} catch (NonSuccessfulResumableUploadResponseCodeException e) {
if (e.getCode() == 400) {
Log.w(TAG, "Failed to upload due to a 400 when getting resumable upload information. Downgrading to attachments v2", e);
forceV2 = true;
}
}
}
Aggregations