diff --git a/kifu/core/Cargo.lock b/kifu/core/Cargo.lock index 75c0dcb..91de0a2 100644 --- a/kifu/core/Cargo.lock +++ b/kifu/core/Cargo.lock @@ -163,6 +163,7 @@ version = "0.1.0" dependencies = [ "grid", "serde", + "serde_json", "thiserror", "typeshare", ] diff --git a/kifu/core/Cargo.toml b/kifu/core/Cargo.toml index 12b2b0d..e78c7bc 100644 --- a/kifu/core/Cargo.toml +++ b/kifu/core/Cargo.toml @@ -8,5 +8,6 @@ edition = "2021" [dependencies] grid = { version = "0.9" } serde = { version = "1", features = [ "derive" ] } +serde_json = { version = "1" } thiserror = { version = "1" } typeshare = { version = "1" } diff --git a/kifu/core/src/api.rs b/kifu/core/src/api.rs index 810d3bd..6777816 100644 --- a/kifu/core/src/api.rs +++ b/kifu/core/src/api.rs @@ -70,14 +70,8 @@ pub struct CoreApp { } impl CoreApp { - pub fn new() -> Self { - /* Candidate for dependency injection from the UI */ - let user_home = std::env::var("HOME").expect("the user's home directory isn't set"); - let mut config_path = std::path::PathBuf::from(user_home); - config_path.push(".config"); - config_path.push("kifu"); - - let config = Config::new(config_path); + pub fn new(config_path: std::path::PathBuf) -> Self { + let config = Config::from_path(config_path).expect("configuration to open"); let state = Arc::new(RwLock::new(AppState::new())); Self { config, state } diff --git a/kifu/core/src/config.rs b/kifu/core/src/config.rs index 401b7ed..5a7b26b 100644 --- a/kifu/core/src/config.rs +++ b/kifu/core/src/config.rs @@ -1,5 +1,12 @@ use crate::types::Player; -use std::{collections::HashMap, path::PathBuf}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + fs::File, + io::{ErrorKind, Read}, + path::PathBuf, +}; +use thiserror::Error; /* pub trait ConfigOption { @@ -22,18 +29,28 @@ pub trait Config { } */ -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] enum OptionNames { DatabasePath, Me, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum ConfigOption { DatabasePath(DatabasePath), Me(Me), } +#[derive(Debug, Error)] +pub enum ConfigReadError { + #[error("Cannot read the configuration file: {0}")] + CannotRead(std::io::Error), + #[error("Cannot open the configuration file for reading: {0}")] + CannotOpen(std::io::Error), + #[error("Invalid json data found in the configurationfile: {0}")] + InvalidJSON(serde_json::Error), +} + #[derive(Clone, Debug)] pub struct Config { config_path: PathBuf, @@ -48,6 +65,37 @@ impl Config { } } + pub fn from_path(config_path: PathBuf) -> Result { + let mut settings = config_path.clone(); + settings.push("config"); + + match File::open(settings) { + Ok(mut file) => { + let mut buf = String::new(); + file.read_to_string(&mut buf) + .map_err(|err| ConfigReadError::CannotRead(err))?; + let values = serde_json::from_str(buf.as_ref()) + .map_err(|err| ConfigReadError::InvalidJSON(err))?; + Ok(Self { + config_path, + values, + }) + } + Err(io_err) => { + match io_err.kind() { + ErrorKind::NotFound => { + /* create the path and an empty file */ + Ok(Self { + config_path, + values: HashMap::new(), + }) + } + _ => Err(ConfigReadError::CannotOpen(io_err)), + } + } + } + } + fn set(&mut self, val: ConfigOption) { let _ = match val { ConfigOption::DatabasePath(_) => self.values.insert(OptionNames::DatabasePath, val), @@ -63,7 +111,7 @@ impl Config { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct DatabasePath(PathBuf); impl From<&Config> for DatabasePath { @@ -75,7 +123,7 @@ impl From<&Config> for DatabasePath { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Me(Player); impl From<&Config> for Option { diff --git a/kifu/core/src/types.rs b/kifu/core/src/types.rs index a819c4c..1b3ce32 100644 --- a/kifu/core/src/types.rs +++ b/kifu/core/src/types.rs @@ -91,7 +91,7 @@ impl From for String { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Player { pub name: String, pub rank: Option, diff --git a/kifu/gtk/Cargo.lock b/kifu/gtk/Cargo.lock index 41fd545..660eee1 100644 --- a/kifu/gtk/Cargo.lock +++ b/kifu/gtk/Cargo.lock @@ -787,6 +787,7 @@ version = "0.1.0" dependencies = [ "grid", "serde", + "serde_json", "thiserror", "typeshare", ] diff --git a/kifu/gtk/src/main.rs b/kifu/gtk/src/main.rs index 3e34e3e..3570cf7 100644 --- a/kifu/gtk/src/main.rs +++ b/kifu/gtk/src/main.rs @@ -44,7 +44,12 @@ fn main() { .unwrap(), ); - let core = CoreApp::new(); + let user_home = std::env::var("HOME").expect("the user's home directory isn't set"); + let mut config_path = std::path::PathBuf::from(user_home); + config_path.push(".config"); + config_path.push("kifu"); + + let core = CoreApp::new(config_path); let core_handle = runtime.spawn({ let core = core.clone();