retrix/src/config.rs

146 lines
3.5 KiB
Rust

//! Configuration
use std::{fmt::Display, fs::File, io::ErrorKind as IoErrorKind};
use serde::{Deserialize, Serialize};
/// Result alias for this module
pub type Result<T> = std::result::Result<T, Error>;
/// 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<Option<Session>> {
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<Config> {
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> {
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<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::Parsing(e)
}
}