Skip to main content

supreme_fs/game_storage/online/
profiles.rs

1//! Listing, syncing, and fetching profile manifests from the remote backend.
2
3use crate::HybridStorageError;
4use crate::game_storage::{GameStorage, OnlineProfileInfo};
5use std::io::{self, Read};
6
7impl GameStorage {
8    /// List available profiles from the online server.
9    pub fn list_online_profiles(&self) -> Result<Vec<OnlineProfileInfo>, HybridStorageError> {
10        let client = self
11            .client
12            .as_ref()
13            .ok_or_else(|| io::Error::other("Online storage not configured"))?;
14        let api_url = self
15            .api_url
16            .as_ref()
17            .ok_or_else(|| io::Error::other("Online storage not configured"))?;
18
19        let url = format!("{api_url}?action=list_profiles");
20
21        let response = client.get(&url).call()?;
22
23        if response.status().as_u16() >= 200 && response.status().as_u16() < 300 {
24            let mut body = String::new();
25            response
26                .into_body()
27                .into_reader()
28                .read_to_string(&mut body)
29                .map_err(HybridStorageError::IoError)?;
30
31            let profiles: Vec<OnlineProfileInfo> = serde_json::from_str(&body).map_err(|e| {
32                HybridStorageError::IoError(io::Error::new(io::ErrorKind::InvalidData, e))
33            })?;
34            Ok(profiles)
35        } else {
36            Err(HybridStorageError::NotFound(
37                "Failed to list profiles".to_string(),
38            ))
39        }
40    }
41
42    /// Sync online profiles: downloads missing manifests and returns a set of filenames available online.
43    pub fn sync_online_profiles(
44        &self,
45    ) -> Result<std::collections::HashSet<String>, HybridStorageError> {
46        let profiles = self.list_online_profiles()?;
47        let mut online_filenames = std::collections::HashSet::new();
48
49        for profile in profiles {
50            online_filenames.insert(profile.filename.clone());
51
52            // Check if exists locally
53            let local_path = self.profiles_path().join(&profile.filename);
54            if !local_path.exists() {
55                // Download and cache
56                // We use get_profile which handles caching internally
57                if let Err(e) = self.get_profile(&profile.filename) {
58                    eprintln!("Failed to sync profile {}: {}", profile.filename, e);
59                }
60            }
61        }
62
63        Ok(online_filenames)
64    }
65
66    pub fn get_profile(&self, profile_name: &str) -> Result<Vec<u8>, HybridStorageError> {
67        self.fetch_and_cache_snapshot("profiles", profile_name)
68    }
69}