wormhole-common 0.2.0

Common code for the Wormhole mod manager project.
Documentation
use std::{fs, path::PathBuf};

use keyvalues_parser::Vdf;

#[cfg(target_os = "linux")]
use super::resolver::linux;
#[cfg(target_os = "macos")]
use super::resolver::macos;
#[cfg(target_os = "windows")]
use super::resolver::windows;

#[derive(Default, Clone, Debug)]
pub struct LibraryFolders {
    pub paths: Vec<PathBuf>,
    pub discovered: bool,
}

impl LibraryFolders {
    pub fn new() -> Self {
        return Self {
            paths: vec![],
            discovered: false,
        };
    }

    #[cfg(target_os = "macos")]
    pub fn get_library_folders_file(&self) -> PathBuf {
        return macos::get_steam_library_folders_file();
    }

    #[cfg(target_os = "linux")]
    pub fn get_library_folders_file(&self) -> PathBuf {
        return linux::get_steam_library_folders_file();
    }

    #[cfg(target_os = "windows")]
    pub fn get_library_folders_file(&self) -> PathBuf {
        return windows::get_steam_library_folders_file();
    }

    pub fn discover(&mut self) -> Option<&mut Self> {
        let libraryfolders_vdf_path = self.get_library_folders_file();

        if libraryfolders_vdf_path.is_file() {
            let vdf_text = fs::read_to_string(&libraryfolders_vdf_path).ok()?;
            let value = Vdf::parse(&vdf_text).ok()?.value;
            let obj = value.get_obj()?;

            let library_folders: Vec<_> = obj
                .iter()
                .filter(|(key, values)| key.parse::<u32>().is_ok() && values.len() == 1)
                .filter_map(|(_, values)| {
                    let library_folder_string = values
                        .get(0)?
                        .get_obj()?
                        .get("path")?
                        .get(0)?
                        .get_str()?
                        .to_string();

                    let library_folder = PathBuf::from(library_folder_string).join("steamapps");

                    return Some(library_folder);
                })
                .collect();

            self.paths = library_folders;
        }

        self.discovered = true;

        return Some(self);
    }
}

pub struct SteamInstallFinder {
    pub library_folders: LibraryFolders,
}

impl Default for SteamInstallFinder {
    fn default() -> Self {
        let mut me = Self {
            library_folders: LibraryFolders::new(),
        };

        me.library_folders
            .discover()
            .expect("Failed to discover Steam library folders!");

        return me;
    }
}

impl SteamInstallFinder {
    pub fn find_ksp2_dir(&mut self) -> Option<PathBuf> {
        for library_folder in self.library_folders.clone().paths {
            let ksp2_dir = library_folder.join("common").join("Kerbal Space Program 2");

            if ksp2_dir.is_dir() {
                let dir_contents = fs::read_dir(&ksp2_dir).unwrap().flatten();

                for file in dir_contents {
                    let file_path = file.path();

                    if file_path.is_file()
                        && file_path
                            .as_os_str()
                            .to_str()
                            .unwrap()
                            .contains("KSP2_x64.exe")
                    {
                        return Some(ksp2_dir);
                    }
                }
            }
        }

        return None;
    }

    pub fn find_ksp1_dir(&mut self) -> Option<PathBuf> {
        for library_folder in self.library_folders.clone().paths {
            let ksp2_dir = library_folder.join("common").join("Kerbal Space Program");

            if ksp2_dir.is_dir() {
                let dir_contents = fs::read_dir(&ksp2_dir).unwrap().flatten();

                for file in dir_contents {
                    let file_path = file.path();

                    if file_path.is_file()
                        && file_path
                            .as_os_str()
                            .to_str()
                            .unwrap()
                            .contains("KSP_x64.exe")
                    {
                        return Some(ksp2_dir);
                    }
                }
            }
        }

        return None;
    }
}