Describe albums, the folder pickers and download progress in the designs
storage.md's trait listing stopped at get; it now has get_reporting, what the default and the Nextcloud override do, and where develop reads the figures. A new §5.3 says how folders are chosen — the portal or Windows dialogue, the server browser whose New folder is create_dir, SAF on Android — and where an album's files go: a server folder relative to the account root, with the outbox's third .dest line, or a device folder that never syncs. catalog.md §8.2 said only collections merge, which had not been true since keywords, people and capture metadata joined them, and is less true with albums; it now lists what merges and why album_folders does not. §2 records that the album tables, like dedup_probes, are made on first use rather than by a migration. outstanding.md said there was no SAF code on Android. There is now, for album folders only, and it carries TRACES: FR-PLAT-AND-1, which the entry says overstates a requirement about the library; FR-PLAT-AND-2 and S10's row follow from that.
This commit is contained in:
+56
-2
@@ -85,6 +85,9 @@ pub trait RemoteBackend: Send + Sync {
|
||||
// transfer
|
||||
async fn get(&self, id: &RemoteId, range: Option<Range<u64>>)
|
||||
-> Result<Vec<u8>, RemoteError>;
|
||||
async fn get_reporting(&self, id: &RemoteId, // defaulted
|
||||
progress: &(dyn Fn(u64, Option<u64>) + Send + Sync))
|
||||
-> Result<Vec<u8>, RemoteError>;
|
||||
async fn put(&self, path: &RemotePath, body: Vec<u8>, precond: Option<Precondition>)
|
||||
-> Result<Validator, RemoteError>;
|
||||
async fn put_many(&self, items: Vec<(RemotePath, Vec<u8>)>) // defaulted
|
||||
@@ -111,6 +114,16 @@ Rules that are not obvious from the signatures:
|
||||
- **`get` takes an optional range, and it is a hint.** A backend without cheap
|
||||
ranges may return the whole object; the caller slices. Correctness holds
|
||||
either way and `Capabilities::range_reads` says whether it was cheap.
|
||||
- **`get_reporting` is for the one transfer somebody is watching.** An original
|
||||
opened in develop is tens of megabytes, and "downloading" alone for that long
|
||||
reads as stuck. It reports the bytes received and the length the server
|
||||
declared, if it declared one. The default is `get` whole and one report at the
|
||||
end, which is right for a backend whose read is local; Nextcloud overrides it
|
||||
to read the body chunk by chunk. The develop view reads the figures by path
|
||||
from the in-flight registry in `ui/dr-ui/src/library/thumbnails_fetch.rs`,
|
||||
because a step along the roll usually lands on a frame the prefetcher is
|
||||
already fetching, and falls back on the catalog's file length when no length
|
||||
was declared.
|
||||
- **Chunked upload is not in the trait.** It is an implementation detail of
|
||||
`put`, chosen by body size. Exposing it would leak one server's protocol.
|
||||
- **`move_to` must preserve identity where the backend has stable ids.** This
|
||||
@@ -118,7 +131,9 @@ Rules that are not obvious from the signatures:
|
||||
allocates a new id, orphaning the thumbnail shard and turning a restore into a
|
||||
full re-download.
|
||||
- **`create_dir` makes parents and succeeds if the directory exists.** Callers
|
||||
use it to guarantee a destination, not to claim they created one.
|
||||
use it to guarantee a destination, not to claim they created one. It is also
|
||||
the server browser's `New folder` (§5.3), which then lists the parent again
|
||||
rather than inserting the name it asked for: the server may have normalised it.
|
||||
|
||||
### 3.2 `Capabilities` — what is cheap
|
||||
|
||||
@@ -294,6 +309,7 @@ for a second backend:
|
||||
| `bulk_upload` | yes, `POST /remote.php/dav/bulk` |
|
||||
| `conditional_write` | yes, `If-Match` |
|
||||
| `server_previews` | `CommonFormatsOnly` — stock Nextcloud renders no RAW |
|
||||
| `get_reporting` | overridden: the body is read chunk by chunk, against `Content-Length` |
|
||||
| sign-in | `SignIn::Browser`, Login Flow v2, system browser, app password |
|
||||
|
||||
Also kept: the `oc:permissions` probe on a refused `PUT`, which is what
|
||||
@@ -315,7 +331,8 @@ which makes it the route that works on a machine with no secrets daemon at all.
|
||||
| `bulk_upload` | no |
|
||||
| `conditional_write` | yes, with a documented residual race |
|
||||
| `server_previews` | `None` |
|
||||
| sign-in | `SignIn::EndpointOnly` |
|
||||
| `get_reporting` | the default: a local read, reported once when it is done |
|
||||
| sign-in | `SignIn::EndpointOnly`, the folder chosen in the platform's dialogue (§5.3) |
|
||||
|
||||
**Why `LocalEtags` and not `PropagatingEtags`.** A POSIX directory's mtime
|
||||
changes when its own entry list changes and at no other time — not when a
|
||||
@@ -377,6 +394,43 @@ behind a network banner. An endpoint that is not a directory at all maps to
|
||||
`RemoteError::Configuration`: nothing was unreachable and no credential was
|
||||
wrong, so neither of the other two would send the user anywhere useful.
|
||||
|
||||
### 5.3 Choosing folders, and the folders exports go to
|
||||
|
||||
**Folders are pointed at, never typed** (FR-EXP-6). On the desktop,
|
||||
`ui/dr-ui/src/folder_dialog.rs` asks the platform: the XDG desktop portal's
|
||||
FileChooser on Linux, through `rfd`, and the common item dialogue on Windows.
|
||||
That is how the folder connector's endpoint is chosen on the launch screen, and
|
||||
the path it returns still goes through `normalise_endpoint` as a typed one did.
|
||||
A folder on the server is chosen in the in-app browser, which lists with `list`
|
||||
and makes a folder with `create_dir`; the launch screen and the album sheet
|
||||
share it through `ui/dr-ui/src/remote_folders.rs`, which keeps both round trips
|
||||
off the interface thread. Android has no filesystem dialogue, so its library
|
||||
folder is still typed, and an album's folder there comes from the Storage
|
||||
Access Framework's tree picker.
|
||||
|
||||
**An album is where exports go** (FR-EXP-10), and never inside the library: a
|
||||
JPEG written into the tree a scan catalogues comes back as a photograph beside
|
||||
the RAW it was made from. Its folder is one of two kinds
|
||||
(`dr_catalog::albums::Place`):
|
||||
|
||||
- **On the server,** relative to the *account* root, not the library root. The
|
||||
browser refuses a folder inside the library and says why; on a server whose
|
||||
whole account is the library, every folder is inside it, and it says that
|
||||
instead. Exports reach it through the outbox like any upload, and a queued
|
||||
file's `.dest` record gains a third line saying its folder is relative to
|
||||
the account — a third line rather than a leading slash, because a record
|
||||
written before albums may carry a stray slash and has to keep the meaning it
|
||||
was written with.
|
||||
- **On this device,** a path, or on Android a SAF tree URI with a persisted
|
||||
grant, written through `DocumentsContract` (`ui/dr-ui/src/saf.rs`). A
|
||||
provider renames on a collision by itself, so the album records the name it
|
||||
was given rather than the one asked for.
|
||||
|
||||
A server folder lives on the album row and syncs with it. A device folder lives
|
||||
in `album_folders`, which the merge never reads and the upload snapshot drops,
|
||||
because a path or a grant on one device means nothing on another: an album made
|
||||
on the desktop arrives on the tablet with no folder until one is chosen there.
|
||||
|
||||
---
|
||||
|
||||
## 6. Virtual filesystems
|
||||
|
||||
Reference in New Issue
Block a user