mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
refactor: extract psysonic-syncfs crate (M4/7)
Moves all on-disk cache + device-sync code out of the top crate:
crates/psysonic-syncfs/ new lib crate
src/cache/{offline,hot,downloads,fs_utils} unchanged behaviour
src/sync/{batch,device} (no tray.rs — that's UI)
src/file_transfer.rs shared HTTP helpers
src/lib.rs + DownloadSemaphore type
+ sync_cancel_flags fn
The shell crate keeps `lib_commands/sync/tray.rs` (OS tray icon — UI
concern, will move to shell-tauri at M7) but drops the rest of
`lib_commands/cache/` and the syncfs sibling files.
Tauri command quirk surfaced and resolved: `#[tauri::command]` puts its
`__cmd__*` and `__tauri_command_name_*` helper macros at the *exact*
module of the function, and `pub use` doesn't carry them across module
boundaries. invoke_handler! in lib.rs now references each syncfs
command via its full deepest path
(`psysonic_syncfs::cache::offline::download_track_offline`, etc.) so
Tauri's macros resolve at the right scope. Same approach the audio
crate already uses (`audio::commands::audio_play`).
Cross-crate ref migrations applied via batch sed:
crate::audio::* → psysonic_audio::*
crate::analysis_runtime::* → psysonic_analysis::analysis_runtime::*
crate::analysis_cache::* → psysonic_analysis::analysis_cache::*
crate::subsonic_wire_user_agent → psysonic_core::user_agent::*
super::super::file_transfer:: → crate::file_transfer::
Behaviour preserving. Cargo check + clippy --workspace clean.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
use std::path::Path;
|
||||
|
||||
/// Recursively sums the size of all files under `root`.
|
||||
/// Missing roots, unreadable directories, and unreadable files are silently skipped.
|
||||
pub fn dir_size_recursive(root: &Path) -> u64 {
|
||||
if !root.exists() {
|
||||
return 0;
|
||||
}
|
||||
let mut total: u64 = 0;
|
||||
let mut stack = vec![root.to_path_buf()];
|
||||
while let Some(dir) = stack.pop() {
|
||||
let rd = match std::fs::read_dir(&dir) {
|
||||
Ok(r) => r,
|
||||
Err(_) => continue,
|
||||
};
|
||||
for entry in rd.flatten() {
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
stack.push(path);
|
||||
} else if let Ok(meta) = std::fs::metadata(&path) {
|
||||
total += meta.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
total
|
||||
}
|
||||
|
||||
/// Walks upward from `start_dir`, removing each empty directory using `remove_dir`
|
||||
/// (never `remove_dir_all`). Stops as soon as a non-empty directory is hit, the
|
||||
/// boundary is reached, or removal fails.
|
||||
///
|
||||
/// `boundary` is never removed and is treated as a hard stop. If `start_dir` is
|
||||
/// not under `boundary`, the function is a no-op.
|
||||
pub fn prune_empty_dirs_up_to(start_dir: &Path, boundary: &Path) {
|
||||
let mut current = Some(start_dir.to_path_buf());
|
||||
while let Some(dir) = current {
|
||||
if dir == boundary || !dir.starts_with(boundary) {
|
||||
break;
|
||||
}
|
||||
match std::fs::read_dir(&dir) {
|
||||
Ok(mut entries) => {
|
||||
if entries.next().is_some() {
|
||||
break;
|
||||
}
|
||||
if std::fs::remove_dir(&dir).is_err() {
|
||||
break;
|
||||
}
|
||||
current = dir.parent().map(|p| p.to_path_buf());
|
||||
}
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user