Support requesting VFS hydration; fix Android TLS cross-compilation
Correcting the previous commit: I claimed VFS placeholders could not be
downloaded. That was wrong. The desktop client exposes a socket at
$XDG_RUNTIME_DIR/Nextcloud/socket speaking newline-delimited
COMMAND:argument, and MAKE_AVAILABLE_LOCALLY:<path> does fetch the file.
Verified against client 4.0.7: a 1-byte stub became a real 2.8MB file in
2.8 seconds.
Implemented as dr-sync-nextcloud::desktop_client, deliberately optional.
Android has no desktop client, no XDG_RUNTIME_DIR socket and no
placeholders, so detect() returns None there and callers fall back to the
connector. It earns its place only because it is ~30 lines with no
dependencies: where a library already lives in a VFS folder, asking the
client to fetch beats downloading a second copy over WebDAV and leaving
the client's placeholder state inconsistent.
What this does not change: hydration is whole-file, so it suits the
original tier and never browsing. Filling a grid this way downloads the
entire library. Range extraction remains the only mechanism satisfying
FR-NC-3, and ARCH §9.0 now says so precisely.
Also fixes two real Android build failures found by cross-compiling:
- reqwest's `rustls` feature defaults to aws-lc-rs, whose aws-lc-sys
crate is C and fails under the NDK — exactly the pain D1 chose Rust
to avoid. Switched to rustls-no-provider + ring, installing the
provider in the constructor so no caller can build a client that
panics on first use.
- ring itself needs CC/AR per target; cargo-ndk sets only the linker.
Added them to the container.
87 tests passing. dr-sync-nextcloud cross-compiles for aarch64-linux-android.
This commit is contained in:
+24
-8
@@ -679,20 +679,36 @@ Three findings, each independently disqualifying:
|
||||
`IMG.CR2.nextcloud` exists, containing exactly one byte. Any extension-based scan sees
|
||||
`.nextcloud`, so the app needs placeholder-aware code regardless — VFS is not transparent.
|
||||
|
||||
2. **Reads do not hydrate.** Reading the stub returns its 1 byte and nothing else; no fetch is
|
||||
triggered, the stub is unchanged, and the real name never appears. Suffix mode is an inert
|
||||
marker, not a filesystem hook — there is no FUSE layer intercepting reads. Hydration happens
|
||||
only when the *client* is instructed to sync that file. **DarkRoom cannot read through a
|
||||
placeholder at all.**
|
||||
2. **Reads do not hydrate, but hydration can be *requested*.** Reading a stub returns its one byte
|
||||
and triggers nothing — there is no FUSE layer intercepting reads. However the client exposes a
|
||||
local socket at `$XDG_RUNTIME_DIR/Nextcloud/socket` speaking a newline-delimited
|
||||
`COMMAND:argument` protocol, and `MAKE_AVAILABLE_LOCALLY:<path>` does fetch the file.
|
||||
**Verified 2026-08-09:** a 1-byte `.nextcloud` stub was replaced by the real 2.7 MB file within
|
||||
seconds. `MAKE_ONLINE_ONLY` dehydrates again.
|
||||
|
||||
3. **Even with hydration, granularity is wrong.** VFS has two states, 1 byte or all bytes. The
|
||||
preview tier — the one that makes remote browsing viable on mobile data — needs a ~256 KB prefix
|
||||
of a 27 MB file. A hydrating VFS would transfer ~100× what FR-NC-3 requires, which is precisely
|
||||
the cost range extraction exists to avoid.
|
||||
|
||||
Coexistence is still fine and worth supporting: a user may keep a VFS-synced folder, and DarkRoom
|
||||
should recognise `*.nextcloud` stubs and report those images as `Availability::Offline` (FR-NC-6c)
|
||||
rather than as corrupt files. What it must not do is depend on VFS for transfer.
|
||||
**What this changes, and what it does not.** Hydration-on-request makes VFS a usable *original*
|
||||
tier: for an image the user opens in develop or exports, asking the client to fetch it is a
|
||||
legitimate alternative to fetching it ourselves, and it inherits their transfer, resume and
|
||||
conflict handling for free.
|
||||
|
||||
It does **not** rescue the preview tier, which is the one that matters for browsing. Finding 3
|
||||
stands: hydration is whole-file, so filling a grid still costs the entire library. Range extraction
|
||||
remains the only mechanism that satisfies FR-NC-3.
|
||||
|
||||
**Design consequence.** VFS is supported as an optional *source*, not as the transfer layer:
|
||||
|
||||
- Recognise `*.nextcloud` stubs and report them as `Availability::Offline` (FR-NC-6c) rather than
|
||||
as corrupt files.
|
||||
- Where a library lives under a VFS-synced folder, offer "download" on a stub by writing
|
||||
`MAKE_AVAILABLE_LOCALLY:<path>` to the socket, rather than fetching a second copy over WebDAV and
|
||||
leaving the client's own state inconsistent.
|
||||
- Never depend on it: the socket is Linux-only, absent on Android, and absent when the client is
|
||||
not running. The direct connector remains the primary path.
|
||||
|
||||
### 9.1 The three tiers, restated as policy
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| Source files scanned | 23 |
|
||||
| TRACES tags found | 30 |
|
||||
| Source files scanned | 25 |
|
||||
| TRACES tags found | 31 |
|
||||
| Requirements defined | 143 |
|
||||
| Requirements covered | 32 |
|
||||
| **Coverage** | **22.4%** (32/143) |
|
||||
@@ -37,18 +37,18 @@ _None._
|
||||
| FR-CAT-1a | [`core/dr-types/src/lib.rs:23`](../core/dr-types/src/lib.rs#L23) |
|
||||
| FR-CAT-2 | [`tools/traceability/src/lib.rs:473`](../tools/traceability/src/lib.rs#L473) |
|
||||
| FR-CAT-5 | [`core/dr-decode/src/lib.rs:125`](../core/dr-decode/src/lib.rs#L125) |
|
||||
| FR-CAT-9 | [`core/dr-types/src/lib.rs:80`](../core/dr-types/src/lib.rs#L80) |
|
||||
| FR-CAT-9 | [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-types/src/lib.rs:80`](../core/dr-types/src/lib.rs#L80) |
|
||||
| FR-CULL-1 | [`core/dr-decode/src/preview.rs:96`](../core/dr-decode/src/preview.rs#L96) |
|
||||
| FR-CULL-2 | [`core/dr-decode/src/preview.rs:123`](../core/dr-decode/src/preview.rs#L123) |
|
||||
| FR-DEV-4 | [`core/dr-gpu/src/lib.rs:119`](../core/dr-gpu/src/lib.rs#L119) |
|
||||
| FR-DSP-1 | [`ui/dr-ui/src/lib.rs:21`](../ui/dr-ui/src/lib.rs#L21) |
|
||||
| FR-EXP-9 | [`core/dr-decode/src/lib.rs:151`](../core/dr-decode/src/lib.rs#L151) |
|
||||
| FR-NC-1 | [`core/dr-sync-nextcloud/src/auth.rs:132`](../core/dr-sync-nextcloud/src/auth.rs#L132), [`core/dr-sync-nextcloud/src/auth.rs:44`](../core/dr-sync-nextcloud/src/auth.rs#L44) |
|
||||
| FR-NC-12 | [`core/dr-sync-nextcloud/src/lib.rs:30`](../core/dr-sync-nextcloud/src/lib.rs#L30), [`core/dr-sync/src/lib.rs:128`](../core/dr-sync/src/lib.rs#L128), [`core/dr-sync/src/lib.rs:34`](../core/dr-sync/src/lib.rs#L34) |
|
||||
| FR-NC-12 | [`core/dr-sync-nextcloud/src/lib.rs:32`](../core/dr-sync-nextcloud/src/lib.rs#L32), [`core/dr-sync/src/lib.rs:128`](../core/dr-sync/src/lib.rs#L128), [`core/dr-sync/src/lib.rs:34`](../core/dr-sync/src/lib.rs#L34) |
|
||||
| FR-NC-3 | [`core/dr-decode/src/preview.rs:123`](../core/dr-decode/src/preview.rs#L123), [`core/dr-sync/src/capability.rs:41`](../core/dr-sync/src/capability.rs#L41) |
|
||||
| FR-NC-4 | [`core/dr-sync-nextcloud/src/propfind.rs:100`](../core/dr-sync-nextcloud/src/propfind.rs#L100), [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51), [`core/dr-sync/src/capability.rs:6`](../core/dr-sync/src/capability.rs#L6), [`core/dr-sync/src/lib.rs:128`](../core/dr-sync/src/lib.rs#L128) |
|
||||
| FR-NC-5 | [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51) |
|
||||
| FR-NC-6c | [`core/dr-types/src/lib.rs:131`](../core/dr-types/src/lib.rs#L131), [`core/dr-types/src/lib.rs:80`](../core/dr-types/src/lib.rs#L80) |
|
||||
| FR-NC-6c | [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-types/src/lib.rs:131`](../core/dr-types/src/lib.rs#L131), [`core/dr-types/src/lib.rs:80`](../core/dr-types/src/lib.rs#L80) |
|
||||
| FR-PLAT-AND-1 | [`core/dr-types/src/lib.rs:23`](../core/dr-types/src/lib.rs#L23) |
|
||||
| FR-RAW-1 | [`core/dr-decode/src/lib.rs:83`](../core/dr-decode/src/lib.rs#L83), [`core/dr-types/src/lib.rs:90`](../core/dr-types/src/lib.rs#L90) |
|
||||
| FR-RAW-3 | [`core/dr-decode/src/lib.rs:151`](../core/dr-decode/src/lib.rs#L151) |
|
||||
|
||||
Reference in New Issue
Block a user