summaryrefslogtreecommitdiff
path: root/systems
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-11 22:52:25 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-11 22:52:25 +0800
commit085bce616f68eb6c1586f7a7e1089b5f4cdd0155 (patch)
tree5782ae03692754845958ef06b92c56805ddd7bbc /systems
parent55c7ea778be2f3ce44d88440607ac8d4117e31d2 (diff)
Add vault and workspace systems with config management
Diffstat (limited to 'systems')
-rw-r--r--systems/vault/Cargo.toml14
-rw-r--r--systems/vault/src/func.rs40
-rw-r--r--systems/vault/src/lib.rs2
-rw-r--r--systems/vault/src/vault.rs41
-rw-r--r--systems/vault/src/vault/config.rs45
-rw-r--r--systems/vault/src/vault/error.rs40
-rw-r--r--systems/vault/src/vault/manager.rs37
-rw-r--r--systems/workspace/Cargo.toml14
-rw-r--r--systems/workspace/src/func.rs45
-rw-r--r--systems/workspace/src/lib.rs2
-rw-r--r--systems/workspace/src/workspace.rs38
-rw-r--r--systems/workspace/src/workspace/config.rs121
-rw-r--r--systems/workspace/src/workspace/error.rs40
-rw-r--r--systems/workspace/src/workspace/manager.rs38
14 files changed, 517 insertions, 0 deletions
diff --git a/systems/vault/Cargo.toml b/systems/vault/Cargo.toml
new file mode 100644
index 0000000..d0cfe7f
--- /dev/null
+++ b/systems/vault/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "vault_system"
+edition = "2024"
+version.workspace = true
+
+[dependencies]
+asset_system = { path = "../_asset" }
+config_system = { path = "../_config" }
+constants = { path = "../_constants" }
+framework = { path = "../_framework" }
+
+serde.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
diff --git a/systems/vault/src/func.rs b/systems/vault/src/func.rs
new file mode 100644
index 0000000..125c0ac
--- /dev/null
+++ b/systems/vault/src/func.rs
@@ -0,0 +1,40 @@
+use crate::vault::{Vault, config::VaultConfig, error::VaultOperationError, manager::VaultManager};
+use asset_system::asset::Handle;
+use framework::space::Space;
+use std::{env::current_dir, path::PathBuf};
+
+/// Create a vault at the current location
+pub async fn create_vault_here() -> Result<(), VaultOperationError> {
+ create_vault(current_dir()?).await
+}
+
+/// Create a vault at the specified location
+pub async fn create_vault(path: impl Into<PathBuf>) -> Result<(), VaultOperationError> {
+ let path = path.into();
+ let mut space = Space::new(Vault);
+ space.set_current_dir(path)?;
+ space.init_here().await?;
+
+ Ok(())
+}
+
+#[allow(unused)]
+/// Get a handle to the vault configuration file and edit its content
+pub async fn operate_vault_config<F>(
+ vault_path: impl Into<PathBuf>,
+ operate: F,
+) -> Result<(), VaultOperationError>
+where
+ F: AsyncFn(Handle<VaultConfig>),
+{
+ // Get the vault manager and set the context to the given vault path
+ let mut mgr = VaultManager::new();
+ mgr.get_space_mut().set_current_dir(vault_path.into())?;
+
+ // Obtain the vault configuration, and pass it to the function for execution
+ let config = mgr.vault_config()?;
+ let handle = config.get_handle().await?;
+ operate(handle).await;
+
+ Ok(())
+}
diff --git a/systems/vault/src/lib.rs b/systems/vault/src/lib.rs
new file mode 100644
index 0000000..c64eae4
--- /dev/null
+++ b/systems/vault/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod func;
+pub mod vault;
diff --git a/systems/vault/src/vault.rs b/systems/vault/src/vault.rs
new file mode 100644
index 0000000..262f8c5
--- /dev/null
+++ b/systems/vault/src/vault.rs
@@ -0,0 +1,41 @@
+use asset_system::rw::RWData;
+use constants::vault::{
+ dirs::{vault_dir_changes, vault_dir_ignore_rules, vault_dir_member_root, vault_dir_refsheets},
+ files::vault_file_config,
+};
+use framework::{SpaceRootTest, space::SpaceRoot};
+use tokio::fs;
+
+use crate::vault::config::VaultConfig;
+
+pub mod config;
+pub mod error;
+pub mod manager;
+
+#[derive(Default, SpaceRootTest)]
+pub struct Vault;
+
+impl SpaceRoot for Vault {
+ fn get_pattern() -> framework::space::SpaceRootFindPattern {
+ framework::space::SpaceRootFindPattern::IncludeFile(vault_file_config().into())
+ }
+
+ async fn create_space(
+ path: &std::path::Path,
+ ) -> Result<(), framework::space::error::SpaceError> {
+ let vault_toml = path.join(vault_file_config());
+
+ // Create configuration file
+ VaultConfig::write(VaultConfig::default(), &vault_toml)
+ .await
+ .map_err(|e| framework::space::error::SpaceError::Other(e.to_string()))?;
+
+ // Create directories
+ fs::create_dir_all(vault_dir_refsheets()).await?;
+ fs::create_dir_all(vault_dir_member_root()).await?;
+ fs::create_dir_all(vault_dir_ignore_rules()).await?;
+ fs::create_dir_all(vault_dir_changes()).await?;
+
+ Ok(())
+ }
+}
diff --git a/systems/vault/src/vault/config.rs b/systems/vault/src/vault/config.rs
new file mode 100644
index 0000000..7c4db70
--- /dev/null
+++ b/systems/vault/src/vault/config.rs
@@ -0,0 +1,45 @@
+use asset_system::{RWDataTest, rw::RWData};
+use config_system::rw::{read_config, write_config};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, RWDataTest)]
+pub struct VaultConfig {}
+
+impl RWData<VaultConfig> for VaultConfig {
+ type DataType = VaultConfig;
+
+ async fn read(
+ path: &std::path::PathBuf,
+ ) -> Result<Self::DataType, asset_system::error::DataReadError> {
+ let read_config = read_config(path).await;
+ match read_config {
+ Ok(config) => Ok(config),
+ Err(e) => Err(asset_system::error::DataReadError::IoError(
+ std::io::Error::new(std::io::ErrorKind::Other, e),
+ )),
+ }
+ }
+
+ async fn write(
+ data: Self::DataType,
+ path: &std::path::PathBuf,
+ ) -> Result<(), asset_system::error::DataWriteError> {
+ let write_config = write_config(path, &data).await;
+ match write_config {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ return Err(asset_system::error::DataWriteError::IoError(
+ std::io::Error::new(std::io::ErrorKind::Other, e),
+ ));
+ }
+ }
+ }
+
+ fn test_data() -> Self::DataType {
+ VaultConfig::default()
+ }
+
+ fn verify_data(data_a: Self::DataType, data_b: Self::DataType) -> bool {
+ &data_a == &data_b
+ }
+}
diff --git a/systems/vault/src/vault/error.rs b/systems/vault/src/vault/error.rs
new file mode 100644
index 0000000..b35a9c8
--- /dev/null
+++ b/systems/vault/src/vault/error.rs
@@ -0,0 +1,40 @@
+use asset_system::error::{DataApplyError, DataReadError, DataWriteError, HandleLockError};
+use framework::space::error::SpaceError;
+
+#[derive(thiserror::Error, Debug)]
+pub enum VaultOperationError {
+ #[error("IO error: {0}")]
+ Io(#[from] std::io::Error),
+
+ #[error("{0}")]
+ Other(String),
+
+ #[error("Configuration not found")]
+ ConfigNotFound,
+
+ #[error("Vault not found")]
+ VaultNotFound,
+
+ #[error("Handle lock error: {0}")]
+ HandleLock(#[from] HandleLockError),
+
+ #[error("Data read error: {0}")]
+ DataRead(#[from] DataReadError),
+
+ #[error("Data write error: {0}")]
+ DataWrite(#[from] DataWriteError),
+
+ #[error("Data apply error: {0}")]
+ DataApply(#[from] DataApplyError),
+}
+
+impl From<SpaceError> for VaultOperationError {
+ fn from(value: SpaceError) -> Self {
+ match value {
+ SpaceError::SpaceNotFound => VaultOperationError::VaultNotFound,
+ SpaceError::Io(error) => VaultOperationError::Io(error),
+ SpaceError::Other(e) => Self::Other(e),
+ _ => Self::Other(value.to_string()),
+ }
+ }
+}
diff --git a/systems/vault/src/vault/manager.rs b/systems/vault/src/vault/manager.rs
new file mode 100644
index 0000000..bae26d4
--- /dev/null
+++ b/systems/vault/src/vault/manager.rs
@@ -0,0 +1,37 @@
+use asset_system::asset::ReadOnlyAsset;
+use constants::vault::files::vault_file_config;
+use framework::space::Space;
+
+use crate::vault::{Vault, config::VaultConfig, error::VaultOperationError};
+
+pub struct VaultManager {
+ space: Space<Vault>,
+}
+
+impl VaultManager {
+ pub fn new() -> Self {
+ VaultManager {
+ space: Space::new(Vault),
+ }
+ }
+
+ /// Get an immutable reference to the internal Space
+ pub fn get_space(&self) -> &Space<Vault> {
+ &self.space
+ }
+
+ /// Get a mutable reference to the internal Space
+ pub fn get_space_mut(&mut self) -> &mut Space<Vault> {
+ &mut self.space
+ }
+
+ /// Get a read-only instance of the vault configuration file
+ pub fn vault_config(&self) -> Result<ReadOnlyAsset<VaultConfig>, VaultOperationError> {
+ let config_path = self.space.local_path(vault_file_config())?;
+ if !config_path.exists() {
+ return Err(VaultOperationError::ConfigNotFound);
+ }
+ let asset = ReadOnlyAsset::from(config_path);
+ Ok(asset)
+ }
+}
diff --git a/systems/workspace/Cargo.toml b/systems/workspace/Cargo.toml
new file mode 100644
index 0000000..c394bb3
--- /dev/null
+++ b/systems/workspace/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "workspace_system"
+edition = "2024"
+version.workspace = true
+
+[dependencies]
+asset_system = { path = "../_asset" }
+config_system = { path = "../_config" }
+constants = { path = "../_constants" }
+framework = { path = "../_framework" }
+
+serde.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
diff --git a/systems/workspace/src/func.rs b/systems/workspace/src/func.rs
new file mode 100644
index 0000000..4a1e57d
--- /dev/null
+++ b/systems/workspace/src/func.rs
@@ -0,0 +1,45 @@
+use std::{env::current_dir, path::PathBuf};
+
+use asset_system::asset::Handle;
+use framework::space::Space;
+
+use crate::workspace::{
+ Workspace, config::WorkspaceConfig, error::WorkspaceOperationError, manager::WorkspaceManager,
+};
+
+/// Create a workspace at the current location
+pub async fn create_workspace_here() -> Result<(), WorkspaceOperationError> {
+ create_workspace(current_dir()?).await
+}
+
+/// Create a workspace at the specified location
+pub async fn create_workspace(path: impl Into<PathBuf>) -> Result<(), WorkspaceOperationError> {
+ let path = path.into();
+ let mut space = Space::new(Workspace);
+ space.set_current_dir(path)?;
+ space.init_here().await?;
+
+ Ok(())
+}
+
+#[allow(unused)]
+/// Get a handle to the workspace configuration file and edit its content
+pub async fn operate_workspace_config<F>(
+ workspace_path: impl Into<PathBuf>,
+ operate: F,
+) -> Result<(), WorkspaceOperationError>
+where
+ F: AsyncFn(Handle<WorkspaceConfig>),
+{
+ // Get the workspace manager and set the context to the given workspace path
+ let mut mgr = WorkspaceManager::new();
+ mgr.get_space_mut().set_current_dir(workspace_path.into())?;
+
+ // Obtain the read-only asset of the workspace configuration file,
+ // lock it to get a writable handle, and pass it to the function for execution
+ let config = mgr.workspace_config()?;
+ let handle = config.get_handle().await?;
+ operate(handle).await;
+
+ Ok(())
+}
diff --git a/systems/workspace/src/lib.rs b/systems/workspace/src/lib.rs
new file mode 100644
index 0000000..9fd4ec8
--- /dev/null
+++ b/systems/workspace/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod func;
+pub mod workspace;
diff --git a/systems/workspace/src/workspace.rs b/systems/workspace/src/workspace.rs
new file mode 100644
index 0000000..6310146
--- /dev/null
+++ b/systems/workspace/src/workspace.rs
@@ -0,0 +1,38 @@
+use asset_system::rw::RWData;
+use constants::workspace::{dirs::workspace_dir_workspace, files::workspace_file_config};
+use framework::{SpaceRootTest, space::SpaceRoot};
+use tokio::fs::create_dir_all;
+
+use crate::workspace::config::WorkspaceConfig;
+
+pub mod config;
+pub mod error;
+pub mod manager;
+
+#[derive(Default, SpaceRootTest)]
+pub struct Workspace;
+
+impl SpaceRoot for Workspace {
+ fn get_pattern() -> framework::space::SpaceRootFindPattern {
+ framework::space::SpaceRootFindPattern::IncludeDotDir(workspace_dir_workspace().into())
+ }
+
+ async fn create_space(
+ path: &std::path::Path,
+ ) -> Result<(), framework::space::error::SpaceError> {
+ let workspace_root = path.join(workspace_dir_workspace());
+ let workspace_toml = path.join(workspace_file_config());
+
+ // Create workspace directory
+ create_dir_all(workspace_root)
+ .await
+ .map_err(framework::space::error::SpaceError::from)?;
+
+ // Create configuration file
+ WorkspaceConfig::write(WorkspaceConfig::default(), &workspace_toml)
+ .await
+ .map_err(|e| framework::space::error::SpaceError::Other(e.to_string()))?;
+
+ Ok(())
+ }
+}
diff --git a/systems/workspace/src/workspace/config.rs b/systems/workspace/src/workspace/config.rs
new file mode 100644
index 0000000..278ec08
--- /dev/null
+++ b/systems/workspace/src/workspace/config.rs
@@ -0,0 +1,121 @@
+use std::{io::Error, path::PathBuf};
+
+use asset_system::{
+ RWDataTest,
+ error::{DataReadError, DataWriteError},
+ rw::RWData,
+};
+use config_system::rw::{read_config, write_config};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, RWDataTest)]
+pub struct WorkspaceConfig {
+ /// Upstream address, pointing to the upstream Vault
+ #[serde(rename = "upstream")]
+ upstream: String,
+
+ /// Vault Uuid, used to ensure consistency between upstream and local
+ #[serde(rename = "uuid")]
+ uuid: Option<String>,
+
+ /// Account name used by self,
+ /// upstream Vault uses this parameter for identity verification
+ #[serde(rename = "account")]
+ use_accout: Option<String>,
+}
+
+impl WorkspaceConfig {
+ /// Returns a reference to the upstream address.
+ pub fn upstream(&self) -> &String {
+ &self.upstream
+ }
+
+ /// Sets the upstream address.
+ pub fn set_upstream(&mut self, upstream: String) {
+ self.upstream = upstream
+ }
+
+ /// Returns a new instance with the given upstream address.
+ pub fn with_upstream(mut self, upstream: String) -> Self {
+ self.upstream = upstream;
+ self
+ }
+
+ /// Returns a reference to the vault UUID, if any.
+ pub fn uuid(&self) -> Option<&String> {
+ self.uuid.as_ref()
+ }
+
+ /// Sets the vault UUID.
+ pub fn set_uuid(&mut self, uuid: String) {
+ self.uuid = Some(uuid)
+ }
+
+ /// Returns a new instance with the given vault UUID.
+ pub fn with_uuid(mut self, uuid: String) -> Self {
+ self.uuid = Some(uuid);
+ self
+ }
+
+ /// Clears the vault UUID.
+ pub fn erase_uuid(&mut self) {
+ self.uuid = None;
+ }
+
+ /// Returns a reference to the account name, if any.
+ pub fn account(&self) -> Option<&String> {
+ self.use_accout.as_ref()
+ }
+
+ /// Sets the account name.
+ pub fn set_account(&mut self, account: String) {
+ self.use_accout = Some(account)
+ }
+
+ /// Returns a new instance with the given account name.
+ pub fn with_account(mut self, account: String) -> Self {
+ self.use_accout = Some(account);
+ self
+ }
+
+ /// Clears the account name.
+ pub fn erase_account(&mut self) {
+ self.use_accout = None;
+ }
+}
+
+impl RWData<WorkspaceConfig> for WorkspaceConfig {
+ type DataType = WorkspaceConfig;
+
+ async fn read(path: &PathBuf) -> Result<Self::DataType, DataReadError> {
+ let read_config = read_config(path).await;
+ match read_config {
+ Ok(config) => Ok(config),
+ Err(e) => Err(DataReadError::IoError(Error::new(
+ std::io::ErrorKind::Other,
+ e,
+ ))),
+ }
+ }
+
+ async fn write(data: Self::DataType, path: &PathBuf) -> Result<(), DataWriteError> {
+ let write_config = write_config(path, &data).await;
+ match write_config {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ return Err(DataWriteError::IoError(Error::new(
+ std::io::ErrorKind::Other,
+ e,
+ )));
+ }
+ }
+ }
+
+ fn test_data() -> Self::DataType {
+ WorkspaceConfig::default()
+ }
+
+ fn verify_data(data_a: Self::DataType, data_b: Self::DataType) -> bool {
+ &data_a == &data_b
+ }
+}
diff --git a/systems/workspace/src/workspace/error.rs b/systems/workspace/src/workspace/error.rs
new file mode 100644
index 0000000..495558b
--- /dev/null
+++ b/systems/workspace/src/workspace/error.rs
@@ -0,0 +1,40 @@
+use asset_system::error::{DataApplyError, DataReadError, DataWriteError, HandleLockError};
+use framework::space::error::SpaceError;
+
+#[derive(thiserror::Error, Debug)]
+pub enum WorkspaceOperationError {
+ #[error("IO error: {0}")]
+ Io(#[from] std::io::Error),
+
+ #[error("{0}")]
+ Other(String),
+
+ #[error("Configuration not found")]
+ ConfigNotFound,
+
+ #[error("Workspace not found")]
+ WorkspaceNotFound,
+
+ #[error("Handle lock error: {0}")]
+ HandleLock(#[from] HandleLockError),
+
+ #[error("Data read error: {0}")]
+ DataRead(#[from] DataReadError),
+
+ #[error("Data write error: {0}")]
+ DataWrite(#[from] DataWriteError),
+
+ #[error("Data apply error: {0}")]
+ DataApply(#[from] DataApplyError),
+}
+
+impl From<SpaceError> for WorkspaceOperationError {
+ fn from(value: SpaceError) -> Self {
+ match value {
+ SpaceError::SpaceNotFound => WorkspaceOperationError::WorkspaceNotFound,
+ SpaceError::Io(error) => WorkspaceOperationError::Io(error),
+ SpaceError::Other(e) => Self::Other(e),
+ _ => Self::Other(value.to_string()),
+ }
+ }
+}
diff --git a/systems/workspace/src/workspace/manager.rs b/systems/workspace/src/workspace/manager.rs
new file mode 100644
index 0000000..9e319a1
--- /dev/null
+++ b/systems/workspace/src/workspace/manager.rs
@@ -0,0 +1,38 @@
+use crate::workspace::{Workspace, config::WorkspaceConfig, error::WorkspaceOperationError};
+use asset_system::asset::ReadOnlyAsset;
+use constants::workspace::files::workspace_file_config;
+use framework::space::Space;
+
+pub struct WorkspaceManager {
+ space: Space<Workspace>,
+}
+
+impl WorkspaceManager {
+ pub fn new() -> Self {
+ WorkspaceManager {
+ space: Space::new(Workspace),
+ }
+ }
+
+ /// Get an immutable reference to the internal Space
+ pub fn get_space(&self) -> &Space<Workspace> {
+ &self.space
+ }
+
+ /// Get a mutable reference to the internal Space
+ pub fn get_space_mut(&mut self) -> &mut Space<Workspace> {
+ &mut self.space
+ }
+
+ /// Get a read-only instance of the workspace configuration file
+ pub fn workspace_config(
+ &self,
+ ) -> Result<ReadOnlyAsset<WorkspaceConfig>, WorkspaceOperationError> {
+ let config_path = self.space.local_path(workspace_file_config())?;
+ if !config_path.exists() {
+ return Err(WorkspaceOperationError::ConfigNotFound);
+ }
+ let asset = ReadOnlyAsset::from(config_path);
+ Ok(asset)
+ }
+}