helixlauncher_core/
config.rs1use serde::{Deserialize, Serialize};
9use std::env;
10use std::path::PathBuf;
11use std::{
12 fs::{self, File},
13 io,
14};
15
16pub const CONFIG_NAME: &str = "libhelix_config.json";
17
18#[derive(Debug, Deserialize, Serialize)]
19pub struct Config {
20 #[serde(skip)]
23 path: PathBuf, }
26
27impl Config {
28 pub fn new(name: &str) -> Result<Self, Error> {
29 let mut path = get_base_path();
31 path.push(name);
32
33 let config = if !path.exists() {
34 if let Err(e) = fs::create_dir_all(&path) {
37 if e.kind() == io::ErrorKind::PermissionDenied {
38 return Err(Error::PermissionDenied(e));
39 }
40 }
41
42 let conf = Self::default_config(path);
43 conf.save_config()?;
44 conf
45 } else {
46 Self::read_config(path)?
47 };
48
49 Ok(config)
50 }
51
52 pub fn save_config(&self) -> Result<(), Error> {
53 let filepath = self.path.join(CONFIG_NAME);
54
55 let mut file = File::options().write(true).create(true).open(filepath)?;
56 serde_json::to_writer_pretty(&mut file, self)?;
57
58 Ok(())
59 }
60
61 pub fn read_config<P: Into<PathBuf>>(path: P) -> io::Result<Self> {
62 let path: PathBuf = path.into();
63
64 let file = File::open(path.join(CONFIG_NAME))?;
65 let mut read: Self = serde_json::from_reader(file)?;
66 read.path = path;
67
68 Ok(read)
69 }
70
71 fn default_config(path: PathBuf) -> Self {
72 Self { path }
73 }
74}
75
76#[derive(Debug, thiserror::Error)]
77pub enum Error {
78 #[error("Could not find config file")]
79 ConfigNotFound,
80 #[error("Permission denied: {0}")]
81 PermissionDenied(io::Error),
82 #[error("An IO error occurred {0}")]
83 IoError(io::Error),
84 #[error("Serialization failed: {0}")]
85 SerializeFailed(serde_json::Error),
86 #[error("Deserialization failed: {0}")]
87 DeserializeFailed(serde_json::Error),
88}
89
90impl From<io::Error> for Error {
91 fn from(e: io::Error) -> Self {
92 use io::ErrorKind;
93
94 match e.kind() {
95 ErrorKind::NotFound => Self::ConfigNotFound,
96 ErrorKind::PermissionDenied => Self::PermissionDenied(e),
97 _ => Self::IoError(e),
98 }
99 }
100}
101
102impl From<serde_json::Error> for Error {
103 fn from(e: serde_json::Error) -> Self {
104 use serde_json::error::Category;
105
106 match e.classify() {
107 Category::Syntax | Category::Data | Category::Eof => Self::DeserializeFailed(e),
108 Category::Io => Self::IoError(e.into()),
109 }
110 }
111}
112
113fn get_base_path() -> PathBuf {
114 if cfg!(windows) {
116 env::var("APPDATA").unwrap().into()
117 } else {
118 let home = env::var("HOME");
119
120 match home {
121 Ok(ok) => {
122 let mut path: PathBuf = ok.into();
123 path.push(".local");
124 path.push("share");
125 path
126 }
127 Err(_) => env::current_dir().unwrap(),
128 }
129 }
130}