356 lines
10 KiB
Rust
356 lines
10 KiB
Rust
//! Configuration file that handles (de-)serializing other components
|
|
|
|
use std::{fs::{self, DirEntry}, io::Write, path::{Path, PathBuf}};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{SquadObject, account::Account, error::Error, quest::Quest};
|
|
|
|
/// Struct for containing paths to other (de-)serializable things
|
|
#[derive(Serialize, Deserialize)]
|
|
#[serde(default)]
|
|
pub struct Config {
|
|
/// Path to config directory
|
|
#[serde(skip)]
|
|
pub path: PathBuf,
|
|
|
|
/// Path to serialized [quests][`crate::quest::Quest`] folder
|
|
pub quests_path: PathBuf,
|
|
|
|
/// Path to serialized [accounts][`crate::account::Account`] folder
|
|
pub accounts_path: PathBuf,
|
|
|
|
/// Path to serialized [map][`crate::map::Map`] file
|
|
pub map: PathBuf,
|
|
|
|
/// If true, print to std{out/err}
|
|
pub verbose: bool,
|
|
}
|
|
|
|
impl Default for Config {
|
|
fn default() -> Self {
|
|
Config {
|
|
path: ".".into(),
|
|
quests_path: "quests".into(),
|
|
accounts_path: "accounts".into(),
|
|
map: "map.toml".into(),
|
|
verbose: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_quest_entry(quest_entry: DirEntry) -> Result<Quest, Error>{
|
|
let filetype = quest_entry.file_type();
|
|
if let Err(error) = filetype {
|
|
return Err(Error::IoError(error));
|
|
}
|
|
|
|
let path = quest_entry.path();
|
|
|
|
let filetype = filetype.unwrap();
|
|
if !filetype.is_file() {
|
|
return Err(Error::IsNotAFile(path));
|
|
}
|
|
|
|
Quest::load(path)
|
|
}
|
|
|
|
fn handle_account_entry(account_entry: DirEntry) -> Result<Account, Error>{
|
|
let filetype = account_entry.file_type();
|
|
if let Err(error) = filetype {
|
|
return Err(Error::IoError(error));
|
|
}
|
|
|
|
let path = account_entry.path();
|
|
|
|
let filetype = filetype.unwrap();
|
|
if !filetype.is_file() {
|
|
return Err(Error::IsNotAFile(path));
|
|
}
|
|
|
|
Account::load(path)
|
|
}
|
|
|
|
impl Config {
|
|
/// Deserialize config from TOML.
|
|
///
|
|
/// This function wraps [try_load][Config::try_load].
|
|
///
|
|
/// Logs all errors if `config.verbose == true`.
|
|
/// Returns default config on error.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::config::Config;
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
/// ```
|
|
pub fn load(path: PathBuf) -> Self {
|
|
let dir = path.parent()
|
|
.unwrap_or(Path::new("."))
|
|
.to_owned();
|
|
|
|
match Self::try_load(path) {
|
|
Ok(conf) => {
|
|
if conf.verbose {
|
|
println!("Successfully loaded config");
|
|
}
|
|
conf
|
|
},
|
|
Err(error) => {
|
|
let conf = Config {
|
|
path: dir,
|
|
..Default::default()
|
|
};
|
|
|
|
if conf.verbose {
|
|
println!("Error while loading config: {error}");
|
|
}
|
|
|
|
conf
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Serialize config into TOML.
|
|
/// Config will be saved as `path/config.toml`
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::config::Config;
|
|
///
|
|
/// let path = "cfg".into();
|
|
///
|
|
/// let config = Config::default();
|
|
///
|
|
/// if let Err(error) = config.save(path) {
|
|
/// // handle error
|
|
/// }
|
|
/// ```
|
|
pub fn save(&self, path: PathBuf) -> Result<(), Error> {
|
|
let mut path = path;
|
|
path.push("config.toml");
|
|
|
|
let str = match toml::to_string_pretty(&self) {
|
|
Ok(string) => string,
|
|
Err(error) => return Err(Error::TomlSerializeError(error)),
|
|
};
|
|
|
|
let mut file = match fs::File::create(path) {
|
|
Ok(f) => f,
|
|
Err(error) => return Err(Error::IoError(error)),
|
|
};
|
|
|
|
if let Err(error) = file.write_all(str.as_bytes()) {
|
|
return Err(Error::IoError(error));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Deserialize config from TOML
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::{config::Config,error::Error};
|
|
/// # fn main() {
|
|
/// # let _ = wrapper();
|
|
/// # }
|
|
/// # fn wrapper() -> Result<(), Error> {
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::try_load(path)?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn try_load(path: PathBuf) -> Result<Self, Error> {
|
|
let dir = path.parent()
|
|
.unwrap_or(Path::new("."))
|
|
.to_owned();
|
|
|
|
match fs::read_to_string(path) {
|
|
Ok(string) => {
|
|
match toml::from_str::<Config>(&string) {
|
|
Ok(mut conf) => {
|
|
conf.path = dir;
|
|
Ok(conf)
|
|
},
|
|
Err(error) => {
|
|
Err(Error::TomlDeserializeError(error))
|
|
}
|
|
}
|
|
},
|
|
Err(error) => {
|
|
Err(Error::IoError(error))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns full path to quests folder
|
|
/// This path will be relative to $PWD, not to config.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::config::Config;
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
///
|
|
/// let quests_path = config.full_quests_path();
|
|
/// ```
|
|
pub fn full_quests_path(&self) -> PathBuf {
|
|
let mut path = self.path.clone();
|
|
path.push(self.quests_path.clone());
|
|
path
|
|
}
|
|
|
|
/// Load [Vec]<[Quest]> from quests folder.
|
|
/// Also logs errors and counts successfully loaded quests.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::{config::Config, quest::Quest};
|
|
///
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
/// let quests = config.load_quests();
|
|
///
|
|
/// for quest in quests {
|
|
/// println!("Quest #{} {}", quest.id, quest.name);
|
|
/// }
|
|
/// ```
|
|
pub fn load_quests(&self) -> Vec<Quest> {
|
|
let mut out_vec = Vec::new();
|
|
|
|
let path = self.full_quests_path();
|
|
|
|
match fs::read_dir(path) {
|
|
Ok(iter) => {
|
|
for entry in iter {
|
|
match entry {
|
|
Ok(quest_entry) => {
|
|
match handle_quest_entry(quest_entry) {
|
|
Ok(quest) => out_vec.push(quest),
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading single quest: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
},
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading single quest: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
}
|
|
},
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading quests: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
|
|
if self.verbose {
|
|
println!("Loaded {} quests successfully", out_vec.len());
|
|
}
|
|
|
|
out_vec
|
|
}
|
|
|
|
/// Returns full path to accounts folder
|
|
/// This path will be relative to $PWD, not to config.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::config::Config;
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
///
|
|
/// let accounts_path = config.full_accounts_path();
|
|
/// ```
|
|
pub fn full_accounts_path(&self) -> PathBuf {
|
|
let mut path = self.path.clone();
|
|
path.push(self.accounts_path.clone());
|
|
path
|
|
}
|
|
|
|
/// Load [Vec]<[Account]> from accounts folder.
|
|
/// Also logs errors and counts successfully loaded quests.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::{config::Config, account::Account};
|
|
///
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
/// let accounts = config.load_accounts();
|
|
///
|
|
/// for account in accounts {
|
|
/// println!("Account {}", account.id);
|
|
/// }
|
|
/// ```
|
|
pub fn load_accounts(&self) -> Vec<Account> {
|
|
let mut out_vec = Vec::new();
|
|
|
|
let path = self.full_accounts_path();
|
|
|
|
match fs::read_dir(path) {
|
|
Ok(iter) => {
|
|
for entry in iter {
|
|
match entry {
|
|
Ok(acc_entry) => {
|
|
match handle_account_entry(acc_entry) {
|
|
Ok(quest) => out_vec.push(quest),
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading single account: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
},
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading single account: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
}
|
|
},
|
|
Err(error) if self.verbose => {
|
|
eprintln!("Error on loading accounts: {error}");
|
|
},
|
|
_ => {},
|
|
}
|
|
|
|
if self.verbose {
|
|
println!("Loaded {} accounts successfully", out_vec.len());
|
|
}
|
|
|
|
out_vec
|
|
}
|
|
|
|
/// Returns full path to map.toml
|
|
/// This path will be relative to $PWD, not to config.
|
|
///
|
|
/// # Examples
|
|
/// ```rust
|
|
/// use squad_quest::{config::Config,error::Error,map::Map,SquadObject};
|
|
/// # fn main() {
|
|
/// # let _ = wrapper();
|
|
/// # }
|
|
/// # fn wrapper() -> Result<(),Error> {
|
|
///
|
|
/// let path = "cfg/config.toml".into();
|
|
/// let config = Config::load(path);
|
|
///
|
|
/// let map_path = config.full_map_path();
|
|
/// let map = Map::load(map_path)?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn full_map_path(&self) -> PathBuf {
|
|
let mut path = self.path.clone();
|
|
path.push(self.map.clone());
|
|
path
|
|
}
|
|
}
|