diff options
| -rw-r--r-- | crates/env/src/member/manager.rs | 105 | ||||
| -rw-r--r-- | crates/env/src/vault.rs | 2 | ||||
| -rw-r--r-- | crates/env/src/vault/manage.rs | 1 | ||||
| -rw-r--r-- | crates/env/src/workspace.rs | 3 | ||||
| -rw-r--r-- | crates/env/src/workspace/local.rs (renamed from crates/env/src/local.rs) | 0 | ||||
| -rw-r--r-- | crates/env/src/workspace/local/config.rs (renamed from crates/env/src/local/config.rs) | 0 | ||||
| -rw-r--r-- | crates/env/src/workspace/local/manage.rs (renamed from crates/env/src/local/manage.rs) | 0 | ||||
| -rw-r--r-- | crates/env/src/workspace/member.rs (renamed from crates/env/src/member.rs) | 29 | ||||
| -rw-r--r-- | crates/env/src/workspace/vault.rs | 109 | ||||
| -rw-r--r-- | crates/env/src/workspace/vault/config.rs (renamed from crates/env/src/vault/config.rs) | 16 | ||||
| -rw-r--r-- | crates/env/src/workspace/vault/member.rs | 105 |
11 files changed, 242 insertions, 128 deletions
diff --git a/crates/env/src/member/manager.rs b/crates/env/src/member/manager.rs deleted file mode 100644 index a6a2b50..0000000 --- a/crates/env/src/member/manager.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::{ - fs, - io::{Error, ErrorKind}, - path::PathBuf, -}; - -use cfg_file::config::ConfigFile; - -use crate::{ - constants::{SERVER_FILE_MEMBER_INFO, SERVER_FILE_MEMBER_PUB}, - current::current_vault_path, - member::Member, - vault::config::MemberUuid, -}; - -pub struct VaultMemberManager; - -const UUID_PARAM: &str = "{member_uuid}"; - -impl VaultMemberManager { - /// Read member from configuration file - pub async fn member(uuid: MemberUuid) -> Result<Member, std::io::Error> { - if let Some(cfg_file) = Self::member_cfg(uuid)? { - let member = Member::read_from(cfg_file).await?; - return Ok(member); - } - - Err(Error::new(ErrorKind::NotFound, "Member not found!")) - } - - /// Register a member to vault - pub async fn register_member_to_vault(member: Member) -> Result<(), std::io::Error> { - // Ensure member not exist - if let Some(_) = Self::member_cfg(member.uuid())? { - return Err(Error::new( - ErrorKind::DirectoryNotEmpty, - format!("Member `{}` already registered!", member.id()), - )); - } - - // Wrtie config file to member dir - let member_cfg_path = Self::member_cfg_path(member.uuid())?; - Member::write_to(&member, member_cfg_path).await?; - - Ok(()) - } - - /// Remove member from vault - pub fn remove_member_from_vault(uuid: MemberUuid) -> Result<(), std::io::Error> { - // Ensure member exist - if let Some(member_cfg_path) = Self::member_cfg(uuid)? { - fs::remove_file(member_cfg_path)?; - } - - Ok(()) - } - - /// Try to get the member's configuration file to determine if the member exists - pub fn member_cfg(uuid: MemberUuid) -> Result<Option<PathBuf>, std::io::Error> { - let cfg_file = Self::member_cfg_path(uuid)?; - if cfg_file.exists() { - Ok(Some(cfg_file)) - } else { - Ok(None) - } - } - - /// Try to get the member's public key file to determine if the member has login permission - pub fn member_key(uuid: MemberUuid) -> Result<Option<PathBuf>, std::io::Error> { - let key_file = Self::member_key_path(uuid)?; - if key_file.exists() { - Ok(Some(key_file)) - } else { - Ok(None) - } - } - - /// Get the member's configuration file path, but do not check if the file exists - pub fn member_cfg_path(uuid: MemberUuid) -> Result<PathBuf, std::io::Error> { - // Has vault - let Some(vault) = current_vault_path() else { - return Err(Error::new(ErrorKind::NotFound, "Vault not found!")); - }; - - let path = - vault.join(SERVER_FILE_MEMBER_INFO.replace(UUID_PARAM, uuid.to_string().as_str())); - Ok(path) - } - - /// Get the member's public key file path, but do not check if the file exists - pub fn member_key_path(uuid: MemberUuid) -> Result<PathBuf, std::io::Error> { - // Has vault - let Some(vault) = current_vault_path() else { - return Err(Error::new(ErrorKind::NotFound, "Vault not found!")); - }; - - let path = - vault.join(SERVER_FILE_MEMBER_PUB.replace(UUID_PARAM, uuid.to_string().as_str())); - Ok(path) - } -} - -pub struct UserMemberManager; - -impl UserMemberManager {} diff --git a/crates/env/src/vault.rs b/crates/env/src/vault.rs deleted file mode 100644 index 72092c2..0000000 --- a/crates/env/src/vault.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod config; -pub mod manage; diff --git a/crates/env/src/vault/manage.rs b/crates/env/src/vault/manage.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/env/src/vault/manage.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/env/src/workspace.rs b/crates/env/src/workspace.rs new file mode 100644 index 0000000..d59a6e0 --- /dev/null +++ b/crates/env/src/workspace.rs @@ -0,0 +1,3 @@ +pub mod local; +pub mod member; +pub mod vault; diff --git a/crates/env/src/local.rs b/crates/env/src/workspace/local.rs index 72092c2..72092c2 100644 --- a/crates/env/src/local.rs +++ b/crates/env/src/workspace/local.rs diff --git a/crates/env/src/local/config.rs b/crates/env/src/workspace/local/config.rs index ddb7dd0..ddb7dd0 100644 --- a/crates/env/src/local/config.rs +++ b/crates/env/src/workspace/local/config.rs diff --git a/crates/env/src/local/manage.rs b/crates/env/src/workspace/local/manage.rs index 8b13789..8b13789 100644 --- a/crates/env/src/local/manage.rs +++ b/crates/env/src/workspace/local/manage.rs diff --git a/crates/env/src/member.rs b/crates/env/src/workspace/member.rs index 0a25151..b81bd82 100644 --- a/crates/env/src/member.rs +++ b/crates/env/src/workspace/member.rs @@ -1,17 +1,16 @@ -pub mod manager; +use std::collections::HashMap; use cfg_file::ConfigFile; use serde::{Deserialize, Serialize}; use string_proc::camel_case; -use uuid::Uuid; #[derive(Debug, Eq, Clone, ConfigFile, Serialize, Deserialize)] pub struct Member { - /// Member ID, used to intuitively display the name to other members + /// Member ID, the unique identifier of the member id: String, - /// Member Uuid, used to ensure the uniqueness of this member - uuid: Uuid, + /// Member metadata + metadata: HashMap<String, String>, } impl Default for Member { @@ -22,7 +21,7 @@ impl Default for Member { impl PartialEq for Member { fn eq(&self, other: &Self) -> bool { - self.uuid == other.uuid + self.id == other.id } } @@ -41,10 +40,9 @@ impl std::convert::AsRef<str> for Member { impl Member { /// Create member struct by id pub fn new(new_id: impl Into<String>) -> Self { - let uuid = Uuid::new_v4(); Self { id: camel_case!(new_id.into()), - uuid, + metadata: HashMap::new(), } } @@ -53,8 +51,17 @@ impl Member { self.id.clone() } - /// Get member uuid - pub fn uuid(&self) -> Uuid { - self.uuid + /// Get metadata + pub fn metadata(&self, key: impl Into<String>) -> Option<&String> { + self.metadata.get(&key.into()) + } + + /// Set metadata + pub fn set_metadata( + &mut self, + key: impl AsRef<str>, + value: impl Into<String>, + ) -> Option<String> { + self.metadata.insert(key.as_ref().to_string(), value.into()) } } diff --git a/crates/env/src/workspace/vault.rs b/crates/env/src/workspace/vault.rs new file mode 100644 index 0000000..b00ba80 --- /dev/null +++ b/crates/env/src/workspace/vault.rs @@ -0,0 +1,109 @@ +use std::{ + env::current_dir, + fs::{self, create_dir_all}, + path::PathBuf, +}; + +use cfg_file::config::ConfigFile; + +use crate::{ + constants::{ + SERVER_FILE_README, SERVER_FILE_VAULT, SERVER_PATH_MEMBER_PUB, SERVER_PATH_MEMBERS, + SERVER_PATH_SHEETS, SERVER_PATH_VIRTUAL_FILE_ROOT, + }, + current::{current_vault_path, find_vault_path}, + workspace::vault::config::VaultConfig, +}; + +pub mod config; +pub mod member; +pub mod vitrual_file; + +pub type MemberId = String; + +pub struct Vault { + config: VaultConfig, + vault_path: PathBuf, +} + +impl Vault { + /// Get vault path + pub fn vault_path(&self) -> &PathBuf { + &self.vault_path + } + + /// Initialize vault + pub fn init(config: VaultConfig, vault_path: impl Into<PathBuf>) -> Option<Self> { + let Some(vault_path) = find_vault_path(vault_path) else { + return None; + }; + Some(Self { config, vault_path }) + } + + /// Initialize vault + pub fn init_current_dir(config: VaultConfig) -> Option<Self> { + let Some(vault_path) = current_vault_path() else { + return None; + }; + Some(Self { config, vault_path }) + } + + /// Setup vault + pub async fn setup_vault(vault_path: impl Into<PathBuf>) -> Result<(), std::io::Error> { + let vault_path: PathBuf = vault_path.into(); + + // 1. Setup main config + let config = VaultConfig::default(); + VaultConfig::write_to(&config, vault_path.join(SERVER_FILE_VAULT)).await?; + + // 2. Setup sheets directory + create_dir_all(vault_path.join(SERVER_PATH_SHEETS))?; + + // 3. Setup key directory + create_dir_all(vault_path.join(SERVER_PATH_MEMBER_PUB))?; + + // 4. Setup member directory + create_dir_all(vault_path.join(SERVER_PATH_MEMBERS))?; + + // 5. Setup storage directory + create_dir_all(vault_path.join(SERVER_PATH_VIRTUAL_FILE_ROOT))?; + + // Final, generate README.md + let readme_content = format!( + "\ + # JustEnoughVCS Server Setup + + This directory contains the server configuration and data for `JustEnoughVCS`. + + ## User Authentication + To allow users to connect to this server, place their public keys in the `{}` directory. + Each public key file should correspond to a registered user. + + ## File Storage + All version-controlled files (Virtual File) are stored in the `{}` directory. + + ## License + This software is distributed under the MIT License. + + ## Support + Repository: `https://github.com/JustEnoughVCS/VersionControl` + Please report any issues or questions on the GitHub issue tracker. + + ## Thanks :) + Thank you for using `JustEnoughVCS!` + ", + SERVER_PATH_MEMBER_PUB, SERVER_PATH_VIRTUAL_FILE_ROOT + ) + .trim() + .to_string(); + fs::write(vault_path.join(SERVER_FILE_README), readme_content)?; + + Ok(()) + } + + /// Setup vault in current directory + pub async fn setup_vault_current_dir() -> Result<(), std::io::Error> { + Self::setup_vault(current_dir()?).await?; + Ok(()) + } +} diff --git a/crates/env/src/vault/config.rs b/crates/env/src/workspace/vault/config.rs index f4e97e6..983a9e5 100644 --- a/crates/env/src/vault/config.rs +++ b/crates/env/src/workspace/vault/config.rs @@ -1,11 +1,9 @@ use cfg_file::ConfigFile; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::constants::SERVER_FILE_VAULT; -use crate::member::Member; - -pub type MemberUuid = Uuid; +use crate::workspace::member::Member; +use crate::workspace::vault::MemberId; #[derive(Default, Serialize, Deserialize, ConfigFile)] #[cfg_file(path = SERVER_FILE_VAULT)] @@ -13,8 +11,8 @@ pub struct VaultConfig { /// Vault name, which can be used as the project name and generally serves as a hint vault_name: String, - /// Vault admin Uuids, a list of member Uuids representing administrator identities - vault_admin_list: Vec<MemberUuid>, + /// Vault admin id, a list of member id representing administrator identities + vault_admin_list: Vec<MemberId>, } impl VaultConfig { @@ -25,7 +23,7 @@ impl VaultConfig { // Add admin pub fn add_admin(&mut self, member: &Member) { - let uuid = member.uuid(); + let uuid = member.id(); if !self.vault_admin_list.contains(&uuid) { self.vault_admin_list.push(uuid); } @@ -33,7 +31,7 @@ impl VaultConfig { // Remove admin pub fn remove_admin(&mut self, member: &Member) { - let uuid = member.uuid(); - self.vault_admin_list.retain(|&x| x != uuid); + let id = member.id(); + self.vault_admin_list.retain(|x| x != &id); } } diff --git a/crates/env/src/workspace/vault/member.rs b/crates/env/src/workspace/vault/member.rs new file mode 100644 index 0000000..45452c5 --- /dev/null +++ b/crates/env/src/workspace/vault/member.rs @@ -0,0 +1,105 @@ +use std::{ + fs, + io::{Error, ErrorKind}, + path::PathBuf, +}; + +use cfg_file::config::ConfigFile; + +use crate::{ + constants::{SERVER_FILE_MEMBER_INFO, SERVER_FILE_MEMBER_PUB}, + workspace::{ + member::Member, + vault::{MemberId, Vault}, + }, +}; + +const ID_PARAM: &str = "{member_id}"; + +/// Member Manage +impl Vault { + /// Read member from configuration file + pub async fn member(&self, id: MemberId) -> Result<Member, std::io::Error> { + if let Some(cfg_file) = self.member_cfg(id) { + let member = Member::read_from(cfg_file).await?; + return Ok(member); + } + + Err(Error::new(ErrorKind::NotFound, "Member not found!")) + } + + /// Update member info + pub async fn update_member(&self, member: Member) -> Result<(), std::io::Error> { + // Ensure member exist + if let Some(_) = self.member_cfg(member.id()) { + let member_cfg_path = self.member_cfg_path(member.id()); + Member::write_to(&member, member_cfg_path).await?; + return Ok(()); + } + + Err(Error::new(ErrorKind::NotFound, "Member not found!")) + } + + /// Register a member to vault + pub async fn register_member_to_vault(&self, member: Member) -> Result<(), std::io::Error> { + // Ensure member not exist + if let Some(_) = self.member_cfg(member.id()) { + return Err(Error::new( + ErrorKind::DirectoryNotEmpty, + format!("Member `{}` already registered!", member.id()), + )); + } + + // Wrtie config file to member dir + let member_cfg_path = self.member_cfg_path(member.id()); + Member::write_to(&member, member_cfg_path).await?; + + Ok(()) + } + + /// Remove member from vault + pub fn remove_member_from_vault(&self, id: MemberId) -> Result<(), std::io::Error> { + // Ensure member exist + if let Some(member_cfg_path) = self.member_cfg(id) { + fs::remove_file(member_cfg_path)?; + } + + Ok(()) + } + + /// Try to get the member's configuration file to determine if the member exists + pub fn member_cfg(&self, id: MemberId) -> Option<PathBuf> { + let cfg_file = self.member_cfg_path(id); + if cfg_file.exists() { + Some(cfg_file) + } else { + None + } + } + + /// Try to get the member's public key file to determine if the member has login permission + pub fn member_key(&self, id: MemberId) -> Option<PathBuf> { + let key_file = self.member_key_path(id); + if key_file.exists() { + Some(key_file) + } else { + None + } + } + + /// Get the member's configuration file path, but do not check if the file exists + pub fn member_cfg_path(&self, id: MemberId) -> PathBuf { + let path = self + .vault_path + .join(SERVER_FILE_MEMBER_INFO.replace(ID_PARAM, id.to_string().as_str())); + path + } + + /// 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 { + let path = self + .vault_path + .join(SERVER_FILE_MEMBER_PUB.replace(ID_PARAM, id.to_string().as_str())); + path + } +} |
