wyvern 1.3.0

A simple CLI tool for installing and maintaining linux GOG games
Documentation
use curl::easy::{Handler, WriteError};
use fs::File;
use fs::OpenOptions;
use gog::token::Token;
use indicatif::{ProgressBar, ProgressStyle};
use serde_json;
use std::collections::HashMap;
use std::default::Default;
use std::fs;
use std::io::{Read, Write};
use std::path::PathBuf;
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Hash)]
pub enum SaveType {
    GOG(i64),
    Other(String),
}
type SaveMap = HashMap<String, SaveInfo>;
#[derive(Serialize, Deserialize)]
pub struct Config {
    pub version: u8,
    pub sync_saves: Option<String>,
    pub token: Option<Token>,
}
impl Default for Config {
    fn default() -> Config {
        Config {
            version: 1,
            sync_saves: None,
            token: None,
        }
    }
}
#[derive(Serialize, Deserialize)]
pub struct SaveInfo {
    pub identifier: SaveType,
    pub path: String,
}
#[derive(Serialize, Deserialize)]
pub struct SaveDB {
    pub saves: SaveMap,
}
impl Default for SaveDB {
    fn default() -> SaveDB {
        SaveDB {
            saves: HashMap::new(),
        }
    }
}
impl SaveDB {
    pub fn load<N>(path: N) -> Result<SaveDB, std::io::Error>
    where
        N: Into<PathBuf>,
    {
        let path = path.into();
        let mut unparsed = String::new();
        let file = fs::File::open(path.clone());
        if file.is_ok() {
            file.unwrap().read_to_string(&mut unparsed)?;
            Ok(serde_json::from_str(&unparsed).unwrap())
        } else {
            let default = SaveDB::default();
            default.store(path)?;
            Ok(default)
        }
    }
    pub fn store<N>(&self, path: N) -> Result<&SaveDB, std::io::Error>
    where
        N: Into<PathBuf>,
    {
        let to_write = serde_json::to_string(&self).unwrap();
        OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(path.into())?
            .write_all(to_write.as_bytes())?;
        Ok(self)
    }
}
pub struct GameInfo {
    pub version: String,
    pub name: String,
}
impl GameInfo {
    pub fn parse(ginfo: impl Into<String>) -> Result<GameInfo, gog::Error> {
        let ginfo = ginfo.into();
        let mut lines = ginfo.trim().lines();
        info!("Getting name from gameinfo");
        if let Some(name) = lines.next() {
            let name = name.to_string();
            info!("Getting version string from gameinfo");
            if let Some(version) = lines.last() {
                let version = version.trim().to_string();
                Ok(GameInfo {
                    name: name,
                    version: version,
                })
            } else {
                error!("Could not get version from gameinfo");
                Err(gog::ErrorKind::MissingField("name".to_string()).into())
            }
        } else {
            error!("Could not fetch name from gameinfo file");
            Err(gog::ErrorKind::MissingField("name".to_string()).into())
        }
    }
}
pub struct WriteHandler {
    pub writer: File,
    pub pb: Option<ProgressBar>,
}
impl Handler for WriteHandler {
    fn write(&mut self, data: &[u8]) -> std::result::Result<usize, WriteError> {
        self.writer.write_all(data).expect("Couldn't write to file");
        if self.pb.is_some() {
            let pb = self.pb.take().unwrap();
            pb.inc(data.len() as u64);
            self.pb.replace(pb);
        }
        Ok(data.len())
    }
}
#[derive(Serialize, Debug)]
pub struct GamesList {
    pub games: Vec<Game>,
}
#[derive(Serialize, Debug)]
pub enum Game {
    ProductInfo(gog::gog::ProductDetails),
    GameInfo(gog::gog::GameDetails, i64),
}
impl Game {
    pub fn title(&self) -> String {
        match self {
            Game::ProductInfo(details) => details.title.clone(),
            Game::GameInfo(details, _id) => details.title.clone(),
        }
    }
}