Skip to content

Conversation

@zerox80
Copy link
Contributor

@zerox80 zerox80 commented Aug 27, 2025

Implementierung von wiederaufnehmbaren Uploads mit dem TUS-Protokoll

Zusammenfassung

Dieses Pull-Request führt die Unterstützung für das TUS-Protokoll (v1.0.0) für Datei-Uploads ein. Dies ermöglicht robuste, wiederaufnehmbare und in Blöcke aufgeteilte Uploads, was die Zuverlässigkeit bei großen Dateien und instabilen Netzwerkverbindungen erheblich verbessert. Die Implementierung ist in das bestehende WorkManager-System für Hintergrund-Uploads integriert und beinhaltet einen Fallback-Mechanismus auf traditionelle WebDAV-Uploads, falls TUS nicht verfügbar ist.

Problembeschreibung

Das Hochladen großer Dateien auf mobilen Geräten ist anfällig für Fehler durch Netzwerkunterbrechungen, das Schließen der App oder Server-Timeouts. Der bisherige, auf WebDAV basierende Upload-Mechanismus unterstützte keine Wiederaufnahme von Uploads. Das bedeutete, dass jede Unterbrechung einen vollständigen Neustart des Uploads erforderte. Dies führte zu einer schlechten Benutzererfahrung, verschwendeter Bandbreite und einer hohen Fehlerquote bei großen Dateien.

Lösungsansatz

Dieses PR löst das Problem, indem das TUS-Protokoll als primäre Methode für Uploads implementiert wird, die eine bestimmte Chunk-Größe überschreiten.

Wesentliche Änderungen im Detail:

  • TUS-Protokoll-Integration:

    • Neue RemoteOperation-Klassen für die zentralen TUS-Aktionen wurden hinzugefügt:
      • opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/files/tus/CreateTusUploadRemoteOperation.kt
      • opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/files/tus/PatchTusUploadChunkRemoteOperation.kt
      • opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/files/tus/GetTusUploadOffsetRemoteOperation.kt
      • opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/files/tus/CheckTusSupportRemoteOperation.kt
    • TUS-spezifische HTTP-Header (Tus-Resumable, Upload-Offset, etc.) wurden in opencloudComLibrary/src/main/java/eu/opencloud/android/lib/common/http/HttpConstants.java definiert.
  • Anpassungen der Worker-Klassen:

    • Die zentrale Upload-Logik in opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromFileSystemWorker.kt und opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromContentUriWorker.kt wurde überarbeitet, um TUS für Dateien zu priorisieren, die größer als CHUNK_SIZE sind.
    • Wiederaufnahmefähigkeit: Die TUS-Upload-URL und der aktuelle Fortschritt (Offset) werden nun im opencloudDomain/src/main/java/eu/opencloud/android/domain/transfers/TransferRepository.kt in der Datenbank gespeichert. Bei einer Unterbrechung kann der Worker den Upload genau an der letzten bekannten Position fortsetzen.
    • Wiederholungslogik mit Backoff: Die PATCH-Operation zum Hochladen der Chunks enthält nun einen robusten Wiederholungsmechanismus. Bei vorübergehenden Netzwerkfehlern wird der Versuch nach einer exponentiell ansteigenden Wartezeit wiederholt, um die Stabilität zu erhöhen.
    • Fallback-Mechanismus: Falls der Server TUS nicht unterstützt oder die initiale Erstellung des TUS-Uploads fehlschlägt, schalten die Worker automatisch auf den bisherigen WebDAV-basierten Chunk-Upload um. Dies stellt die Abwärtskompatibilität sicher.
  • Datenbank-Erweiterungen:

    • Das opencloudDomain/src/main/java/eu/opencloud/android/domain/transfers/model/OCTransfer.kt-Datenmodell und das TransferRepository wurden um Felder zur Speicherung des TUS-Zustands erweitert (tusUploadUrl, tusUploadOffset, etc.), um die Wiederaufnahmefähigkeit über App-Neustarts hinweg zu gewährleisten.
  • UI- und Fortschrittsanzeige:

    • Der Upload-Fortschritt wird über die WorkManager-API direkt aus der TUS-Upload-Schleife an die Benutzeroberfläche (opencloudApp/src/main/java/eu/opencloud/android/ui/activity/UploadListActivity.java) gemeldet. Dies sorgt für eine nahtlose und korrekte Fortschrittsanzeige.
    • Die Fehlerbehandlung wurde verbessert, um spezifischeres Feedback bei Upload-Fehlern (z.B. bei Anmeldefehlern) zu geben.
  • Logging:

    • Der gesamte TUS-Workflow wurde mit ausführlichem Debug-Logging via Timber versehen, um die Fehlersuche und Überprüfung zu vereinfachen.

Anleitung zum Testen

  1. Erfolgreicher TUS-Upload:

    • Eine Datei hochladen, die größer als CHUNK_SIZE ist.
    • Überprüfen, ob der Upload erfolgreich abgeschlossen wird.
    • In den Logs nach Meldungen suchen, die auf die Verwendung von TUS hinweisen (z.B. "Attempting TUS for large upload", "TUS resume offset").
  2. Test der Wiederaufnahmefähigkeit:

    • Den Upload einer großen Datei starten.
    • Während des Uploads die Netzwerkverbindung trennen.
    • Nach kurzer Zeit die Verbindung wiederherstellen.
    • Beobachten, ob der Upload automatisch an der unterbrochenen Stelle fortgesetzt und erfolgreich beendet wird.
  3. Test des Fallback-Mechanismus:

    • (Falls möglich) Gegen einen Server testen, auf dem TUS deaktiviert ist.
    • Eine große Datei hochladen.
    • Überprüfen, ob der Upload erfolgreich über den alten Chunk-Mechanismus abgeschlossen wird. In den Logs sollte eine Meldung wie "TUS flow failed, will fallback..." erscheinen.
  4. Test bei App-Neustart:

    • Einen großen Upload starten.
    • Die App vollständig schließen (Force Close).
    • Die App neu öffnen.
    • Überprüfen, ob der Upload automatisch fortgesetzt wird.

@zerox80
Copy link
Contributor Author

zerox80 commented Aug 27, 2025

Bitte überprüft auch wie es mit Lizenz sein soll. Ich bin mir da unsicher.

@zerox80
Copy link
Contributor Author

zerox80 commented Sep 10, 2025

Is there any news?

@ankumm
Copy link

ankumm commented Oct 17, 2025

Could you provid an apk for tester who are not able to compile it?

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 21, 2025

Could you provid an apk for tester who are not able to compile it?

https://github.com/zerox80/android/releases/tag/1.0rc

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 22, 2025

@guruz

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 23, 2025

fix(cache): add LruCache and null-safe disk cache init for thumbnails

  • Introduce in-memory LruCache for thumbnails to reduce disk I/O and speed up image loading
  • Add null/recycled bitmap checks before caching to prevent crashes and wasted work
  • Make disk cache initialization resilient: fall back to internal cache dir when external is unavailable; log and skip if none
  • Add memory cache lock and wire add/remove to keep memory and disk caches in sync
  • Minor cleanup: remove unused imports/fields and improve logging

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 23, 2025

opencloudApp/src/main/java/eu/opencloud/android/datamodel/ThumbnailsCacheManager.java:72 ergänzt einen threadsicheren In-Memory-LruCache samt Lock, prüft Schlüssel/Bitmap vor dem Schreiben, generiert robuste Cache-Keys für OCFile und fällt beim Disk-Cache auf das interne Verzeichnis zurück, falls extern nicht verfügbar.
In derselben Klasse (181, 408-465, 523-608) wird die Thumbnail-Pipeline gehärtet: Streams werden in finally geschlossen, HTTP-404 führt sofort zum Abschalten weiterer Aktualisierungen, PNGs erhalten den Hintergrundeinzug, und executeThumbnailTask bündelt AsyncTask-Aufrufe auf den Thread-Pool.
opencloudApp/src/main/java/eu/opencloud/android/presentation/files/filelist/FileListAdapter.kt:68-191 speichert das Ergebnis von shouldDisallowTouches…, aktiviert stabile IDs (getItemId), blendet Footer in Picker-Szenarien aus und korrigiert Selektionshilfen (selectableItemCount, versteckte Drei-Punkt-Menüs bei aktiver Auswahl).
Der Adapter nutzt nun durchgängig ThumbnailsCacheManager.getBitmapFromDiskCache(file) und executeThumbnailTask (210-305), setzt fehlende Thumbnails auf Platzhalter, räumt PNG-Hintergründe wieder frei und verhindert Starten der Generation ohne gültiges Konto.
Weitere Views (FileDetailsFragment.kt:430-444, MainFileListFragment.kt:603-620, RemoveFilesDialogFragment.kt:120-134, ShareFileFragment.kt:240, ReceiveExternalFilesAdapter.java:151) migrieren auf die neue Cache-API, sodass alle Thumbnail-Einstiegsstellen dieselbe Speicherstrategie und das zentrale Task-Dispatching verwenden.

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 23, 2025

fix(auth): OIDC-Login ohne Dynamic Registration ermöglichen

  • OAuthUtils.getClientAuth (opencloudApp/.../OAuthUtils.kt:87) gibt bei leerem Secret jetzt null zurück, damit kein leerer Basic-Header gesendet wird.
  • LoginActivity.exchangeAuthorizationCodeForTokens (opencloudApp/.../LoginActivity.kt:605) wurde so angepasst, dass:
    • zuerst dynamisch registrierte Clients genutzt und andernfalls auf oauth2_client_id zurückgegriffen wird,
    • client_id immer im Token-Request-Body bleibt, auch bei Public Clients,
    • client_secret/Authorization nur angehängt werden, wenn ein nicht-leeres Secret vorliegt und der Server client_secret_post explizit unterstützt.
  • AccountAuthenticator.performTokenRefresh (opencloudApp/.../AccountAuthenticator.java:344) übernimmt die gleiche Fallback-Logik beim Refresh Token und respektiert token_endpoint_auth_methods_supported.
  • TokenRequest und TokenRequestParams (opencloudDomain/.../TokenRequest.kt:33, opencloudComLibrary/.../TokenRequestParams.kt:31) akzeptieren nun nullbare Auth-Header; TokenRequestRemoteOperation (opencloudComLibrary/.../TokenRequestRemoteOperation.kt:55) verzichtet entsprechend auf den Authorization-Header, wenn kein Secret vorhanden ist.
  • Abgleich mit dem Backend: Der mitgelieferte Keycloak-Client (opencloud/devtools/deployments/opencloud_full/config/keycloak/clients/OpenCloudAndroid.json) ist als publicClient: true hinterlegt und passt somit zur neuen Fallback-Strategie.
  • gradlew-Unit-Tests scheitern weiterhin an einer veralteten TUS-Integrationstest-Signatur; die Korrektur steht noch aus und hängt nicht mit dieser Änderung zusammen.

Refs: opencloud-eu/opencloud-compose#122

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 24, 2025

feat(upload): honor TUS capabilities and refine fallback logic

  • Read filesTusSupport from capabilities and pass into TUS flow
  • Respect server maxChunkSize and HTTP method override during PATCH
  • Prefer TUS for large files; on failure, force chunked fallback for
    large files when TUS is advertised, even if legacy chunking is off
  • Expanded logging for chosen chunk sizes and overrides
  • Applied to ContentUri and FileSystem upload workers

Why: improve interoperability with varying servers/proxies, respect
server limits, and increase reliability of large uploads.

@ankumm
Copy link

ankumm commented Oct 27, 2025

Could you provid an apk for tester who are not able to compile it?

https://github.com/zerox80/android/releases/tag/1.0rc

Danke! Läuft wie geschmiert jetzt ;-)

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 27, 2025

Could you provid an apk for tester who are not able to compile it?

https://github.com/zerox80/android/releases/tag/1.0rc

Danke! Läuft wie geschmiert jetzt ;-)

Probier die neueren Versionen im release, die cachen nun die Thumbnails etc um die Last zu verbessern, uploads sind zuverlässiger

@kulmann kulmann requested a review from guruz October 28, 2025 13:22
@guruz
Copy link
Contributor

guruz commented Oct 29, 2025

@zerox80 Sorry for delay.
Thank you for the contribution, TUS is definitely needed!

Before we can do a deeper review, here are some pre comments from me:

Please ping when you updated the PR :)

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 29, 2025

Wait, why from August?

zerox80 commented last week
feat(upload): honor TUS capabilities and refine fallback logic

Read filesTusSupport from capabilities and pass into TUS flow
Respect server maxChunkSize and HTTP method override during PATCH
Prefer TUS for large files; on failure, force chunked fallback for
large files when TUS is advertised, even if legacy chunking is off
Expanded logging for chosen chunk sizes and overrides
Applied to ContentUri and FileSystem upload workers
Why: improve interoperability with varying servers/proxies, respect
server limits, and increase reliability of large uploads.

This solves lot of issues, for example using 5G Network etc. Ill keep this one aswell.

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 29, 2025

@guruz

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 29, 2025

PR updated! :) Squashed August commits, removed OIDC & permission/PNG changes, clean commit history with TUS + Thumbnails separated.

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 29, 2025

And i apologise for mixing up with PR's, it won't happen in future (the stuff with Thumbnail caching in a PR with TUS is kinda bullshit i know) :) let me know about updates! Thanks.

@zerox80 zerox80 force-pushed the main branch 2 times, most recently from 47e002e to e99a96e Compare October 29, 2025 23:00
@guruz
Copy link
Contributor

guruz commented Oct 30, 2025

Thanks, will have a look sometime today :)

@zerox80
Copy link
Contributor Author

zerox80 commented Oct 31, 2025

Fixed gradle build :) Couldnt build it otherwise.

Copy link
Contributor

@guruz guruz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, my comments are added to the individual lines.

I have only looked at the first commit dd872cd so far and not at your other stuff .

Regarding what you mean about Progress display, I think the function getRunningUploadsWorkInfosLiveData might be relevant..

}

if (!usedTus) {
if (isChunkingAllowed && fileSize > CHUNK_SIZE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheOneRing says that actually the old chunking is being phased out. So basicaly, files are uploaded either with a single PUT or with TUS. So you can kick out this handling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out. With the current OpenCloud, we no longer need the old WebDAV chunking as a fallback. I'll adjust the PR so that we only try TUS for large uploads and fall back to a simple PUT otherwise.

removeCacheFile()
}

private fun uploadTusFile(client: OpenCloudClient) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have quite similar code in this file here and in UploadFileFromSystemWorker. Did you check if this is OK? It might be OK or it might not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point with the double TUS code is valid. I extract the common logic into a small helper so that
UploadFileFromContentUriWorker
and
UploadFileFromFileSystemWorker
use the same process.

val idx = initial.indexOf("/uploads/")
if (idx > 0) initial.substring(0, idx + "/uploads/".length) else withSlash
}
val altInitial = initial.replace("/remote.php/dav/", "/dav/")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hardcoded stuff fishy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this as well. The OPTIONS request now just hits the uploads collection (base + optional trailing slash) and drops the manual /remote.php replacements. That keeps the detection logic in line with what the backend serves and avoids the brittle string juggling.

}

// Fallback probe on this endpoint: try POST with minimal test
Timber.d("TUS headers inconclusive at %s, probing with POST test", endpoint)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a TUS probe is necessary. OpenCloud always supports TUS(?).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Since the capabilities endpoint already advertises TUS for OpenCloud I removed the POST probe entirely and only evaluate the headers. If the OPTIONS call fails we now just return “unsupported” without firing any extra requests.

// TUS Upload-Metadata (decoded for debugging)
val filename = remotePath.substringAfterLast('/')
val mtime = (file.lastModified() / 1000).toString()
val checksum = "sha1 " + computeSha1(file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a sha1 computed here?
Is the checksum (sha256) not coming from the caller of this function?
Maybe I'm misunderstanding something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that was redundant. I removed the internal SHA‑1 and leave the checksum field to whatever the caller passes in the metadata (we still ensure filename + mtime defaults). The helper now simply forwards those values to the TUS POST.

"notNull": false
},
{
"fieldPath": "tusUploadOffset",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't look at this in detail, but does it make sense to have the Offset stored in the LOCAL db? Doesn't the server need to tell us what he received last?

Or is this related to multithreaded workers somehow and I dont understand it yet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...because the server has the definitie state of what it received before a disconenct/timeout/network issue. The clients view might be incorrect and further ahead or whatever

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I dropped the local tusUploadOffset field and always resume from the server state. The helper now calls GetTusUploadOffset (with our standard executeRemoteOperation) whenever we recover or resume, so we stay in sync with the backend


// Try to recover by re-checking current offset from server and continue
val recover = try {
val off = GetTusUploadOffsetRemoteOperation(tusUrl!!).execute(client)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do all those .execute calls not need to be wrapped into executeRemoteOperation(...) to get better exceptions?
Analog to the existing code..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I routed the head/creation/recover calls through executeRemoteOperation inside TusUploadHelper, so we still get the mapped exceptions while keeping the loop logic intact.

init {
require(chunkSize > 0) { "Chunk size must be greater than zero" }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the changes in this file about?

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 3, 2025

The old WebDAV chunking logic has been removed – we now only try TUS (if the file size is sufficient) and otherwise fall back to a simple PUT.
The TUS-specific upload logic is now located in TusUploadHelper, so that UploadFileFromFileSystemWorker and UploadFileFromContentUriWorker use the same path.
CheckTusSupportRemoteOperation works without hard-coded /remote.php replacements; the OPTIONS request goes directly to the upload collection, fallback PROBE removed.
The checksum now only uses the value provided by the caller; the internal SHA-1 code has been removed.
I deleted the local tusUploadOffset – when continuing, we query the server via GetTusUploadOffsetRemoteOperation.
All TUS requests run via executeRemoteOperation so that errors are mapped consistently as before.
The 404 in PATCH came from the incorrectly assembled upload path; the last commit also corrects this.

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 3, 2025

I think its problematic that removeLocal is set to true boolean, because the original file gets deleted after upload. I set it to false.

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 3, 2025

I have addressed the outstanding issues in the latest commits. Could you please take a look at the current overall status? The older commits now contain outdated changes.

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 3, 2025

image ups, sorry

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 24, 2025

@guruz Can u test again?

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 24, 2025

@guruz detekt should pass now.

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 24, 2025

@guruz

- Add TUS upload operations (create, chunk, offset check, support detection)
- Implement chunked upload with resume capability
- Add file list adapter, thumbnail requester, and file details improvements
- Fix unit test failures on Windows (path separator compatibility)
- Upgrade MockK to 1.13.13 for Java 21 support
- Add Gradle Version Catalog for dependency management
- Fix Detekt issues and build warnings
@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

settings local is for my IDE i committed it accidently.
@guruz test again with the latest commit, with gradle test, gradle detekt etc. Show me the logs then with gist again just like yesterday. But also, Before the last commit everything was green. Could we skip the test and detekt stuff and just test functionality, and we fix it in later PR?

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

Ok, its all green :)

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

Ups! I reverted. pushed to wrong branch :)

FloatingActionButton inflates our action icons without a themed Context. With targetSdk 34/35 the ?attr/colorControlNormal tint in the vectors cannot resolve and the app crashes during Splash/FileDisplayActivity startup (see unresolved theme attribute warnings). Remove the theme-dependent tint from ic_action_create_dir.xml, ic_action_create_file.xml, ic_action_open_shortcut.xml and let FAB apply its own tint. No code changes; verified with assembleDebug.
@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

@guruz I found the crash issue. Its solved now - for newer SDKs. So future crashes for other PRs won't happen. Please review and merge

@guruz
Copy link
Contributor

guruz commented Nov 25, 2025

I can confirm it works :) (hooray!)

One thing I notice in the log output is that it runs GetTusUploadOffsetRemoteOperation directly after CreateTusUploadRemoteOperation? Is the iOS and the desktop doing this the same way?
Intuitively I would have said it's not necessary because you know offset is 0 after creationwhatever was uploaded as create with upload?
In case iOS/Desktop don't do it like this: Please don't fix this in this PR, I would prefer to merge something than to have more changes now.

11-25 12:33:30.313  5756  7440 D (UploadFileFromContentUriWorker.kt:283): D: Attempting TUS upload (size=32212086, threshold=10240000, resume=false)
11-25 12:33:30.315  5756  7440 D (TusUploadHelper.kt:44): D: TUS: starting upload for /Test/opencloud-server-3.7.0-1.1.aarch64 (1).rpm size=32212086
11-25 12:33:30.317  5756  7440 D (TusUploadHelper.kt:58): D: TUS: creating upload resource filename=opencloud-server-3.7.0-1.1.aarch64 (1).rpm size=32212086 metadata={filename=opencloud-server-3.7.0-1.1.aarch64 (1).rpm, mimetype=rpm}
11-25 12:33:30.318  5756  7440 D (TusUploadHelper.kt:271): D: TUS: using collection endpoint: https://demo.opencloud.eu/dav/spaces/d21381aa-01dc-45cb-a5b8-e6880c47c954$baf1910c-04be-41bd-9c24-685871975b18
11-25 12:33:30.319  5756  7440 D (CreateTusUploadRemoteOperation.kt:53): D: TUS resolved collection: https://demo.opencloud.eu/dav/spaces/d21381aa-01dc-45cb-a5b8-e6880c47c954$baf1910c-04be-41bd-9c24-685871975b18/Test
11-25 12:33:30.320  5756  7440 D (CreateTusUploadRemoteOperation.kt:57): D: TUS Creation URL: https://demo.opencloud.eu/dav/spaces/d21381aa-01dc-45cb-a5b8-e6880c47c954$baf1910c-04be-41bd-9c24-685871975b18/Test
11-25 12:33:30.322  5756  7440 D (OpenCloudClient.java:129): D: Executing in request with id 1d183c28-670b-4473-ae5d-2f954c677582


11-25 12:33:31.532  5756  7444 D (AvailableOfflinePeriodicWorker.kt:48): I: Available offline files that needs to be synced: 0
11-25 12:33:31.536  5756  6182 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=28a5c967-976c-4f25-bc53-08bb2b37eb1e, tags={ eu.opencloud.android.workers.AvailableOfflinePeriodicWorker, AVAILABLE_OFFLINE_PERIODIC_WORKER } ]
11-25 12:33:32.558  5756  5756 W JobService: onNetworkChanged() not implemented in androidx.work.impl.background.systemjob.SystemJobService. Must override in a subclass.
11-25 12:33:32.913  5756  7440 D (CreateTusUploadRemoteOperation.kt:105): D: TUS Creation [https://demo.opencloud.eu/dav/spaces/d21381aa-01dc-45cb-a5b8-e6880c47c954$baf1910c-04be-41bd-9c24-685871975b18/Test] - 201
11-25 12:33:32.920  5756  7440 D (CreateTusUploadRemoteOperation.kt:139): D: TUS upload resource created: https://demo.opencloud.eu/data/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmV2YSJdLCJleHAiOjE3NjQxNTY4MTAsImlhdCI6MTc2NDA3MDQxMCwidGFyZ2V0IjoiaHR0cDovL2xvY2FsaG9zdDo5MTU4L2RhdGEvdHVzLzUxNzQ4MjQxLWQ0ZjQtNDViNy1hMDkxLWE1YjkyNzI4NTMwOSJ9.ONwiVN6rS-b8PEY9U4fY-l3zDYTzEonDq3vHINEJhiE
11-25 12:33:32.937  5756  7440 D (OpenCloudClient.java:129): D: Executing in request with id 14a73ecf-4ba2-47a3-afc2-36a37fc5fb15
11-25 12:33:32.978  5756  7440 D (GetTusUploadOffsetRemoteOperation.kt:28): D: Get TUS upload offset - 200


11-25 12:33:32.980  5756  7440 D (TusUploadHelper.kt:117): D: TUS: resume offset 10485760 / 32212086
11-25 12:33:32.983  5756  7440 D (TusUploadHelper.kt:167): D: TUS: uploading chunk=10000000 at offset=10485760 remaining=21726326
11-25 12:33:32.988  5756  7440 D (OpenCloudClient.java:129): D: Executing in request with id 5265e21e-38f1-4f9c-b4cb-5f435c5192e0


11-25 12:33:35.736  5756  7440 D (PatchTusUploadChunkRemoteOperation.kt:72): D: Patch TUS upload chunk via PatchMethod - 204


11-25 12:33:35.744  5756  7440 D (TusUploadHelper.kt:167): D: TUS: uploading chunk=10000000 at offset=20485760 remaining=11726326
11-25 12:33:35.756  5756  7440 D (OpenCloudClient.java:129): D: Executing in request with id 9b4df9d0-5cdf-4c0a-8256-dbc34baca1ca


11-25 12:33:38.177  5756  7440 D (PatchTusUploadChunkRemoteOperation.kt:72): D: Patch TUS upload chunk via PatchMethod - 204


11-25 12:33:38.180  5756  7440 D (TusUploadHelper.kt:167): D: TUS: uploading chunk=1726326 at offset=30485760 remaining=1726326
11-25 12:33:38.197  5756  7440 D (OpenCloudClient.java:129): D: Executing in request with id 22d06934-dc42-4735-b502-3885140c3677
11-25 12:33:38.600  5756  5756 W JobService: onNetworkChanged() not implemented in androidx.work.impl.background.systemjob.SystemJobService. Must override in a subclass.


11-25 12:33:38.838  5756  7440 D (PatchTusUploadChunkRemoteOperation.kt:72): D: Patch TUS upload chunk via PatchMethod - 204


11-25 12:33:38.851  5756  7440 D (TusUploadHelper.kt:146): I: TUS: upload completed for /Test/opencloud-server-3.7.0-1.1.aarch64 (1).rpm (size=32212086)
11-25 12:33:38.856  5756  7440 D (UploadFileFromContentUriWorker.kt:315): D: TUS upload completed for /Test/opencloud-server-3.7.0-1.1.aarch64 (1).rpm
11-25 12:33:38.869  5756  6182 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=ef9adc83-c79d-4cd7-9e20-a8c18bbc4a7c, tags={ eu.opencloud.android.workers.UploadFileFromContentUriWorker, dennis@demo.opencloud.eu, 2 } ]

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

Hi, u can merge this, and we can discuss later about this, is this fine?
I tried to make it similar to the web. Thefirst Request is a Post Request - a10MB Cunk, like the web does.
Or do u mean something else?

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

I can make a future PR if its really needed, but the risk ruining a almost 4k lines of Codebase change is too much, cuz the Code works fine now...

@kulmann
Copy link
Contributor

kulmann commented Nov 25, 2025

I hereby assign the copyright attribution for these changes to OpenCloud GmbH. You are welcome to list 'OpenCloud GmbH' in the file headers/license texts instead of my name.

Thank you for that. From my understanding it's not even needed - all of the code is automatically GPL because of copyleft. OpenCloud doesn't do dual licensing (gpl + commercial or something similar), so from my understanding everything is already good, even without your comment.

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

I hereby assign the copyright attribution for these changes to OpenCloud GmbH. You are welcome to list 'OpenCloud GmbH' in the file headers/license texts instead of my name.

Thank you for that. From my understanding it's not even needed - all of the code is automatically GPL because of copyleft. OpenCloud doesn't do dual licensing (gpl + commercial or something similar), so from my understanding everything is already good, even without your comment.

Okay - I am confused because i see a lot of "Owncloud" and "Author" names :) But its ur choice, feel free

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 25, 2025

@guruz I checked the code (
propagateuploadtus.cpp
) and you are right. It does not perform a HEAD request immediately after POST. It reads the Upload-Offset directly from the 201 Created response headers.

So the Android implementation can indeed be optimized here, but as you suggested, let's do that in a follow-up PR to keep this one focused.

@kulmann
Copy link
Contributor

kulmann commented Nov 26, 2025

Okay - I am confused because i see a lot of "Owncloud" and "Author" names :) But its ur choice, feel free

we're just not allowed to remove them from the fork. we don't need them for ourselves afaik.

@guruz
Copy link
Contributor

guruz commented Nov 26, 2025

but as you suggested, let's do that in a follow-up PR to keep this one focused.

Yes 100% please keep this PR as it is.
I will merge it today/tomorrow. Sorry this all takes longer than expected ... thank you for your contribution!

@zerox80
Copy link
Contributor Author

zerox80 commented Nov 26, 2025

but as you suggested, let's do that in a follow-up PR to keep this one focused.

Yes 100% please keep this PR as it is. I will merge it today/tomorrow. Sorry this all takes longer than expected ... thank you for your contribution!

Would be good if u could do it very soon, because 2 other PRs can be rebased to the main branch then so i can detekt and test the codes much better so it works next time out of box for u ^^

@guruz guruz merged commit 0db2c87 into opencloud-eu:main Nov 26, 2025
3 checks passed
@guruz
Copy link
Contributor

guruz commented Dec 1, 2025

For some other reason, i just started a current apk on an emulator i already had opencloud on.
I'm getting this https://gist.github.com/guruz/a313e97d03c58ead427051128d8d1c14
Since the error is in OCTransferEntity i'm thinking we broke something

@guruz
Copy link
Contributor

guruz commented Dec 1, 2025

Not sure 100% yet, but can it be that https://github.com/opencloud-eu/android/pull/36/files#diff-9f289054dcdd01f9adb4859d64ffff91098241a246f4778846ede49f19aeb3f2 misses the migrations for
tusUploadExpires

tusResumableVersion

tusUploadLength

tusUploadUrl

tusUploadConcat

tusUploadChecksum

tusUploadMetadata

maybe more

@zerox80
Copy link
Contributor Author

zerox80 commented Dec 1, 2025

I have fixed the crash by adding the missing migration steps for the transfers table in Migration_48.kt. I also created a test MigrationToDB48Test.kt and verified that the migration works correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants