From b0ae3b3b5c8b005b3f7cb2b26b17ae521a38c669 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 22 Sep 2025 16:49:51 +0800 Subject: Modify the file structure --- crates/env/src/local.rs | 2 - crates/env/src/local/config.rs | 37 ----------- crates/env/src/local/manage.rs | 1 - crates/env/src/member.rs | 60 ----------------- crates/env/src/member/manager.rs | 105 ----------------------------- crates/env/src/vault.rs | 2 - crates/env/src/vault/config.rs | 39 ----------- crates/env/src/vault/manage.rs | 1 - crates/env/src/workspace.rs | 3 + crates/env/src/workspace/local.rs | 2 + crates/env/src/workspace/local/config.rs | 37 +++++++++++ crates/env/src/workspace/local/manage.rs | 1 + crates/env/src/workspace/member.rs | 67 +++++++++++++++++++ crates/env/src/workspace/vault.rs | 109 +++++++++++++++++++++++++++++++ crates/env/src/workspace/vault/config.rs | 37 +++++++++++ crates/env/src/workspace/vault/member.rs | 105 +++++++++++++++++++++++++++++ 16 files changed, 361 insertions(+), 247 deletions(-) delete mode 100644 crates/env/src/local.rs delete mode 100644 crates/env/src/local/config.rs delete mode 100644 crates/env/src/local/manage.rs delete mode 100644 crates/env/src/member.rs delete mode 100644 crates/env/src/member/manager.rs delete mode 100644 crates/env/src/vault.rs delete mode 100644 crates/env/src/vault/config.rs delete mode 100644 crates/env/src/vault/manage.rs create mode 100644 crates/env/src/workspace.rs create mode 100644 crates/env/src/workspace/local.rs create mode 100644 crates/env/src/workspace/local/config.rs create mode 100644 crates/env/src/workspace/local/manage.rs create mode 100644 crates/env/src/workspace/member.rs create mode 100644 crates/env/src/workspace/vault.rs create mode 100644 crates/env/src/workspace/vault/config.rs create mode 100644 crates/env/src/workspace/vault/member.rs (limited to 'crates') diff --git a/crates/env/src/local.rs b/crates/env/src/local.rs deleted file mode 100644 index 72092c2..0000000 --- a/crates/env/src/local.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod config; -pub mod manage; diff --git a/crates/env/src/local/config.rs b/crates/env/src/local/config.rs deleted file mode 100644 index ddb7dd0..0000000 --- a/crates/env/src/local/config.rs +++ /dev/null @@ -1,37 +0,0 @@ -use cfg_file::ConfigFile; -use serde::{Deserialize, Serialize}; -use std::net::SocketAddr; - -use crate::constants::CLIENT_FILE_WORKSPACE; -use crate::constants::PORT; - -#[derive(Serialize, Deserialize, ConfigFile)] -#[cfg_file(path = CLIENT_FILE_WORKSPACE)] -pub struct LocalConfig { - /// The vault address, representing the upstream address of the local workspace, - /// to facilitate timely retrieval of new updates from the upstream source. - vault_addr: SocketAddr, -} - -impl Default for LocalConfig { - fn default() -> Self { - Self { - vault_addr: SocketAddr::V4(std::net::SocketAddrV4::new( - std::net::Ipv4Addr::new(127, 0, 0, 1), - PORT, - )), - } - } -} - -impl LocalConfig { - /// Set the vault address. - pub fn set_vault_addr(&mut self, addr: SocketAddr) { - self.vault_addr = addr; - } - - /// Get the vault address. - pub fn vault_addr(&self) -> SocketAddr { - self.vault_addr - } -} diff --git a/crates/env/src/local/manage.rs b/crates/env/src/local/manage.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/env/src/local/manage.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/env/src/member.rs b/crates/env/src/member.rs deleted file mode 100644 index 0a25151..0000000 --- a/crates/env/src/member.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub mod manager; - -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 - id: String, - - /// Member Uuid, used to ensure the uniqueness of this member - uuid: Uuid, -} - -impl Default for Member { - fn default() -> Self { - Self::new("default_user") - } -} - -impl PartialEq for Member { - fn eq(&self, other: &Self) -> bool { - self.uuid == other.uuid - } -} - -impl std::fmt::Display for Member { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.id) - } -} - -impl std::convert::AsRef for Member { - fn as_ref(&self) -> &str { - &self.id - } -} - -impl Member { - /// Create member struct by id - pub fn new(new_id: impl Into) -> Self { - let uuid = Uuid::new_v4(); - Self { - id: camel_case!(new_id.into()), - uuid, - } - } - - /// Get member id - pub fn id(&self) -> String { - self.id.clone() - } - - /// Get member uuid - pub fn uuid(&self) -> Uuid { - self.uuid - } -} 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 { - 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, 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, 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 { - // 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 { - // 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/config.rs b/crates/env/src/vault/config.rs deleted file mode 100644 index f4e97e6..0000000 --- a/crates/env/src/vault/config.rs +++ /dev/null @@ -1,39 +0,0 @@ -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; - -#[derive(Default, Serialize, Deserialize, ConfigFile)] -#[cfg_file(path = SERVER_FILE_VAULT)] -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, -} - -impl VaultConfig { - // Change name of the vault. - pub fn change_name(&mut self, name: impl Into) { - self.vault_name = name.into() - } - - // Add admin - pub fn add_admin(&mut self, member: &Member) { - let uuid = member.uuid(); - if !self.vault_admin_list.contains(&uuid) { - self.vault_admin_list.push(uuid); - } - } - - // Remove admin - pub fn remove_admin(&mut self, member: &Member) { - let uuid = member.uuid(); - self.vault_admin_list.retain(|&x| x != uuid); - } -} 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/workspace/local.rs b/crates/env/src/workspace/local.rs new file mode 100644 index 0000000..72092c2 --- /dev/null +++ b/crates/env/src/workspace/local.rs @@ -0,0 +1,2 @@ +pub mod config; +pub mod manage; diff --git a/crates/env/src/workspace/local/config.rs b/crates/env/src/workspace/local/config.rs new file mode 100644 index 0000000..ddb7dd0 --- /dev/null +++ b/crates/env/src/workspace/local/config.rs @@ -0,0 +1,37 @@ +use cfg_file::ConfigFile; +use serde::{Deserialize, Serialize}; +use std::net::SocketAddr; + +use crate::constants::CLIENT_FILE_WORKSPACE; +use crate::constants::PORT; + +#[derive(Serialize, Deserialize, ConfigFile)] +#[cfg_file(path = CLIENT_FILE_WORKSPACE)] +pub struct LocalConfig { + /// The vault address, representing the upstream address of the local workspace, + /// to facilitate timely retrieval of new updates from the upstream source. + vault_addr: SocketAddr, +} + +impl Default for LocalConfig { + fn default() -> Self { + Self { + vault_addr: SocketAddr::V4(std::net::SocketAddrV4::new( + std::net::Ipv4Addr::new(127, 0, 0, 1), + PORT, + )), + } + } +} + +impl LocalConfig { + /// Set the vault address. + pub fn set_vault_addr(&mut self, addr: SocketAddr) { + self.vault_addr = addr; + } + + /// Get the vault address. + pub fn vault_addr(&self) -> SocketAddr { + self.vault_addr + } +} diff --git a/crates/env/src/workspace/local/manage.rs b/crates/env/src/workspace/local/manage.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/crates/env/src/workspace/local/manage.rs @@ -0,0 +1 @@ + diff --git a/crates/env/src/workspace/member.rs b/crates/env/src/workspace/member.rs new file mode 100644 index 0000000..b81bd82 --- /dev/null +++ b/crates/env/src/workspace/member.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use cfg_file::ConfigFile; +use serde::{Deserialize, Serialize}; +use string_proc::camel_case; + +#[derive(Debug, Eq, Clone, ConfigFile, Serialize, Deserialize)] +pub struct Member { + /// Member ID, the unique identifier of the member + id: String, + + /// Member metadata + metadata: HashMap, +} + +impl Default for Member { + fn default() -> Self { + Self::new("default_user") + } +} + +impl PartialEq for Member { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl std::fmt::Display for Member { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.id) + } +} + +impl std::convert::AsRef for Member { + fn as_ref(&self) -> &str { + &self.id + } +} + +impl Member { + /// Create member struct by id + pub fn new(new_id: impl Into) -> Self { + Self { + id: camel_case!(new_id.into()), + metadata: HashMap::new(), + } + } + + /// Get member id + pub fn id(&self) -> String { + self.id.clone() + } + + /// Get metadata + pub fn metadata(&self, key: impl Into) -> Option<&String> { + self.metadata.get(&key.into()) + } + + /// Set metadata + pub fn set_metadata( + &mut self, + key: impl AsRef, + value: impl Into, + ) -> Option { + 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) -> Option { + 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 { + 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) -> 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/workspace/vault/config.rs b/crates/env/src/workspace/vault/config.rs new file mode 100644 index 0000000..983a9e5 --- /dev/null +++ b/crates/env/src/workspace/vault/config.rs @@ -0,0 +1,37 @@ +use cfg_file::ConfigFile; +use serde::{Deserialize, Serialize}; + +use crate::constants::SERVER_FILE_VAULT; +use crate::workspace::member::Member; +use crate::workspace::vault::MemberId; + +#[derive(Default, Serialize, Deserialize, ConfigFile)] +#[cfg_file(path = SERVER_FILE_VAULT)] +pub struct VaultConfig { + /// Vault name, which can be used as the project name and generally serves as a hint + vault_name: String, + + /// Vault admin id, a list of member id representing administrator identities + vault_admin_list: Vec, +} + +impl VaultConfig { + // Change name of the vault. + pub fn change_name(&mut self, name: impl Into) { + self.vault_name = name.into() + } + + // Add admin + pub fn add_admin(&mut self, member: &Member) { + let uuid = member.id(); + if !self.vault_admin_list.contains(&uuid) { + self.vault_admin_list.push(uuid); + } + } + + // Remove admin + pub fn remove_admin(&mut self, member: &Member) { + 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 { + 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 { + 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 { + 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 + } +} -- cgit