@@ -11,6 +11,7 @@ import eu.opencloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSyst
1111import eu.opencloud.android.lib.resources.files.tus.CreateTusUploadRemoteOperation
1212import eu.opencloud.android.lib.resources.files.tus.GetTusUploadOffsetRemoteOperation
1313import eu.opencloud.android.lib.resources.files.tus.PatchTusUploadChunkRemoteOperation
14+ import eu.opencloud.android.domain.exceptions.FileNotFoundException
1415import timber.log.Timber
1516import java.io.File
1617import kotlin.math.min
@@ -23,10 +24,12 @@ class TusUploadHelper(
2324) {
2425 @Volatile
2526 private var cancelled = false
27+ private var activePatchOperation: PatchTusUploadChunkRemoteOperation ? = null
2628
2729 fun cancel () {
2830 cancelled = true
2931 Timber .d(" TUS: upload cancellation requested" )
32+ activePatchOperation?.cancel()
3033 }
3134
3235 /* *
@@ -48,6 +51,8 @@ class TusUploadHelper(
4851 progressCallback : ((Long , Long ) -> Unit )? = null,
4952 spaceWebDavUrl : String? = null,
5053 ) {
54+ // Reset cancelled state for new upload
55+ cancelled = false
5156 Timber .d(" TUS: starting upload for %s size=%d" , remotePath, fileSize)
5257
5358 var tusUrl = transfer.tusUploadUrl
@@ -138,7 +143,8 @@ class TusUploadHelper(
138143 tusSupport = tusSupport,
139144 progressListener = progressListener,
140145 progressCallback = progressCallback,
141- initialOffset = offset
146+ initialOffset = offset,
147+ uploadId = uploadId,
142148 )
143149
144150 // Verify upload is actually complete
@@ -167,7 +173,8 @@ class TusUploadHelper(
167173 tusSupport : OCCapability .TusSupport ? ,
168174 progressListener : OnDatatransferProgressListener ? ,
169175 progressCallback : ((Long , Long ) -> Unit )? ,
170- initialOffset : Long
176+ initialOffset : Long ,
177+ uploadId : Long ,
171178 ): Long {
172179 var offset = initialOffset
173180 val serverMaxChunk = tusSupport?.maxChunkSize?.takeIf { it > 0 }?.toLong()
@@ -193,8 +200,10 @@ class TusUploadHelper(
193200 ).apply {
194201 progressListener?.let { addDataTransferProgressListener(it) }
195202 }
203+ activePatchOperation = patchOperation
196204
197205 val patchResult = patchOperation.execute(client)
206+ activePatchOperation = null
198207 if (! patchResult.isSuccess || patchResult.data == null || patchResult.data!! < offset) {
199208 consecutiveFailures++
200209 Timber .w(
@@ -211,6 +220,7 @@ class TusUploadHelper(
211220 currentOffset = offset,
212221 totalSize = fileSize,
213222 progressCallback = progressCallback,
223+ uploadId = uploadId,
214224 )
215225
216226 if (recoveredOffset != null && recoveredOffset > offset) {
@@ -297,6 +307,7 @@ class TusUploadHelper(
297307 currentOffset : Long ,
298308 totalSize : Long ,
299309 progressCallback : ((Long , Long ) -> Unit )? ,
310+ uploadId : Long ,
300311 ): Long? = try {
301312 val newOffset = executeRemoteOperation {
302313 GetTusUploadOffsetRemoteOperation (tusUrl).execute(client)
@@ -321,6 +332,19 @@ class TusUploadHelper(
321332 } catch (e: java.io.IOException ) {
322333 Timber .w(e, " TUS: recover offset failed" )
323334 throw e
335+ } catch (e: FileNotFoundException ) {
336+ Timber .w(e, " TUS: upload not found on server (404), clearing state to restart" )
337+ transferRepository.updateTusState(
338+ id = uploadId,
339+ tusUploadUrl = null ,
340+ tusUploadLength = null ,
341+ tusUploadMetadata = null ,
342+ tusUploadChecksum = null ,
343+ tusResumableVersion = null ,
344+ tusUploadExpires = null ,
345+ tusUploadConcat = null ,
346+ )
347+ throw java.io.IOException (" TUS: upload session lost (404), forcing restart" , e)
324348 } catch (recoverError: Throwable ) {
325349 Timber .w(recoverError, " TUS: recover offset failed" )
326350 null
0 commit comments