Skip to content

Commit

Permalink
Add filesystem storage (#838)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrencev authored Oct 8, 2024
1 parent 01f1ffa commit 865f086
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 1 deletion.
5 changes: 5 additions & 0 deletions packages/account_sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ tsify-next = "0.5.4"
urlencoding = "2.1.3"
once_cell.workspace = true

# Webauthn deps
base64 = { workspace = true, optional = true }
base64urlsafedata = { workspace = true, optional = true }
coset = { workspace = true, optional = true }
Expand All @@ -43,6 +44,9 @@ p256 = { workspace = true, optional = true }
serde_cbor_2 = { version = "0.12.0-dev", optional = true }
sha2 = { workspace = true, optional = true }

# Filestorage deps
dirs = { version = "5", optional = true }

[dev-dependencies]
hyper = { version = "0.14.27", features = ["server"] }
rand_core = { version = "0.6", features = ["getrandom"] }
Expand Down Expand Up @@ -94,3 +98,4 @@ webauthn = [
"web-sys/PublicKeyCredential",
"web-sys/PublicKeyCredentialCreationOptions",
]
filestorage = ["dirs"]
110 changes: 110 additions & 0 deletions packages/account_sdk/src/storage/filestorage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use super::{StorageBackend, StorageError, StorageValue};

use async_trait::async_trait;
use std::fs;
use std::io::Read;
use std::path::PathBuf;

#[derive(Clone)]
pub struct FileSystemBackend {
base_path: PathBuf,
}

impl Default for FileSystemBackend {
fn default() -> Self {
let config_dir = dirs::config_dir()
.unwrap_or_else(|| std::env::current_dir().expect("Failed to get current directory"));

let base_path = config_dir.join("cartridge");

Self { base_path }
}
}

impl FileSystemBackend {
fn file_path(&self, key: &str) -> PathBuf {
self.base_path.join(key)
}

fn ensure_path_exists(&self, path: PathBuf) -> Result<(), StorageError> {
fs::create_dir_all(path).map_err(|e| {
StorageError::OperationFailed(format!("Failed to create directory: {}", e))
})
}
}

#[async_trait]
impl StorageBackend for FileSystemBackend {
fn set(&mut self, key: &str, value: &StorageValue) -> Result<(), StorageError> {
let path = self.file_path(key);
if let Some(parent) = path.parent() {
self.ensure_path_exists(parent.to_path_buf())?;
}
let serialized = serde_json::to_string(value)?;
fs::write(&path, &serialized)
.map_err(|e| StorageError::OperationFailed(format!("Failed to write file: {}", e)))?;
Ok(())
}

fn get(&self, key: &str) -> Result<Option<StorageValue>, StorageError> {
let path = self.file_path(key);
if path.exists() {
let mut file = fs::File::open(&path).map_err(|e| {
StorageError::OperationFailed(format!("Failed to open file: {}", e))
})?;
let mut contents = String::new();
file.read_to_string(&mut contents).map_err(|e| {
StorageError::OperationFailed(format!("Failed to read file: {}", e))
})?;
let deserialized = serde_json::from_str(&contents)?;
Ok(Some(deserialized))
} else {
Ok(None)
}
}

fn remove(&mut self, key: &str) -> Result<(), StorageError> {
let path = self.file_path(key);
if path.exists() {
fs::remove_file(&path).map_err(|e| {
StorageError::OperationFailed(format!("Failed to remove file: {}", e))
})?;
}
Ok(())
}

fn clear(&mut self) -> Result<(), StorageError> {
if self.base_path.exists() {
fs::remove_dir_all(&self.base_path).map_err(|e| {
StorageError::OperationFailed(format!("Failed to remove directory: {}", e))
})?;
}
self.ensure_path_exists(self.base_path.clone())?;
Ok(())
}

fn keys(&self) -> Result<Vec<String>, StorageError> {
let mut keys = Vec::new();
if self.base_path.exists() {
for entry in fs::read_dir(&self.base_path).map_err(|e| {
StorageError::OperationFailed(format!("Failed to read directory: {}", e))
})? {
let entry = entry.map_err(|e| {
StorageError::OperationFailed(format!("Failed to read directory entry: {}", e))
})?;
if entry
.file_type()
.map_err(|e| {
StorageError::OperationFailed(format!("Failed to get file type: {}", e))
})?
.is_file()
{
if let Some(file_name) = entry.file_name().to_str() {
keys.push(file_name.to_string());
}
}
}
}
Ok(keys)
}
}
7 changes: 6 additions & 1 deletion packages/account_sdk/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use coset::CborSerializable;
use crate::account::session::hash::Session;
use starknet::{core::types::Felt, signers::SigningKey};

#[cfg(all(not(target_arch = "wasm32"), feature = "filestorage"))]
pub mod filestorage;
#[cfg(not(target_arch = "wasm32"))]
pub mod inmemory;
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -165,8 +167,11 @@ pub trait StorageBackend: Send + Sync {
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(all(not(target_arch = "wasm32"), not(feature = "filestorage")))]
pub type Storage = inmemory::InMemoryBackend;

#[cfg(target_arch = "wasm32")]
pub type Storage = localstorage::LocalStorage;

#[cfg(all(not(target_arch = "wasm32"), feature = "filestorage"))]
pub type Storage = filestorage::FileSystemBackend;

0 comments on commit 865f086

Please sign in to comment.