Data Directory Layout¶
All persistent application data lives next to the executable. This is a portable layout — moving the .app bundle moves all its data with it. The paths are centralized in src-tauri/src/app_paths.rs.
Source: src-tauri/src/app_paths.rs
Layout¶
{exe_dir}/
rutracker/
session.json reqwest cookie jar (Base64 JSON)
meta.json username, avatar data URL, active mirror
proxy.txt HTTP proxy URL (one line, optional)
covers/ torrent post cover art disk cache
webview/ WebView2 data directory (login window)
soulseek/
creds.json login credentials { username, password }
covers/ SoulSeek peer cover art disk cache
bt/ (debug builds: dev/bt/)
torrent/ librqbit session state (export downloads)
covers/ librqbit cover art session
vozduxan/ vozduxan C++ libtorrent session state
cache_settings.json cache size limits and TTL overrides
app_debug.json debug log ring buffer (persisted on exit)
general-list.json debug track registry (every seen track)
likes.json liked track IDs array
dev/ debug builds only
bt/torrent|covers|vozduxan/ isolated dev streaming sessions
dumps/ search dump snapshots
Debug builds use dev/bt/ instead of bt/ so development libtorrent sessions (with their accumulated piece cache and peer lists) do not contaminate the production data on the same machine.
Path helpers¶
Every path in the application is obtained through a helper in app_paths.rs. Adding a new file requires adding a helper there — never hardcode a path string in any other module.
fn base(_app: &AppHandle) -> Result<PathBuf, String> {
let exe = std::env::current_exe()?;
exe.parent()
.ok_or_else(|| "executable has no parent directory".to_string())
.map(|p| p.to_path_buf())
}
base() is the executable directory. All other helpers build on it:
// RuTracker
pub fn rt_session_path(app: &AppHandle) -> Result<PathBuf, String> {
Ok(rt_dir(app)?.join("session.json"))
}
// BitTorrent (debug vs release)
pub fn bt_vozduxan_dir(app: &AppHandle) -> Result<PathBuf, String> {
Ok(bt_base_dir(app)?.join("vozduxan"))
}
pub fn bt_base_dir(app: &AppHandle) -> Result<PathBuf, String> {
let b = base(app)?;
Ok(if cfg!(debug_assertions) {
b.join("dev").join("bt")
} else {
b.join("bt")
})
}
Notable files¶
session.json¶
reqwest cookie jar in JSON format. Used by the RuTracker HTTP client to persist the phpBB session cookie across app restarts. On startup, rutracker_restore_session validates the cookies are still valid by making a live request; if not, it clears the file and returns logged-out state.
meta.json¶
{
"username": "user123",
"avatar_data_url": "data:image/jpeg;base64,...",
"mirror": "rutracker.org"
}
The avatar is stored as a data URL because the WebView does not share cookies with the Rust HTTP client — loading the avatar URL directly would return a 403. Rust fetches it on login and serializes to base64.
vozduxan/¶
libtorrent session state: resume data for all known torrents, the DHT routing table, and the piece cache. This directory can grow large for users who stream many different albums. The cache size and TTL are configurable via cache_settings.json and enforced by vozduxan_session_evict.
general-list.json¶
A debug registry that records every track entity the app has ever seen. Written by general_list_write (Rust) via the general_list_append Tauri command. Used to reconstruct session history for debugging — not part of the normal user-facing feature set.
macOS app bundle note¶
On macOS, std::env::current_exe() returns the path inside the .app bundle:
So bt/vozduxan/ lives at:
This is intentional — data travels with the bundle. The bundle's Contents/MacOS/ directory is writable by the owning user on macOS (unlike Contents/Resources/).