A thumbnail is the one derived artefact worth sending over the wire: it costs a range fetch plus a decode to produce and is identical for every client looking at the same file. A second device that downloads a shard gets a full grid without fetching a byte of RAW. Sharded at 25 MB, filled sequentially. The cap is about sync granularity, not SQLite's limits — one growing database means every client re-downloads it whenever a single thumbnail is added, whereas with sequential fill only the newest shard is ever dirty and sealed shards are safe to cache forever. Stored JPEG-encoded rather than as raw RGBA: a 256px RGBA buffer is ~256 KB against ~20 KB encoded, and that 13x is transfer cost on every client. Keyed on Nextcloud's oc:fileid, stable across server-side rename and move. Assisted-by: LLM
138 lines
5.2 KiB
TOML
138 lines
5.2 KiB
TOML
[workspace]
|
||
resolver = "2"
|
||
members = [
|
||
"core/dr-types",
|
||
"core/dr-catalog",
|
||
"core/dr-thumbs",
|
||
"core/dr-decode",
|
||
"core/dr-gpu",
|
||
"core/dr-lens",
|
||
"core/dr-pipeline",
|
||
"core/dr-sync",
|
||
"core/dr-sync-nextcloud",
|
||
"platform/dr-plat",
|
||
"ui/dr-ui",
|
||
"apps/darkroom-desktop",
|
||
"tools/traceability",
|
||
]
|
||
|
||
[workspace.package]
|
||
version = "0.1.0"
|
||
edition = "2021"
|
||
rust-version = "1.92"
|
||
license = "GPL-3.0-or-later"
|
||
repository = "https://github.com/dtourolle/DarkRoom"
|
||
|
||
[workspace.dependencies]
|
||
# Internal
|
||
dr-types = { path = "core/dr-types" }
|
||
dr-catalog = { path = "core/dr-catalog" }
|
||
dr-thumbs = { path = "core/dr-thumbs" }
|
||
dr-decode = { path = "core/dr-decode" }
|
||
dr-gpu = { path = "core/dr-gpu" }
|
||
dr-lens = { path = "core/dr-lens" }
|
||
dr-pipeline = { path = "core/dr-pipeline" }
|
||
dr-plat = { path = "platform/dr-plat" }
|
||
dr-sync = { path = "core/dr-sync" }
|
||
dr-sync-nextcloud = { path = "core/dr-sync-nextcloud" }
|
||
dr-ui = { path = "ui/dr-ui" }
|
||
|
||
# GPU + UI
|
||
wgpu = "23"
|
||
slint = { version = "1.9", default-features = false }
|
||
slint-build = "1.9"
|
||
|
||
# UI token codegen (S2): style.yaml -> theme.slint. serde_yaml was deprecated
|
||
# by its maintainer in 2024 and serde_yml, the first fork, has since been
|
||
# deprecated too; serde_norway is the fork still receiving releases. Its
|
||
# mappings preserve insertion order, which is what lets the generated Slint
|
||
# keep the token ordering the YAML author chose.
|
||
serde_norway = "0.9"
|
||
|
||
# Foundations
|
||
anyhow = "1"
|
||
thiserror = "2"
|
||
log = "0.4"
|
||
env_logger = "0.11"
|
||
pollster = "0.4"
|
||
|
||
# Networking — no mature Nextcloud crate exists; the connector is hand-rolled
|
||
# over reqwest (D7). reqwest_dav was evaluated and is too thin to build on.
|
||
# `rustls-no-provider` rather than `rustls`: the latter defaults to the
|
||
# aws-lc-rs crypto provider, whose aws-lc-sys crate is C and fails to
|
||
# cross-compile for Android — precisely the NDK pain D1 chose Rust to avoid.
|
||
# ring is pure Rust apart from a small asm core that does build under the NDK.
|
||
#
|
||
# Note this still pulls rustls-platform-verifier, which crashes on Android
|
||
# unless initialised from Kotlin (spike S3). D7 records `tls_certs_only` plus
|
||
# webpki-roots as the escape hatch.
|
||
reqwest = { version = "0.13", default-features = false, features = ["rustls-no-provider", "stream", "json"] }
|
||
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
|
||
quick-xml = "0.41"
|
||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time"] }
|
||
url = "2.5"
|
||
async-trait = "0.1"
|
||
serde = { version = "1", features = ["derive"] }
|
||
serde_json = "1"
|
||
base64 = "0.23"
|
||
|
||
# Platform secure storage: Secret Service on Linux, Keystore on Android
|
||
# (FR-NC-2). Credentials never touch the catalog or a plain file.
|
||
# keyring 4 restructured its features: `v1` is the default set and brings
|
||
# the zbus Secret Service backend, which is what GNOME Keyring and KWallet
|
||
# (via ksecretd) both speak.
|
||
keyring = { version = "4", features = ["v1"] }
|
||
|
||
# Decode. rawler is the pure-Rust decoder (D2); zune-jpeg decodes the
|
||
# embedded previews rawler extracts.
|
||
# Catalog. `bundled` compiles SQLite from source rather than linking the
|
||
# system library — the same cross-compilation reasoning as the TLS choice
|
||
# above: no system dependency to satisfy under the Android NDK.
|
||
#
|
||
# `backup` is not optional in practice: it is what takes a consistent snapshot
|
||
# of a live WAL database for upload. A filesystem copy of `catalog.sqlite`
|
||
# while a `-wal` exists beside it uploads a torn file.
|
||
rusqlite = { version = "0.40", features = ["bundled", "backup"] }
|
||
|
||
rawler = "0.7"
|
||
zune-jpeg = "0.4.21"
|
||
# Thumbnails are stored encoded, not as raw RGBA: a 256px RGBA buffer is
|
||
# ~256 KB against ~20 KB as JPEG, and the store syncs to Nextcloud where that
|
||
# 13× is transfer cost on every client. Pure Rust, no C dependency — the same
|
||
# criterion behind the TLS and SQLite choices above.
|
||
jpeg-encoder = "0.7"
|
||
bytemuck = { version = "1", features = ["derive"] }
|
||
|
||
# Lens correction profiles. A pure-Rust port of Lensfun rather than a binding
|
||
# to the C library, for the same cross-compilation reason as the TLS and
|
||
# SQLite choices above: liblensfun would be a third C dependency to satisfy
|
||
# under the Android NDK.
|
||
#
|
||
# The database ships *inside* the crate — 56 XML files, gzipped at build time
|
||
# and decompressed on first lookup. That matters beyond convenience: Android
|
||
# gives us no filesystem path (ARCH §6.9), so a database loaded from a
|
||
# system directory would have nowhere to live there.
|
||
#
|
||
# Licence: LGPL-3.0-or-later, which upgrades cleanly into our GPLv3 (D8).
|
||
# The upstream Lensfun *database* is CC-BY-SA and is redistributed by the
|
||
# crate; attribution belongs in the about screen.
|
||
#
|
||
# Caveat worth remembering: this is a third-party port at 0.7.0, not upstream
|
||
# Lensfun. Verified working against the bundled database (interpolation
|
||
# between calibration points, and an unknown lens returning empty rather than
|
||
# panicking), but the pipeline talks to it through its own profile types so
|
||
# swapping it out is not a pipeline change.
|
||
lensfun = "0.7"
|
||
|
||
[profile.dev]
|
||
# Dependencies optimised even in dev builds — wgpu and image decoding are
|
||
# unusably slow otherwise, and they rarely need debugging.
|
||
opt-level = 0
|
||
|
||
[profile.dev.package."*"]
|
||
opt-level = 2
|
||
|
||
[profile.release]
|
||
lto = "thin"
|
||
codegen-units = 1
|