Use a shared API request limiter across recursive upload and
download traversal so folder detail fetches, file listings,
folder auth, and transfers can run concurrently under one
budget.
Refactor the traversal loops into task-driven pipelines while
preserving skip-if-exists, excludes, cleanup, and current
output behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move token refresh checks into the shared Rust connection/API path so long-running authenticated operations stop reusing stale access tokens. This covers recursive download and upload traversal, recursive ls via the shared APIs, and direct authenticated commands such as cp, mv, rm, and chacl.
Also surface HTTP failures earlier in the affected API methods instead of failing later during response parsing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 5: Replace all Box<dyn Error> return types with anyhow::Result<T>
throughout the codebase. Replace string-based Err("msg".into()) and
format!().into() patterns with bail!() and anyhow!() macros. Fix
dirs::home_dir().unwrap() in settings.rs to use a fallback path instead
of panicking when HOME is unset. Remove stray use std::error::Error
imports no longer needed.
Phase 6: Add From<&User> for CacheUser in models/user.rs and
From<&Laboratory>/From<&Laboratories> for CacheLaboratory/CacheLabsWrapper
in models/laboratory.rs. Simplify commands/login.rs to use .into()
conversions, removing the redundant to_cache_user() and to_cache_labs()
helper functions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The access token obtained at command startup could expire during a long
transfer session (e.g. uploading thousands of files or large files),
causing subsequent requests to fail with 401 Unauthorized.
Root cause: load_cache_with_token_refresh was called only once, and the
resulting MDRSConnection — including its now-stale token — was shared
across all parallel tasks via Arc. There was no mechanism to update the
token in the shared instance after creation.
Fix:
- Add MDRSConnection::with_token(&self, token) that creates a new
connection struct reusing the caller's HTTP client (cheap Arc clone,
shares the connection pool) but carrying a fresh Bearer token.
- In upload.rs and download.rs, call load_cache_with_token_refresh
inside each tokio::spawn task body, then create a task-local
connection via conn.with_token(fresh_token) before transferring the
file. The shared reqwest::Client (connection pool) is preserved.
cp.rs is not changed: it uses only short server-side API calls with no
parallel tasks, so token expiry during a cp operation is negligible.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>