rconcrete 0.2.0

rconcrete is a simple tool for opening an rcon shell to a game server, such as minecraft or factorio
Documentation
use std::{
    fs,
    io::{BufReader, BufWriter, ErrorKind},
    path::PathBuf,
};

use serde::{Deserialize, Serialize};

use crate::error::Error;

#[derive(Default, Serialize, Deserialize)]
pub struct Configuration {
    pub known_servers: Vec<crate::Server>,
}

pub struct ConfigurationFile {
    file_path: PathBuf,
}

impl ConfigurationFile {
    pub fn build_default() -> Result<Self, Error> {
        Ok(Self {
            file_path: Self::get_default_file_path()?,
        })
    }

    fn get_default_file_path() -> Result<PathBuf, Error> {
        let mut dir = directories::ProjectDirs::from("", "", clap::crate_name!())
            .ok_or(Error::FailedToFetchConfigPath)?
            .config_local_dir()
            .to_owned();

        dir.push("config.json");

        let config_file = dir;

        Ok(config_file)
    }

    pub fn read(&self) -> Result<Configuration, Error> {
        match fs::File::open(&self.file_path) {
            Ok(config_file) => {
                let reader = BufReader::new(config_file);
                Ok(serde_json::from_reader(reader).map_err(Error::ConfigParseError)?)
            }
            Err(e) => match e.kind() {
                ErrorKind::NotFound => Ok(Default::default()),
                _ => Err(Error::IoError(e)),
            },
        }
    }

    pub fn write(&self, config: &Configuration) -> Result<(), Error> {
        match fs::create_dir_all(self.file_path.parent().unwrap()) {
            Ok(_) => (),
            Err(e) => match e.kind() {
                ErrorKind::AlreadyExists => (),
                _ => return Err(Error::IoError(e)),
            },
        }
        let config_file = fs::File::create(&self.file_path).map_err(Error::IoError)?;
        let writer = BufWriter::new(config_file);
        serde_json::to_writer_pretty(writer, config).map_err(Error::ConfigWriteError)
    }
}