diff options
| author | 魏曹先生 <1992414357@qq.com> | 2025-11-05 16:47:55 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-05 16:47:55 +0800 |
| commit | 5b920746babf527b75a542da74500eb5895468a4 (patch) | |
| tree | 5e6df4b73fc2721a9b23e43a94d5051e4f4f535d /crates | |
| parent | b036692826f7c5e7e87e1bc1d311152f48fbe843 (diff) | |
| parent | f34fd7e803f0e52f526b7a56c09fdb262ed9b8aa (diff) | |
Merge pull request #35 from JustEnoughVCS/jvcs_dev_actions
Jvcs dev actions
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/vcs_actions/src/actions.rs | 9 | ||||
| -rw-r--r-- | crates/vcs_actions/src/actions/sheet_actions.rs | 156 | ||||
| -rw-r--r-- | crates/vcs_actions/src/registry/client_registry.rs | 3 | ||||
| -rw-r--r-- | crates/vcs_actions/src/registry/server_registry.rs | 3 | ||||
| -rw-r--r-- | crates/vcs_data/src/constants.rs | 2 | ||||
| -rw-r--r-- | crates/vcs_data/src/data/local/config.rs | 23 | ||||
| -rw-r--r-- | crates/vcs_data/src/data/sheet.rs | 10 |
7 files changed, 178 insertions, 28 deletions
diff --git a/crates/vcs_actions/src/actions.rs b/crates/vcs_actions/src/actions.rs index 795d2b0..51186fb 100644 --- a/crates/vcs_actions/src/actions.rs +++ b/crates/vcs_actions/src/actions.rs @@ -116,3 +116,12 @@ pub async fn auth_member( Err(TcpTargetError::NoResult("Auth failed.".to_string())) } + +/// The macro to write and return a result. +#[macro_export] +macro_rules! write_and_return { + ($instance:expr, $result:expr) => {{ + $instance.lock().await.write($result).await?; + return Ok($result); + }}; +} diff --git a/crates/vcs_actions/src/actions/sheet_actions.rs b/crates/vcs_actions/src/actions/sheet_actions.rs index b6ea51d..b4e07a7 100644 --- a/crates/vcs_actions/src/actions/sheet_actions.rs +++ b/crates/vcs_actions/src/actions/sheet_actions.rs @@ -1,13 +1,19 @@ +use std::io::ErrorKind; + use action_system::{action::ActionContext, macros::action_gen}; use serde::{Deserialize, Serialize}; use tcp_connection::error::TcpTargetError; use vcs_data::data::sheet::SheetName; -use crate::actions::{auth_member, check_connection_instance, try_get_vault}; +use crate::{ + actions::{auth_member, check_connection_instance, try_get_local_workspace, try_get_vault}, + write_and_return, +}; #[derive(Default, Serialize, Deserialize)] pub enum MakeSheetActionResult { Success, + SuccessRestore, // Fail AuthorizeFailed(String), @@ -36,31 +42,35 @@ pub async fn make_sheet_action( let vault = try_get_vault(&ctx)?; // Check if the sheet already exists - if vault.sheet(&sheet_name).await.is_ok() { - instance - .lock() - .await - .write(MakeSheetActionResult::SheetAlreadyExists) - .await?; - return Ok(MakeSheetActionResult::SheetAlreadyExists); + if let Ok(mut sheet) = vault.sheet(&sheet_name).await { + // If the sheet has no holder, assign it to the current member (restore operation) + if sheet.holder().is_none() { + sheet.set_holder(member_id); + match sheet.persist().await { + Ok(_) => { + write_and_return!(instance, MakeSheetActionResult::SuccessRestore); + } + Err(e) => { + write_and_return!( + instance, + MakeSheetActionResult::SheetCreationFailed(e.to_string()) + ); + } + } + } else { + write_and_return!(instance, MakeSheetActionResult::SheetAlreadyExists); + } } else { // Create the sheet match vault.create_sheet(&sheet_name, &member_id).await { Ok(_) => { - instance - .lock() - .await - .write(MakeSheetActionResult::Success) - .await?; - return Ok(MakeSheetActionResult::Success); + write_and_return!(instance, MakeSheetActionResult::Success); } Err(e) => { - instance - .lock() - .await - .write(MakeSheetActionResult::SheetCreationFailed(e.to_string())) - .await?; - return Ok(MakeSheetActionResult::SheetCreationFailed(e.to_string())); + write_and_return!( + instance, + MakeSheetActionResult::SheetCreationFailed(e.to_string()) + ); } } } @@ -77,3 +87,109 @@ pub async fn make_sheet_action( Err(TcpTargetError::NoResult("No result.".to_string())) } + +#[derive(Default, Serialize, Deserialize)] +pub enum DropSheetActionResult { + Success, + + // Fail + SheetInUse, + AuthorizeFailed(String), + SheetNotExists, + SheetDropFailed(String), + NoHolder, + NotOwner, + + #[default] + Unknown, +} + +#[action_gen] +pub async fn drop_sheet_action( + ctx: ActionContext, + sheet_name: SheetName, +) -> Result<DropSheetActionResult, TcpTargetError> { + let instance = check_connection_instance(&ctx)?; + + // Auth Member + let member_id = match auth_member(&ctx, instance).await { + Ok(id) => id, + Err(e) => { + return Ok(DropSheetActionResult::AuthorizeFailed(e.to_string())); + } + }; + + // Check sheet in use on local + if ctx.is_proc_on_local() { + let local_workspace = try_get_local_workspace(&ctx)?; + if let Some(sheet) = local_workspace.config().lock().await.sheet_in_use() { + if sheet == &sheet_name { + instance.lock().await.write(false).await?; + return Ok(DropSheetActionResult::SheetInUse); + } + instance.lock().await.write(true).await?; + } else { + instance.lock().await.write(true).await?; + } + } + + if ctx.is_proc_on_remote() { + // Check if client sheet is in use + let sheet_in_use = instance.lock().await.read::<bool>().await?; + if !sheet_in_use { + return Ok(DropSheetActionResult::SheetInUse); + } + + let vault = try_get_vault(&ctx)?; + + // Check if the sheet exists + let mut sheet = match vault.sheet(&sheet_name).await { + Ok(sheet) => sheet, + Err(e) => { + if e.kind() == ErrorKind::NotFound { + write_and_return!(instance, DropSheetActionResult::SheetNotExists); + } else { + write_and_return!( + instance, + DropSheetActionResult::SheetDropFailed(e.to_string()) + ); + } + } + }; + + // Get the sheet's holder + let Some(holder) = sheet.holder() else { + write_and_return!(instance, DropSheetActionResult::NoHolder); + }; + + // Verify the sheet's holder + if holder != &member_id { + write_and_return!(instance, DropSheetActionResult::NotOwner); + } + + // Drop the sheet + sheet.forget_holder(); + match sheet.persist().await { + Ok(_) => { + write_and_return!(instance, DropSheetActionResult::Success); + } + Err(e) => { + write_and_return!( + instance, + DropSheetActionResult::SheetDropFailed(e.to_string()) + ); + } + } + } + + if ctx.is_proc_on_local() { + let result = instance + .lock() + .await + .read::<DropSheetActionResult>() + .await?; + return Ok(result); + } + + Err(TcpTargetError::NoResult("No result.".to_string())) +} diff --git a/crates/vcs_actions/src/registry/client_registry.rs b/crates/vcs_actions/src/registry/client_registry.rs index a0b87a6..95c0939 100644 --- a/crates/vcs_actions/src/registry/client_registry.rs +++ b/crates/vcs_actions/src/registry/client_registry.rs @@ -13,7 +13,7 @@ use crate::{ local_actions::{ register_set_upstream_vault_action, register_update_to_latest_info_action, }, - sheet_actions::register_make_sheet_action, + sheet_actions::{register_drop_sheet_action, register_make_sheet_action}, }, connection::protocol::RemoteActionInvoke, }; @@ -27,6 +27,7 @@ fn register_actions(pool: &mut ActionPool) { // Sheet Actions register_make_sheet_action(pool); + register_drop_sheet_action(pool); } pub fn client_action_pool() -> ActionPool { diff --git a/crates/vcs_actions/src/registry/server_registry.rs b/crates/vcs_actions/src/registry/server_registry.rs index eade391..b99d697 100644 --- a/crates/vcs_actions/src/registry/server_registry.rs +++ b/crates/vcs_actions/src/registry/server_registry.rs @@ -2,7 +2,7 @@ use action_system::action_pool::ActionPool; use crate::actions::{ local_actions::{register_set_upstream_vault_action, register_update_to_latest_info_action}, - sheet_actions::register_make_sheet_action, + sheet_actions::{register_drop_sheet_action, register_make_sheet_action}, }; pub fn server_action_pool() -> ActionPool { @@ -14,6 +14,7 @@ pub fn server_action_pool() -> ActionPool { // Sheet Actions register_make_sheet_action(&mut pool); + register_drop_sheet_action(&mut pool); pool } diff --git a/crates/vcs_data/src/constants.rs b/crates/vcs_data/src/constants.rs index 1d17927..55662e7 100644 --- a/crates/vcs_data/src/constants.rs +++ b/crates/vcs_data/src/constants.rs @@ -54,7 +54,7 @@ pub const CLIENT_FILE_LATEST_INFO: &str = "./.jv/latest.json"; pub const CLIENT_FILE_SHEET_COPY: &str = "./.jv/sheets/{sheet_name}.copy.json"; // Client - Local Draft -pub const CLIENT_PATH_LOCAL_DRAFT: &str = "./.jv/drafts/{sheet_name}/"; +pub const CLIENT_PATH_LOCAL_DRAFT: &str = "./.jv/drafts/{account}_{sheet_name}/"; // Client - Other pub const CLIENT_FILE_IGNOREFILES: &str = "IGNORE_RULES.toml"; diff --git a/crates/vcs_data/src/data/local/config.rs b/crates/vcs_data/src/data/local/config.rs index 3dc5248..fa3b607 100644 --- a/crates/vcs_data/src/data/local/config.rs +++ b/crates/vcs_data/src/data/local/config.rs @@ -1,6 +1,7 @@ use cfg_file::ConfigFile; use cfg_file::config::ConfigFile; use serde::{Deserialize, Serialize}; +use std::io::Error; use std::net::SocketAddr; use std::path::Path; use std::path::PathBuf; @@ -17,6 +18,7 @@ use crate::data::member::MemberId; use crate::data::sheet::SheetName; use crate::data::vault::config::VaultUuid; +const ACCOUNT: &str = "{account}"; const SHEET_NAME: &str = "{sheet_name}"; #[derive(Serialize, Deserialize, ConfigFile)] @@ -68,8 +70,15 @@ impl LocalConfig { } /// Set the currently used account - pub fn set_current_account(&mut self, account: MemberId) { + pub fn set_current_account(&mut self, account: MemberId) -> Result<(), std::io::Error> { + if self.sheet_in_use().is_some() { + return Err(Error::new( + std::io::ErrorKind::DirectoryNotEmpty, + "Please exit the current sheet before switching accounts", + )); + } self.using_account = account; + Ok(()) } /// Set the currently used sheet @@ -107,7 +116,7 @@ impl LocalConfig { self.check_local_path_empty(&local_path).await?; // Get the draft folder path - let draft_folder = self.draft_folder(&sheet, &local_path); + let draft_folder = self.draft_folder(&self.using_account, &sheet, &local_path); if draft_folder.exists() { // Exists @@ -135,7 +144,7 @@ impl LocalConfig { let sheet_name = self.sheet_in_use().as_ref().unwrap().clone(); // Get the draft folder path - let draft_folder = self.draft_folder(&sheet_name, &local_path); + let draft_folder = self.draft_folder(&self.using_account, &sheet_name, &local_path); // Create the draft folder if it doesn't exist if !draft_folder.exists() { @@ -312,11 +321,15 @@ impl LocalConfig { /// Get draft folder pub fn draft_folder( &self, + account: &MemberId, sheet_name: &SheetName, local_workspace_path: impl Into<PathBuf>, ) -> PathBuf { + let account_str = snake_case!(account.as_str()); let sheet_name_str = snake_case!(sheet_name.as_str()); - let draft_path = CLIENT_PATH_LOCAL_DRAFT.replace(SHEET_NAME, &sheet_name_str); + let draft_path = CLIENT_PATH_LOCAL_DRAFT + .replace(ACCOUNT, &account_str) + .replace(SHEET_NAME, &sheet_name_str); local_workspace_path.into().join(draft_path) } @@ -330,7 +343,7 @@ impl LocalConfig { return None; }; - Some(self.draft_folder(sheet_name, current_dir)) + Some(self.draft_folder(&self.using_account, sheet_name, current_dir)) } } diff --git a/crates/vcs_data/src/data/sheet.rs b/crates/vcs_data/src/data/sheet.rs index ce450a6..69dc27d 100644 --- a/crates/vcs_data/src/data/sheet.rs +++ b/crates/vcs_data/src/data/sheet.rs @@ -89,6 +89,16 @@ impl<'a> Sheet<'a> { &self.data.mapping } + /// Forget the holder of this sheet + pub fn forget_holder(&mut self) { + self.data.holder = None; + } + + /// Set the holder of this sheet + pub fn set_holder(&mut self, holder: MemberId) { + self.data.holder = Some(holder); + } + /// Add an input package to the sheet pub fn add_input(&mut self, input_package: InputPackage) -> Result<(), std::io::Error> { if self.data.inputs.iter().any(|input| input == &input_package) { |
