sharenet/passport/src/infrastructure/storage/wasm.rs
continuist 05674b4caa
Some checks failed
Podman Rootless Demo / test-backend (push) Has been skipped
Podman Rootless Demo / test-frontend (push) Has been skipped
Podman Rootless Demo / build-backend (push) Has been skipped
Podman Rootless Demo / build-frontend (push) Failing after 5m32s
Podman Rootless Demo / deploy-prod (push) Has been skipped
Add to project
2025-11-01 11:53:11 -04:00

110 lines
No EOL
4.1 KiB
Rust

//! WASM-compatible storage using browser LocalStorage
use crate::domain::entities::*;
use crate::domain::error::DomainError;
use crate::domain::traits::*;
/// WASM storage using browser LocalStorage
#[derive(Clone)]
pub struct BrowserStorage;
// Mock storage for testing on native targets
#[cfg(not(target_arch = "wasm32"))]
use std::collections::HashMap;
#[cfg(not(target_arch = "wasm32"))]
use std::sync::{Mutex, OnceLock};
#[cfg(not(target_arch = "wasm32"))]
static MOCK_STORAGE: OnceLock<Mutex<HashMap<String, String>>> = OnceLock::new();
impl FileStorage for BrowserStorage {
type Error = DomainError;
fn save(&self, file: &PassportFile, path: &str) -> Result<(), Self::Error> {
// Real implementation for WASM targets
#[cfg(target_arch = "wasm32")]
{
use base64::Engine;
use gloo_storage::Storage;
// Serialize to CBOR
let data = serde_cbor::to_vec(file)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to serialize file: {}", e)))?;
// Convert to base64 for storage
let base64_data = base64::engine::general_purpose::STANDARD.encode(&data);
// Store in browser localStorage using gloo-storage (synchronous)
gloo_storage::LocalStorage::set(path, base64_data)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to store in localStorage: {}", e)))?;
Ok(())
}
// Mock implementation for testing on native targets
#[cfg(not(target_arch = "wasm32"))]
{
// For testing purposes, we'll use a simple in-memory storage
// In a real browser environment, this would use actual localStorage
use base64::Engine;
// Serialize to CBOR
let data = serde_cbor::to_vec(file)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to serialize file: {}", e)))?;
// Convert to base64 for storage
let base64_data = base64::engine::general_purpose::STANDARD.encode(&data);
// Store in mock storage
let mock_storage = MOCK_STORAGE.get_or_init(|| Mutex::new(HashMap::new()));
mock_storage.lock().unwrap().insert(path.to_string(), base64_data);
Ok(())
}
}
fn load(&self, path: &str) -> Result<PassportFile, Self::Error> {
// Real implementation for WASM targets
#[cfg(target_arch = "wasm32")]
{
use base64::Engine;
use gloo_storage::Storage;
// Load from browser localStorage (synchronous)
let base64_data: String = gloo_storage::LocalStorage::get(path)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to load from localStorage: {}", e)))?;
// Decode from base64
let data = base64::engine::general_purpose::STANDARD.decode(&base64_data)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to decode base64: {}", e)))?;
// Deserialize from CBOR
let file = serde_cbor::from_slice(&data)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to deserialize file: {}", e)))?;
Ok(file)
}
// Mock implementation for testing on native targets
#[cfg(not(target_arch = "wasm32"))]
{
use base64::Engine;
// Load from mock storage
let mock_storage = MOCK_STORAGE.get_or_init(|| Mutex::new(HashMap::new()));
let mock_storage = mock_storage.lock().unwrap();
let base64_data = mock_storage.get(path)
.ok_or_else(|| DomainError::InvalidFileFormat(format!("Key not found: {}", path)))?;
// Decode from base64
let data = base64::engine::general_purpose::STANDARD.decode(base64_data)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to decode base64: {}", e)))?;
// Deserialize from CBOR
let file = serde_cbor::from_slice(&data)
.map_err(|e| DomainError::InvalidFileFormat(format!("Failed to deserialize file: {}", e)))?;
Ok(file)
}
}
}