//! Configuration use std::{fmt::Display, fs::File, io::ErrorKind as IoErrorKind}; use serde::{Deserialize, Serialize}; /// Result alias for this module pub type Result = std::result::Result; /// Data for a valid login, including access token and homeserver address #[derive(Serialize, Deserialize, Clone, Debug)] pub struct Session { /// Access token, mxid and device id of the session pub session: matrix_sdk::Session, /// The address of the homeserver pub homeserver: String, } impl Session { /// Read session data from disk. pub fn from_file() -> Result> { let dirs = dirs()?; let file = File::open(dirs.data_dir().join("session.json")); let file = match file { Ok(file) => file, Err(e) => { return match e.kind() { IoErrorKind::NotFound => Ok(None), _ => Err(e.into()), } } }; let session = serde_json::from_reader(file)?; Ok(session) } /// Writes the session data to disk. pub fn write(&self) -> Result<()> { let dirs = dirs()?; std::fs::create_dir_all(dirs.data_dir())?; let file = File::create(dirs.data_dir().join("session.json"))?; serde_json::to_writer_pretty(file, self)?; Ok(()) } } /// Configuration for the application #[derive(Serialize, Deserialize, Clone, Debug)] pub struct Config { /// The global zoom level. pub zoom: f64, } impl Config { /// Creates a new `Config` with default settings pub fn new() -> Config { Config { zoom: 1.0 } } } impl Default for Config { fn default() -> Self { Self::new() } } impl Config { /// Reads the configuration from disk, or creates a new file with default settings if none /// exists pub fn from_file() -> Result { let dirs = dirs()?; let file = File::open(dirs.config_dir().join("retrix.json")); // Create the file if it doesn't exist let file = match file { Ok(file) => file, Err(e) => match e.kind() { IoErrorKind::NotFound => { let config = Config::default(); config.write()?; return Ok(config); } _ => return Err(e.into()), }, }; let config: Config = serde_json::from_reader(file)?; Ok(config) } /// Writes the configuration to disk pub fn write(&self) -> Result<()> { let dirs = dirs()?; std::fs::create_dir_all(dirs.config_dir())?; let file = File::create(dirs.config_dir().join("retrix.json"))?; serde_json::to_writer_pretty(file, self)?; Ok(()) } } /// Generates structure holding paths for config dirs etc. pub fn dirs() -> Result { dirs::ProjectDirs::from("net.amandag", "", "retrix").ok_or(Error::HomeDir) } /// Errors which can happen when handling config files #[derive(Debug)] pub enum Error { /// An error happened opening or creating a file Io(std::io::Error), /// (De)serializing a file failed Parsing(serde_json::Error), /// The home directory couldn't be found HomeDir, } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::Io(e) => write!(f, "Error opening file: {}", e), Error::Parsing(e) => write!(f, "Error in config file: {}", e), Error::HomeDir => write!(f, "Couldn't find home directory"), } } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match *self { Error::Io(ref e) => Some(e), Error::Parsing(ref e) => Some(e), Error::HomeDir => None, } } } impl From for Error { fn from(e: std::io::Error) -> Self { Error::Io(e) } } impl From for Error { fn from(e: serde_json::Error) -> Self { Error::Parsing(e) } }