diff options
Diffstat (limited to 'crates/vcs')
| -rw-r--r-- | crates/vcs/src/data.rs (renamed from crates/vcs/src/workspace.rs) | 0 | ||||
| -rw-r--r-- | crates/vcs/src/data/local.rs (renamed from crates/vcs/src/workspace/local.rs) | 2 | ||||
| -rw-r--r-- | crates/vcs/src/data/local/config.rs (renamed from crates/vcs/src/workspace/local/config.rs) | 2 | ||||
| -rw-r--r-- | crates/vcs/src/data/member.rs (renamed from crates/vcs/src/workspace/member.rs) | 0 | ||||
| -rw-r--r-- | crates/vcs/src/data/user.rs | 28 | ||||
| -rw-r--r-- | crates/vcs/src/data/user/accounts.rs | 161 | ||||
| -rw-r--r-- | crates/vcs/src/data/vault.rs (renamed from crates/vcs/src/workspace/vault.rs) | 2 | ||||
| -rw-r--r-- | crates/vcs/src/data/vault/config.rs (renamed from crates/vcs/src/workspace/vault/config.rs) | 4 | ||||
| -rw-r--r-- | crates/vcs/src/data/vault/member.rs (renamed from crates/vcs/src/workspace/vault/member.rs) | 51 | ||||
| -rw-r--r-- | crates/vcs/src/data/vault/virtual_file.rs (renamed from crates/vcs/src/workspace/vault/virtual_file.rs) | 2 | ||||
| -rw-r--r-- | crates/vcs/src/workspace/user.rs | 1 | ||||
| -rw-r--r-- | crates/vcs/src/workspace/user/accounts.rs | 1 |
12 files changed, 238 insertions, 16 deletions
diff --git a/crates/vcs/src/workspace.rs b/crates/vcs/src/data.rs index 63411a6..63411a6 100644 --- a/crates/vcs/src/workspace.rs +++ b/crates/vcs/src/data.rs diff --git a/crates/vcs/src/workspace/local.rs b/crates/vcs/src/data/local.rs index 8399b6d..1c99832 100644 --- a/crates/vcs/src/workspace/local.rs +++ b/crates/vcs/src/data/local.rs @@ -6,7 +6,7 @@ use tokio::fs; use crate::{ constants::{CLIENT_FILE_README, CLIENT_FILE_WORKSPACE}, current::{current_local_path, find_local_path}, - workspace::local::config::LocalConfig, + data::local::config::LocalConfig, }; pub mod config; diff --git a/crates/vcs/src/workspace/local/config.rs b/crates/vcs/src/data/local/config.rs index d641880..e024569 100644 --- a/crates/vcs/src/workspace/local/config.rs +++ b/crates/vcs/src/data/local/config.rs @@ -4,7 +4,7 @@ use std::net::SocketAddr; use crate::constants::CLIENT_FILE_WORKSPACE; use crate::constants::PORT; -use crate::workspace::vault::MemberId; +use crate::data::vault::MemberId; #[derive(Serialize, Deserialize, ConfigFile)] #[cfg_file(path = CLIENT_FILE_WORKSPACE)] diff --git a/crates/vcs/src/workspace/member.rs b/crates/vcs/src/data/member.rs index 208c78c..208c78c 100644 --- a/crates/vcs/src/workspace/member.rs +++ b/crates/vcs/src/data/member.rs diff --git a/crates/vcs/src/data/user.rs b/crates/vcs/src/data/user.rs new file mode 100644 index 0000000..0abd098 --- /dev/null +++ b/crates/vcs/src/data/user.rs @@ -0,0 +1,28 @@ +use crate::current::current_doc_dir; +use std::path::PathBuf; + +pub mod accounts; + +pub struct UserDirectory { + local_path: PathBuf, +} + +impl UserDirectory { + /// Create a user ditectory struct from the current system's document directory + pub fn current_doc_dir() -> Option<Self> { + Some(UserDirectory { + local_path: current_doc_dir()?, + }) + } + + /// Create a user directory struct from a specified directory path + /// Returns None if the directory does not exist + pub fn from_path<P: Into<PathBuf>>(path: P) -> Option<Self> { + let local_path = path.into(); + if local_path.exists() { + Some(UserDirectory { local_path }) + } else { + None + } + } +} diff --git a/crates/vcs/src/data/user/accounts.rs b/crates/vcs/src/data/user/accounts.rs new file mode 100644 index 0000000..83ebda9 --- /dev/null +++ b/crates/vcs/src/data/user/accounts.rs @@ -0,0 +1,161 @@ +use std::{ + fs, + io::{Error, ErrorKind}, + path::PathBuf, +}; + +use cfg_file::config::ConfigFile; + +use crate::{ + constants::{USER_FILE_ACCOUNTS, USER_FILE_KEY, USER_FILE_MEMBER}, + data::{member::Member, user::UserDirectory, vault::MemberId}, +}; + +const SELF_ID: &str = "{self_id}"; + +/// Account Management +impl UserDirectory { + /// Read account from configuration file + pub async fn account(&self, id: &MemberId) -> Result<Member, std::io::Error> { + if let Some(cfg_file) = self.account_cfg(id) { + let member = Member::read_from(cfg_file).await?; + return Ok(member); + } + + Err(Error::new(ErrorKind::NotFound, "Account not found!")) + } + + /// List all account IDs in the user directory + pub fn account_ids(&self) -> Result<Vec<MemberId>, std::io::Error> { + let accounts_path = self + .local_path + .join(USER_FILE_ACCOUNTS.replace(SELF_ID, "")); + + if !accounts_path.exists() { + return Ok(Vec::new()); + } + + let mut account_ids = Vec::new(); + + for entry in fs::read_dir(accounts_path)? { + let entry = entry?; + let path = entry.path(); + + if path.is_file() + && let Some(file_name) = path.file_stem().and_then(|s| s.to_str()) + && path.extension().and_then(|s| s.to_str()) == Some("toml") + { + // Remove the "_private" suffix from key files if present + let account_id = file_name.replace("_private", ""); + account_ids.push(account_id); + } + } + + Ok(account_ids) + } + + /// Get all accounts + /// This method will read and deserialize account information, please pay attention to performance issues + pub async fn accounts(&self) -> Result<Vec<Member>, std::io::Error> { + let mut accounts = Vec::new(); + + for account_id in self.account_ids()? { + if let Ok(account) = self.account(&account_id).await { + accounts.push(account); + } + } + + Ok(accounts) + } + + /// Update account info + pub async fn update_account(&self, member: Member) -> Result<(), std::io::Error> { + // Ensure account exist + if self.account_cfg(&member.id()).is_some() { + let account_cfg_path = self.account_cfg_path(&member.id()); + Member::write_to(&member, account_cfg_path).await?; + return Ok(()); + } + + Err(Error::new(ErrorKind::NotFound, "Account not found!")) + } + + /// Register an account to user directory + pub async fn register_account(&self, member: Member) -> Result<(), std::io::Error> { + // Ensure account not exist + if self.account_cfg(&member.id()).is_some() { + return Err(Error::new( + ErrorKind::DirectoryNotEmpty, + format!("Account `{}` already registered!", member.id()), + )); + } + + // Ensure accounts directory exists + let accounts_dir = self + .local_path + .join(USER_FILE_ACCOUNTS.replace(SELF_ID, "")); + if !accounts_dir.exists() { + fs::create_dir_all(&accounts_dir)?; + } + + // Write config file to accounts dir + let account_cfg_path = self.account_cfg_path(&member.id()); + Member::write_to(&member, account_cfg_path).await?; + + Ok(()) + } + + /// Remove account from user directory + pub fn remove_account(&self, id: &MemberId) -> Result<(), std::io::Error> { + // Remove config file if exists + if let Some(account_cfg_path) = self.account_cfg(id) { + fs::remove_file(account_cfg_path)?; + } + + // Remove private key file if exists + if let Some(private_key_path) = self.account_private_key(id) + && private_key_path.exists() + { + fs::remove_file(private_key_path)?; + } + + Ok(()) + } + + /// Try to get the account's configuration file to determine if the account exists + pub fn account_cfg(&self, id: &MemberId) -> Option<PathBuf> { + let cfg_file = self.account_cfg_path(id); + if cfg_file.exists() { + Some(cfg_file) + } else { + None + } + } + + /// Try to get the account's private key file to determine if the account has a private key + pub fn account_private_key(&self, id: &MemberId) -> Option<PathBuf> { + let key_file = self.account_private_key_path(id); + if key_file.exists() { + Some(key_file) + } else { + None + } + } + + /// Check if account has private key + pub fn has_private_key(&self, id: &MemberId) -> bool { + self.account_private_key(id).is_some() + } + + /// Get the account's configuration file path, but do not check if the file exists + pub fn account_cfg_path(&self, id: &MemberId) -> PathBuf { + self.local_path + .join(USER_FILE_MEMBER.replace(SELF_ID, id.to_string().as_str())) + } + + /// Get the account's private key file path, but do not check if the file exists + pub fn account_private_key_path(&self, id: &MemberId) -> PathBuf { + self.local_path + .join(USER_FILE_KEY.replace(SELF_ID, id.to_string().as_str())) + } +} diff --git a/crates/vcs/src/workspace/vault.rs b/crates/vcs/src/data/vault.rs index 7f52c9c..9b400bb 100644 --- a/crates/vcs/src/workspace/vault.rs +++ b/crates/vcs/src/data/vault.rs @@ -12,7 +12,7 @@ use crate::{ SERVER_PATH_SHEETS, SERVER_PATH_VF_ROOT, }, current::{current_vault_path, find_vault_path}, - workspace::vault::config::VaultConfig, + data::vault::config::VaultConfig, }; pub mod config; diff --git a/crates/vcs/src/workspace/vault/config.rs b/crates/vcs/src/data/vault/config.rs index 5414e4d..11917de 100644 --- a/crates/vcs/src/workspace/vault/config.rs +++ b/crates/vcs/src/data/vault/config.rs @@ -2,8 +2,8 @@ use cfg_file::ConfigFile; use serde::{Deserialize, Serialize}; use crate::constants::SERVER_FILE_VAULT; -use crate::workspace::member::Member; -use crate::workspace::vault::MemberId; +use crate::data::member::Member; +use crate::data::vault::MemberId; #[derive(Serialize, Deserialize, ConfigFile)] #[cfg_file(path = SERVER_FILE_VAULT)] diff --git a/crates/vcs/src/workspace/vault/member.rs b/crates/vcs/src/data/vault/member.rs index 2d00081..9482d30 100644 --- a/crates/vcs/src/workspace/vault/member.rs +++ b/crates/vcs/src/data/vault/member.rs @@ -7,8 +7,8 @@ use std::{ use cfg_file::config::ConfigFile; use crate::{ - constants::{SERVER_FILE_MEMBER_INFO, SERVER_FILE_MEMBER_PUB}, - workspace::{ + constants::{SERVER_FILE_MEMBER_INFO, SERVER_FILE_MEMBER_PUB, SERVER_PATH_MEMBERS}, + data::{ member::Member, vault::{MemberId, Vault}, }, @@ -28,6 +28,45 @@ impl Vault { Err(Error::new(ErrorKind::NotFound, "Member not found!")) } + /// List all member IDs in the vault + pub fn member_ids(&self) -> Result<Vec<MemberId>, std::io::Error> { + let members_path = self.vault_path.join(SERVER_PATH_MEMBERS); + + if !members_path.exists() { + return Ok(Vec::new()); + } + + let mut member_ids = Vec::new(); + + for entry in fs::read_dir(members_path)? { + let entry = entry?; + let path = entry.path(); + + if path.is_file() + && let Some(file_name) = path.file_stem().and_then(|s| s.to_str()) + && path.extension().and_then(|s| s.to_str()) == Some("toml") + { + member_ids.push(file_name.to_string()); + } + } + + Ok(member_ids) + } + + /// Get all members + /// This method will read and deserialize member information, please pay attention to performance issues + pub async fn members(&self) -> Result<Vec<Member>, std::io::Error> { + let mut members = Vec::new(); + + for member_id in self.member_ids()? { + if let Ok(member) = self.member(&member_id).await { + members.push(member); + } + } + + Ok(members) + } + /// Update member info pub async fn update_member(&self, member: Member) -> Result<(), std::io::Error> { // Ensure member exist @@ -89,17 +128,13 @@ impl Vault { /// Get the member's configuration file path, but do not check if the file exists pub fn member_cfg_path(&self, id: &MemberId) -> PathBuf { - - self - .vault_path + self.vault_path .join(SERVER_FILE_MEMBER_INFO.replace(ID_PARAM, id.to_string().as_str())) } /// Get the member's public key file path, but do not check if the file exists pub fn member_key_path(&self, id: &MemberId) -> PathBuf { - - self - .vault_path + self.vault_path .join(SERVER_FILE_MEMBER_PUB.replace(ID_PARAM, id.to_string().as_str())) } } diff --git a/crates/vcs/src/workspace/vault/virtual_file.rs b/crates/vcs/src/data/vault/virtual_file.rs index c83f700..04b5236 100644 --- a/crates/vcs/src/workspace/vault/virtual_file.rs +++ b/crates/vcs/src/data/vault/virtual_file.rs @@ -16,7 +16,7 @@ use crate::{ SERVER_FILE_VF_META, SERVER_FILE_VF_VERSION_INSTANCE, SERVER_PATH_VF_ROOT, SERVER_PATH_VF_STORAGE, SERVER_PATH_VF_TEMP, }, - workspace::vault::{MemberId, Vault}, + data::vault::{MemberId, Vault}, }; pub type VirtualFileId = String; diff --git a/crates/vcs/src/workspace/user.rs b/crates/vcs/src/workspace/user.rs deleted file mode 100644 index 9bb4894..0000000 --- a/crates/vcs/src/workspace/user.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod accounts; diff --git a/crates/vcs/src/workspace/user/accounts.rs b/crates/vcs/src/workspace/user/accounts.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/vcs/src/workspace/user/accounts.rs +++ /dev/null @@ -1 +0,0 @@ - |
