//! Guild name retrieval and caching functions. use std::collections::HashMap; use std::fs::File; use std::path::PathBuf; use std::sync::RwLock; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; static CACHE: Lazy>> = Lazy::new(|| RwLock::new(HashMap::new())); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Guild { tag: String, name: String, } impl Guild { pub fn tag(&self) -> &str { &self.tag } pub fn name(&self) -> &str { &self.name } } /// Looks up the given guild. /// /// This checks the cache first, and if nothing was found, it will hit the API. pub fn lookup(api_id: &str) -> Option { { let cache = CACHE.read().unwrap(); if let Some(guild) = cache.get(api_id) { return Some(guild.clone()); } } let mut cache = CACHE.write().unwrap(); let url = format!("https://api.guildwars2.com/v2/guild/{}", api_id); let result = ureq::get(&url) .call() .into_json() .expect("Invalid JSON in API response"); let name = result["name"].as_str()?; let tag = result["tag"].as_str()?; let guild = Guild { tag: tag.into(), name: name.into(), }; cache.insert(api_id.into(), guild.clone()); Some(guild) } fn cache_path() -> PathBuf { let mut cache_path = dirs::cache_dir().unwrap(); cache_path.push("raidgrep"); cache_path } /// Loads the cache from the file system. pub fn prepare_cache() { let path = cache_path(); if !path.is_file() { return; } let file = File::open(path).expect("Unable to read cache file"); let cache = serde_json::from_reader(file).expect("Cache file has invalid format"); let mut target = CACHE.write().unwrap(); *target = cache; } /// Saves the cache to the file system pub fn save_cache() { let path = cache_path(); let file = File::create(path).expect("Cannot open cache for writing"); serde_json::to_writer(file, &*CACHE.read().unwrap()).unwrap(); }