1use std::path::{Path, PathBuf};
2
3use anyhow::{Context, Result};
4
5const APP_NAME: &str = "speakers";
6const LEGACY_APP_NAME: &str = "speake-rs";
7
8fn home_dir() -> PathBuf {
9 std::env::var("HOME")
10 .map(PathBuf::from)
11 .unwrap_or_else(|_| PathBuf::from("."))
12}
13
14pub fn config_home() -> PathBuf {
15 std::env::var("XDG_CONFIG_HOME")
16 .map(PathBuf::from)
17 .unwrap_or_else(|_| home_dir().join(".config"))
18}
19
20pub fn data_home() -> PathBuf {
21 std::env::var("XDG_DATA_HOME")
22 .map(PathBuf::from)
23 .unwrap_or_else(|_| home_dir().join(".local/share"))
24}
25
26pub fn runtime_home() -> PathBuf {
27 std::env::var("XDG_RUNTIME_DIR")
28 .map(PathBuf::from)
29 .unwrap_or_else(|_| PathBuf::from("/tmp"))
30}
31
32pub fn app_config_dir() -> PathBuf {
33 config_home().join(APP_NAME)
34}
35
36pub fn app_data_dir() -> PathBuf {
37 data_home().join(APP_NAME)
38}
39
40pub fn app_runtime_dir() -> PathBuf {
41 runtime_home().join(APP_NAME)
42}
43
44pub fn legacy_app_config_dir() -> PathBuf {
45 config_home().join(LEGACY_APP_NAME)
46}
47
48pub fn legacy_app_data_dir() -> PathBuf {
49 data_home().join(LEGACY_APP_NAME)
50}
51
52pub fn config_path() -> PathBuf {
53 app_config_dir().join("config.toml")
54}
55
56pub fn legacy_config_path() -> PathBuf {
57 legacy_app_config_dir().join("config.toml")
58}
59
60pub fn existing_config_path() -> Option<PathBuf> {
61 let current = config_path();
62 if current.exists() {
63 return Some(current);
64 }
65
66 let legacy = legacy_config_path();
67 legacy.exists().then_some(legacy)
68}
69
70pub fn socket_path() -> PathBuf {
71 app_runtime_dir().join("daemon.sock")
72}
73
74pub fn pid_path() -> PathBuf {
75 app_runtime_dir().join("daemon.pid")
76}
77
78pub fn profiles_dir() -> PathBuf {
79 app_data_dir().join("voices")
80}
81
82pub fn legacy_profiles_dir() -> PathBuf {
83 legacy_app_data_dir().join("voices")
84}
85
86pub fn ensure_parent(path: &Path) -> Result<()> {
87 let parent = path
88 .parent()
89 .with_context(|| format!("path has no parent: {}", path.display()))?;
90 std::fs::create_dir_all(parent)
91 .with_context(|| format!("failed to create directory: {}", parent.display()))
92}
93
94pub fn ensure_runtime_dir() -> Result<PathBuf> {
95 let dir = app_runtime_dir();
96 std::fs::create_dir_all(&dir)
97 .with_context(|| format!("failed to create runtime dir: {}", dir.display()))?;
98 Ok(dir)
99}
100
101pub fn ensure_profiles_dir() -> Result<PathBuf> {
102 let dir = profiles_dir();
103 std::fs::create_dir_all(&dir)
104 .with_context(|| format!("failed to create profiles dir: {}", dir.display()))?;
105 Ok(dir)
106}