1use std::env;
2use std::path::{Path, PathBuf};
3
4use serde::{Deserialize, Serialize};
5
6use crate::error::Error;
7
8pub const DEFAULT_BASE_URL: &str = "https://app.hey.com";
10pub const DEFAULT_OAUTH_CLIENT_ID: &str = "khMWSVDVSq78oyKA3KtxmYRv";
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(default)]
16pub struct Config {
17 pub base_url: String,
19 pub oauth_client_id: String,
21 pub cache_dir: PathBuf,
23 pub cache_enabled: bool,
25}
26
27impl Default for Config {
28 fn default() -> Config {
29 Config {
30 base_url: DEFAULT_BASE_URL.to_string(),
31 oauth_client_id: DEFAULT_OAUTH_CLIENT_ID.to_string(),
32 cache_dir: default_cache_dir(),
33 cache_enabled: false,
34 }
35 }
36}
37
38impl Config {
39 pub fn load(path: &Path) -> Result<Config, Error> {
41 match std::fs::read(path) {
42 Ok(bytes) => serde_json::from_slice(&bytes)
43 .map_err(|error| Error::usage(format!("{}: {error}", path.display()))),
44 Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(Config::default()),
45 Err(error) => Err(Error::usage(format!("{}: {error}", path.display()))),
46 }
47 }
48
49 #[must_use]
52 pub fn with_env(mut self) -> Config {
53 if let Some(value) = env_value("HEY_BASE_URL") {
54 self.base_url = value;
55 }
56 if let Some(value) = env_value("HEY_OAUTH_CLIENT_ID") {
57 self.oauth_client_id = value;
58 }
59 if let Some(value) = env_value("HEY_CACHE_DIR") {
60 self.cache_dir = PathBuf::from(value);
61 }
62 if let Some(value) = env_value("HEY_CACHE_ENABLED") {
63 self.cache_enabled = value.eq_ignore_ascii_case("true") || value == "1";
64 }
65 self
66 }
67
68 #[must_use]
70 pub fn with_base_url(mut self, base_url: impl Into<String>) -> Config {
71 self.base_url = base_url.into();
72 self
73 }
74
75 #[must_use]
77 pub fn with_cache_enabled(mut self, enabled: bool) -> Config {
78 self.cache_enabled = enabled;
79 self
80 }
81
82 pub fn origin(&self) -> &str {
84 self.base_url.trim_end_matches('/')
85 }
86}
87
88fn env_value(name: &str) -> Option<String> {
89 env::var(name).ok().filter(|value| !value.is_empty())
90}
91
92pub fn default_cache_dir() -> PathBuf {
95 xdg_dir("XDG_CACHE_HOME", ".cache").join("hey")
96}
97
98pub fn default_config_dir() -> PathBuf {
101 xdg_dir("XDG_CONFIG_HOME", ".config").join("hey")
102}
103
104fn xdg_dir(variable: &str, fallback: &str) -> PathBuf {
105 match env_value(variable) {
106 Some(value) => PathBuf::from(value),
107 None => env::home_dir()
108 .unwrap_or_else(|| PathBuf::from("."))
109 .join(fallback),
110 }
111}