diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt index c699325562..95ff11d595 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.crypto.attachments import android.util.Base64 -import arrow.core.Try import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileKey import timber.log.Timber @@ -50,7 +49,7 @@ object MXEncryptedAttachments { * @param mimetype the mime type * @return the encryption file info */ - fun encryptAttachment(attachmentStream: InputStream, mimetype: String): Try { + fun encryptAttachment(attachmentStream: InputStream, mimetype: String): EncryptionResult { val t0 = System.currentTimeMillis() val secureRandom = SecureRandom() @@ -70,7 +69,7 @@ object MXEncryptedAttachments { val outStream = ByteArrayOutputStream() - try { + outStream.use { val encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) val ivParameterSpec = IvParameterSpec(initVectorBytes) @@ -114,19 +113,7 @@ object MXEncryptedAttachments { ) Timber.v("Encrypt in ${System.currentTimeMillis() - t0} ms") - return Try.just(result) - } catch (oom: OutOfMemoryError) { - Timber.e(oom, "## encryptAttachment failed") - return Try.Failure(oom) - } catch (e: Exception) { - Timber.e(e, "## encryptAttachment failed") - return Try.Failure(e) - } finally { - try { - outStream.close() - } catch (e: Exception) { - Timber.e(e, "## encryptAttachment() : fail to close outStream") - } + return result } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt index 64fcb08bac..2bdcd9a2fb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt @@ -30,6 +30,7 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response import timber.log.Timber +import java.io.IOException import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -50,6 +51,24 @@ internal suspend fun Call.awaitResponse(): Response { } } +internal suspend fun okhttp3.Call.awaitResponse(): okhttp3.Response { + return suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + cancel() + } + + enqueue(object : okhttp3.Callback { + override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) { + continuation.resume(response) + } + + override fun onFailure(call: okhttp3.Call, e: IOException) { + continuation.resumeWithException(e) + } + }) + } +} + /** * Convert a retrofit Response to a Failure, and eventually parse errorBody to convert it to a MatrixError */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt index 15d75ceeb6..2f99199736 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt @@ -16,12 +16,11 @@ package im.vector.matrix.android.internal.session.content -import arrow.core.Try -import arrow.core.Try.Companion.raise import com.squareup.moshi.Moshi import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.network.ProgressRequestBody +import im.vector.matrix.android.internal.network.awaitResponse import im.vector.matrix.android.internal.network.toFailure import okhttp3.* import java.io.File @@ -38,28 +37,26 @@ internal class FileUploader @Inject constructor(@Authenticated private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java) - fun uploadFile(file: File, - filename: String?, - mimeType: String, - progressListener: ProgressRequestBody.Listener? = null): Try { - + suspend fun uploadFile(file: File, + filename: String?, + mimeType: String, + progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { val uploadBody = RequestBody.create(MediaType.parse(mimeType), file) return upload(uploadBody, filename, progressListener) } - fun uploadByteArray(byteArray: ByteArray, - filename: String?, - mimeType: String, - progressListener: ProgressRequestBody.Listener? = null): Try { - + suspend fun uploadByteArray(byteArray: ByteArray, + filename: String?, + mimeType: String, + progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { val uploadBody = RequestBody.create(MediaType.parse(mimeType), byteArray) return upload(uploadBody, filename, progressListener) } - private fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): Try { - val urlBuilder = HttpUrl.parse(uploadUrl)?.newBuilder() ?: return raise(RuntimeException()) + private suspend fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): ContentUploadResponse { + val urlBuilder = HttpUrl.parse(uploadUrl)?.newBuilder() ?: throw RuntimeException() val httpUrl = urlBuilder .addQueryParameter("filename", filename) @@ -72,19 +69,15 @@ internal class FileUploader @Inject constructor(@Authenticated .post(requestBody) .build() - return Try { - okHttpClient.newCall(request).execute().use { response -> - if (!response.isSuccessful) { - throw response.toFailure() - } else { - response.body()?.source()?.let { - responseAdapter.fromJson(it) - } - ?: throw IOException() + return okHttpClient.newCall(request).awaitResponse().use { response -> + if (!response.isSuccessful) { + throw response.toFailure() + } else { + response.body()?.source()?.let { + responseAdapter.fromJson(it) } + ?: throw IOException() } } - } - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt index b015670daa..2d9509b43d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/UploadContentWorker.kt @@ -93,32 +93,28 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : } } - val contentUploadResponse = if (params.isRoomEncrypted) { - Timber.v("Encrypt thumbnail") - contentUploadStateTracker.setEncryptingThumbnail(eventId) - MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) - .flatMap { encryptionResult -> - uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo + try { + val contentUploadResponse = if (params.isRoomEncrypted) { + Timber.v("Encrypt thumbnail") + contentUploadStateTracker.setEncryptingThumbnail(eventId) + val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) + uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo + fileUploader.uploadByteArray(encryptionResult.encryptedByteArray, + "thumb_${attachment.name}", + "application/octet-stream", + thumbnailProgressListener) + } else { + fileUploader.uploadByteArray(thumbnailData.bytes, + "thumb_${attachment.name}", + thumbnailData.mimeType, + thumbnailProgressListener) + } - fileUploader - .uploadByteArray(encryptionResult.encryptedByteArray, - "thumb_${attachment.name}", - "application/octet-stream", - thumbnailProgressListener) - } - } else { - fileUploader - .uploadByteArray(thumbnailData.bytes, - "thumb_${attachment.name}", - thumbnailData.mimeType, - thumbnailProgressListener) + uploadedThumbnailUrl = contentUploadResponse.contentUri + } catch (t: Throwable) { + Timber.e(t) + return handleFailure(params, t) } - - contentUploadResponse - .fold( - { Timber.e(it) }, - { uploadedThumbnailUrl = it.contentUri } - ) } val progressListener = object : ProgressRequestBody.Listener { @@ -133,27 +129,26 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) : var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null - val contentUploadResponse = if (params.isRoomEncrypted) { - Timber.v("Encrypt file") - contentUploadStateTracker.setEncrypting(eventId) + return try { + val contentUploadResponse = if (params.isRoomEncrypted) { + Timber.v("Encrypt file") + contentUploadStateTracker.setEncrypting(eventId) - MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.mimeType) - .flatMap { encryptionResult -> - uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo + val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.mimeType) + uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo - fileUploader - .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener) - } - } else { - fileUploader - .uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener) + fileUploader + .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener) + } else { + fileUploader + .uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener) + } + + handleSuccess(params, contentUploadResponse.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo) + } catch (t: Throwable) { + Timber.e(t) + handleFailure(params, t) } - - return contentUploadResponse - .fold( - { handleFailure(params, it) }, - { handleSuccess(params, it.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo) } - ) } private fun handleFailure(params: Params, failure: Throwable): Result {