Skip to main content

proton_call/
config.rs

1extern crate serde;
2extern crate toml;
3
4use crate::{
5    error::{Error, Kind},
6    throw,
7};
8use std::borrow::Cow;
9use std::fmt::{Display, Formatter};
10use std::path::PathBuf;
11
12/// Config type for parsing config files
13#[derive(Debug, serde::Deserialize)]
14pub struct Config {
15    data: PathBuf,
16    steam: PathBuf,
17    common: Option<PathBuf>,
18}
19
20impl Config {
21    /// Opens and returns the user's config
22    ///
23    /// # Errors
24    ///
25    /// This function will fail if...
26    /// * Can not read `XDG_CONFIG_HOME` or `HOME` from the environment
27    /// * Can not open config file
28    /// * Can not parse config into `Config`
29    pub fn open() -> Result<Config, Error> {
30        use std::fs::File;
31        use std::io::Read;
32
33        // Get default config location
34        let loc: PathBuf = Config::config_location()?;
35
36        // Open the config file
37        let mut file: File = match File::open(&loc) {
38            Ok(f) => f,
39            Err(e) => throw!(Kind::ConfigOpen, "{}", e),
40        };
41
42        // Read the config into memory
43        let mut buffer: Vec<u8> = Vec::new();
44
45        if let Err(e) = file.read_to_end(&mut buffer) {
46            throw!(Kind::ConfigRead, "{}", e);
47        }
48
49        // Parse the config into `Config`
50        let slice: &[u8] = buffer.as_slice();
51
52        let mut config: Config = toml::from_slice(slice)?;
53
54        config.default_common();
55
56        Ok(config)
57    }
58
59    /// Finds one of the two default config locations
60    ///
61    /// # Errors
62    ///
63    /// Will only fail if `XDG_CONFIG_HOME` and `HOME` do not exist in environment
64    pub fn config_location() -> Result<PathBuf, Error> {
65        use std::env::var;
66
67        if let Ok(val) = var("XDG_CONFIG_HOME") {
68            let path: String = format!("{}/proton.conf", val);
69            return Ok(PathBuf::from(path));
70        }
71
72        match var("HOME") {
73            Ok(var) => Ok(PathBuf::from(format!("{}/.config/proton.conf", var))),
74            Err(_) => throw!(Kind::Environment, "XDG_CONFIG_HOME / HOME missing"),
75        }
76    }
77
78    #[inline]
79    /// Sets a default common if not given by user
80    fn default_common(&mut self) {
81        if self.common.is_none() {
82            let common: PathBuf = self._default_common();
83            self.common = Some(common);
84        }
85    }
86
87    #[must_use]
88    /// Generates a default common directory
89    fn _default_common(&self) -> PathBuf {
90        eprintln!("warning: using default common");
91        let steam: Cow<str> = self.steam.to_string_lossy();
92        let common_str: String = format!("{}/steamapps/common/", steam);
93        PathBuf::from(common_str)
94    }
95
96    #[must_use]
97    #[inline]
98    /// Returns the in use common directory
99    pub fn common(&self) -> PathBuf {
100        if let Some(common) = &self.common {
101            common.clone()
102        } else {
103            self._default_common()
104        }
105    }
106
107    #[must_use]
108    #[inline]
109    /// Returns the in use steam directory
110    pub fn steam(&self) -> PathBuf {
111        self.steam.clone()
112    }
113
114    #[must_use]
115    #[inline]
116    /// Returns the in use compat data directory
117    pub fn data(&self) -> PathBuf {
118        self.data.clone()
119    }
120}
121
122impl Display for Config {
123    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
124        let data: Cow<str> = self.data.to_string_lossy();
125        let steam: Cow<str> = self.steam.to_string_lossy();
126
127        let common: String = if let Some(common) = &self.common {
128            common.to_string_lossy().to_string()
129        } else {
130            let pb: PathBuf = self._default_common();
131            pb.to_string_lossy().to_string()
132        };
133
134        write!(f, "steam: {}\ndata: {}\ncommon: {}", steam, data, common)
135    }
136}