game-scanner 1.0.0

Game Scanner for any launcher and OS
Documentation
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

use crate::error::{Error, ErrorKind, Result};
use crate::prelude::{Game, GameCommands, GameState, GameType};
use crate::riotgames::types::RiotGamesProducts;
use crate::util::path::fix_path_separator;

#[derive(Serialize, Deserialize, Debug)]
struct ProductSettings {
    product_install_full_path: String,
    product_install_root: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct RiotClientInstalls {
    associated_client: Option<HashMap<String, String>>,
}

pub fn read(file: &Path, launcher_path: &Path) -> Result<Game> {
    let manifest_data = std::fs::read_to_string(&file).map_err(|error| {
        Error::new(
            ErrorKind::InvalidManifest,
            format!(
                "Invalid Riot Games manifest: {} {}",
                file.display().to_string(),
                error.to_string()
            ),
        )
    });

    if manifest_data.is_err() {
        return Err(manifest_data.err().unwrap());
    }

    let manifest_data = manifest_data.unwrap();

    let product_settings =
        serde_yaml::from_str::<ProductSettings>(&manifest_data).map_err(|error| {
            Error::new(
                ErrorKind::InvalidManifest,
                format!(
                    "Invalid Riot Games manifest: {} {}",
                    file.display().to_string(),
                    error.to_string()
                ),
            )
        });

    if product_settings.is_err() {
        return Err(product_settings.err().unwrap());
    }

    let product_settings = product_settings.unwrap();

    let launcher_installs = launcher_path.join("RiotClientInstalls.json");

    let installs_file = std::fs::read_to_string(&launcher_installs).map_err(|error| {
        Error::new(
            ErrorKind::InvalidManifest,
            format!(
                "Invalid Riot Games manifest: {} {}",
                file.display().to_string(),
                error.to_string()
            ),
        )
    });

    if installs_file.is_err() {
        return Err(installs_file.err().unwrap());
    }

    let installs_file = installs_file.unwrap();

    let riot_client_installs = serde_yaml::from_str::<RiotClientInstalls>(installs_file.as_str())
        .map_err(|error| {
            Error::new(
                ErrorKind::InvalidManifest,
                format!(
                    "Invalid Riot Games manifest: {} {}",
                    file.display().to_string(),
                    error.to_string()
                ),
            )
        });

    if riot_client_installs.is_err() {
        return Err(riot_client_installs.err().unwrap());
    }

    let riot_client_installs = riot_client_installs.unwrap();

    let manifest_filename = String::from(file.file_name().unwrap().to_str().unwrap())
        .replace(".product_settings.yaml", "");

    let product = RiotGamesProducts::from_manifest_name(&manifest_filename);

    let mut game_path = product_settings.product_install_full_path.clone();

    if !game_path.ends_with("/") {
        game_path.push_str("/");
    }

    let launcher_executable = riot_client_installs
        .associated_client
        .and_then(|data| data.get(&game_path).cloned())
        .map(PathBuf::from);

    if launcher_executable.is_none() {
        return Err(Error::new(
            ErrorKind::IgnoredApp,
            format!(
                "({}) {} is an invalid game",
                &product.get_code(),
                &product.get_name()
            ),
        ));
    }

    let mut game_install_path = PathBuf::from(&game_path);

    if cfg!(windows) {
        game_install_path = fix_path_separator(&game_install_path);
    }

    let mut launcher_executable_path = launcher_executable.unwrap();

    if cfg!(windows) {
        launcher_executable_path = fix_path_separator(&launcher_executable_path);
    }

    return Ok(Game {
        _type: GameType::RiotGames.to_string(),
        id: product.get_code().to_string(),
        name: product.get_name().to_string(),
        path: game_install_path.display().to_string(),
        commands: GameCommands {
            install: None,
            launch: vec![
                launcher_executable_path.display().to_string(),
                format!("--launch-product={}", product.get_code()),
                format!("--launch-patchline={}", product.get_server()),
            ],
            uninstall: Some(vec![
                launcher_executable_path.display().to_string(),
                format!("--uninstall-product={}", product.get_code()),
                format!("--uninstall-patchline={}", product.get_server()),
            ]),
        },
        state: GameState {
            installed: true,
            needs_update: false,
            downloading: false,
            total_bytes: None,
            received_bytes: None,
        },
    });
}