[PB-6281]: add encrypted file upload flow with multipart support#464
Conversation
3a60331 to
0506824
Compare
0506824 to
5b81068
Compare
| @@ -0,0 +1,15 @@ | |||
| package com.internxt.cloud.documents.api.model | |||
|
|
|||
| const val ENCRYPT_VERSION_AES03 = "Aes03" | |||
There was a problem hiding this comment.
Shouldn't it be the same string as in the SDK? https://github.com/internxt/sdk/blob/master/src/drive/storage/types.ts#L204
03be86e to
e3fbcb8
Compare
19346e5 to
5b81068
Compare
- add bridge API methods/models for upload start, multipart finish, and file entry creation - introduce encrypted uploader with SHA-256 part hashing and RIPEMD160 shard hash - add upload token helpers in DocumentId and JSON parsing utilities - add upload HTTP client config and Bouncy Castle RIPEMD160 dependency - add crypto callback await helper and pending upload model
5b81068 to
abd0357
Compare
CandelR
left a comment
There was a problem hiding this comment.
@terrerox After reviewing the upload implementation and taking another look at the download implementation, I have noticed that the entire module (EncryptedFileDownloader,EncryptedFileUploader, InternxtDocumentsProvider) relies on blocking threads:
call.execute()blocks a thread for the duration of the transferCompletableFuture.get()blocks another thread during encryptionopenExecutorexists solely to offload work from the binder thread, so it seems that waster a third thread. Opening a file ties up 3 threads, 2 of which do nothing but wait.
Migrating to coroutines solves this at the root:
CryptoServiceis pure native Java, so it can be wrapped directly withsuspendCancellableCoroutinecall.execute()becomescall.await()viaenqueue+suspendCancellableCoroutine- All the
AtomicReference+setOnCancelListener+OperationCanceledExceptionwiring disappears, coroutine cancellation handles it automatically openExecutorcan be removed entirely,runBlockingat the boundary ofopenDocumentis the appropriate bridge
If you’d like to give this a go, it might be worth creating a ticket to address this issue before continue with iOS tasks, as coroutines are the standard concurrency model in modern Kotlin for Android and would significantly simplify the cancellation logic
| failureMessage: String, | ||
| invoke: (OnlyErrorCallback) -> Unit, | ||
| ) { | ||
| val done = CompletableFuture<Unit>() |
There was a problem hiding this comment.
Try to use coroutines, Kotlin and the entire Android ecosystem have moved to coroutines as the standard async model.CompletableFuture.get() blocks the thread while waiting, coroutines suspend instead, freeing the thread for other work, and cancellation is automatic when the coroutine scope is cancelled . Replace with suspendCancellableCoroutine
There was a problem hiding this comment.
I will create another task to address this issue
| etag = response.header("ETag") ?: response.header("Etag") | ||
| ?: throw IOException("Part ${index + 1} missing ETag in response") | ||
| } | ||
| parts.add(UploadedPart(partNumber = index + 1, etag = etag!!)) |
There was a problem hiding this comment.
do not force the no nullable values (!!), this could lead in unexpected errors. Return the resutl to etag directly
|
Implemented coroutines here |



Uh oh!
There was an error while loading. Please reload this page.