From c4b6bcb0870d17c91afa0b0f4a9d8020bbf8208a Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 6 Oct 2025 02:14:03 +0800 Subject: Rename vcs_service to action_system for better naming clarity - Create new action_system crate with action framework - Create action_system_macros crate for procedural macros - Update vcs crate dependencies to use action_system - Maintain same functionality with improved naming --- crates/system_action/src/action.rs | 38 +++++++++++ crates/system_action/src/action_pool.rs | 108 ++++++++++++++++++++++++++++++++ crates/system_action/src/lib.rs | 5 ++ 3 files changed, 151 insertions(+) create mode 100644 crates/system_action/src/action.rs create mode 100644 crates/system_action/src/action_pool.rs create mode 100644 crates/system_action/src/lib.rs (limited to 'crates/system_action/src') diff --git a/crates/system_action/src/action.rs b/crates/system_action/src/action.rs new file mode 100644 index 0000000..14f1148 --- /dev/null +++ b/crates/system_action/src/action.rs @@ -0,0 +1,38 @@ +use tcp_connection::{error::TcpTargetError, instance::ConnectionInstance}; + +pub trait Action { + fn action_name() -> &'static str; + + fn is_remote_action() -> bool; + + fn process( + context: ActionContext, + args: Args, + ) -> impl std::future::Future> + Send; +} + +pub struct ActionContext { + // Whether the action is executed locally or remotely + local: bool, + + /// The connection instance in the current context, + /// used to interact with the machine on the other end + instance: ConnectionInstance, +} + +impl ActionContext { + /// Whether the action is executed locally + pub fn is_local(&self) -> bool { + self.local + } + + /// Whether the action is executed remotely + pub fn is_remote(&self) -> bool { + !self.local + } + + /// Get the connection instance in the current context + pub fn instance(&self) -> &ConnectionInstance { + &self.instance + } +} diff --git a/crates/system_action/src/action_pool.rs b/crates/system_action/src/action_pool.rs new file mode 100644 index 0000000..0a1a6c7 --- /dev/null +++ b/crates/system_action/src/action_pool.rs @@ -0,0 +1,108 @@ +use tcp_connection::error::TcpTargetError; + +use crate::action::{Action, ActionContext}; + +/// A pool of registered actions that can be processed by name +pub struct ActionPool { + /// HashMap storing action name to action implementation mapping + actions: std::collections::HashMap<&'static str, Box>, +} + +impl ActionPool { + /// Creates a new empty ActionPool + pub fn new() -> Self { + Self { + actions: std::collections::HashMap::new(), + } + } + + /// Registers an action type with the pool + /// + /// Usage: + /// ``` + /// action_pool.register::(); + /// ``` + pub fn register(&mut self) + where + A: Action + Send + Sync + 'static, + Args: serde::de::DeserializeOwned + Send + Sync + 'static, + Return: serde::Serialize + Send + Sync + 'static, + { + let action_name = A::action_name(); + self.actions.insert( + action_name, + Box::new(ActionWrapper::(std::marker::PhantomData)), + ); + } + + /// Processes an action by name with given context and arguments + /// + /// Usage: + /// ``` + /// let result = action_pool.process::("my_action", context, args).await?; + /// ``` + pub async fn process<'a, Args, Return>( + &'a self, + action_name: &'a str, + context: ActionContext, + args: Args, + ) -> Result + where + Args: serde::de::DeserializeOwned + Send + 'static, + Return: serde::Serialize + Send + 'static, + { + if let Some(action) = self.actions.get(action_name) { + let result = action.process_erased(context, Box::new(args)).await?; + let result = *result + .downcast::() + .map_err(|_| TcpTargetError::Unsupported("InvalidArguments".to_string()))?; + Ok(result) + } else { + Err(TcpTargetError::Unsupported("InvalidAction".to_string())) + } + } +} + +/// Trait for type-erased actions that can be stored in ActionPool +trait ActionErased: Send + Sync { + /// Processes the action with type-erased arguments and returns type-erased result + fn process_erased( + &self, + context: ActionContext, + args: Box, + ) -> std::pin::Pin< + Box< + dyn std::future::Future, TcpTargetError>> + + Send, + >, + >; +} + +/// Wrapper struct that implements ActionErased for concrete Action types +struct ActionWrapper(std::marker::PhantomData<(A, Args, Return)>); + +impl ActionErased for ActionWrapper +where + A: Action + Send + Sync, + Args: serde::de::DeserializeOwned + Send + Sync + 'static, + Return: serde::Serialize + Send + Sync + 'static, +{ + fn process_erased( + &self, + context: ActionContext, + args: Box, + ) -> std::pin::Pin< + Box< + dyn std::future::Future, TcpTargetError>> + + Send, + >, + > { + Box::pin(async move { + let args = *args + .downcast::() + .map_err(|_| TcpTargetError::Unsupported("InvalidArguments".to_string()))?; + let result = A::process(context, args).await?; + Ok(Box::new(result) as Box) + }) + } +} diff --git a/crates/system_action/src/lib.rs b/crates/system_action/src/lib.rs new file mode 100644 index 0000000..07be1bb --- /dev/null +++ b/crates/system_action/src/lib.rs @@ -0,0 +1,5 @@ +pub use action_system_macros::*; +pub extern crate action_system_macros as macros; + +pub mod action; +pub mod action_pool; -- cgit