1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use std::{
    fs::File,
    io::{Error, Read, Seek},
    path::PathBuf,
};

use lazy_static::lazy_static;
use serde::{Deserialize, Deserializer, Serialize};

const DEFAULT: &str = "%AppData%\\..\\LocalLow\\VRChat\\VRChat";

lazy_static! {
    pub static ref DEFAULT_PATH: PathBuf = crate::parse_path_env(DEFAULT).unwrap();
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct VRChatConfig {
    #[serde(deserialize_with = "deserialize")]
    pub cache_directory: PathBuf,
}

impl Default for VRChatConfig {
    fn default() -> Self {
        Self {
            cache_directory: DEFAULT_PATH.join("Cache-WindowsPlayer"),
        }
    }
}

impl VRChatConfig {
    pub fn get_path() -> PathBuf {
        DEFAULT_PATH.join("config.json")
    }

    pub fn load() -> Result<Self, Error> {
        let path = Self::get_path();
        let mut file = File::options()
            .read(true)
            .write(true)
            .create(true)
            .open(path)?;

        let mut text = String::new();
        file.read_to_string(&mut text)?;
        file.rewind()?;

        match serde_json::from_str(&text) {
            Ok(config) => Ok(config),
            Err(_) => Ok(VRChatConfig::default()),
        }
    }
}

pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<PathBuf, D::Error> {
    let str = Deserialize::deserialize(deserializer).unwrap_or(DEFAULT);
    let path = crate::parse_path_env(str)
        .expect("Failed to parse the default path")
        .join("Cache-WindowsPlayer");

    Ok(path)
}