use serde::{Serialize, de::DeserializeOwned}; use std::any::{Any, TypeId}; use std::collections::HashMap; use std::sync::Arc; use tcp_connection::{error::TcpTargetError, instance::ConnectionInstance}; use tokio::{net::TcpStream, sync::Mutex}; pub trait Action where Args: Serialize + DeserializeOwned + Send, Return: Serialize + DeserializeOwned + Send, { fn action_name() -> &'static str; fn is_remote_action() -> bool; fn process( context: ActionContext, args: Args, ) -> impl std::future::Future> + Send; } #[derive(Default)] pub struct ActionContext { /// Whether the action is executed locally or remotely proc_on_local: bool, /// Whether the action being executed in the current context is a remote action is_remote_action: bool, /// The name of the action being executed action_name: String, /// The JSON-serialized arguments for the action action_args_json: String, /// The connection instance in the current context, instance: Option>>, /// Generic data storage for arbitrary types data: HashMap>, } impl ActionContext { /// Generate local context pub fn local() -> Self { ActionContext { proc_on_local: true, ..Default::default() } } /// Generate remote context pub fn remote() -> Self { ActionContext { proc_on_local: false, ..Default::default() } } /// Build connection instance from TcpStream pub fn build_instance(mut self, stream: TcpStream) -> Self { self.instance = Some(Arc::new(Mutex::new(ConnectionInstance::from(stream)))); self } /// Insert connection instance into context pub fn insert_instance(mut self, instance: ConnectionInstance) -> Self { self.instance = Some(Arc::new(Mutex::new(instance))); self } /// Pop connection instance from context pub fn pop_instance(&mut self) -> Option>> { self.instance.take() } } impl ActionContext { /// Whether the action is executed locally pub fn is_proc_on_local(&self) -> bool { self.proc_on_local } /// Whether the action is executed remotely pub fn is_proc_on_remote(&self) -> bool { !self.proc_on_local } /// Whether the action being executed in the current context is a remote action pub fn is_remote_action(&self) -> bool { self.is_remote_action } /// Set whether the action being executed in the current context is a remote action pub fn set_is_remote_action(&mut self, is_remote_action: bool) { self.is_remote_action = is_remote_action; } /// Get the connection instance in the current context pub fn instance(&self) -> &Option>> { &self.instance } /// Get a mutable reference to the connection instance in the current context pub fn instance_mut(&mut self) -> &mut Option>> { &mut self.instance } /// Get the action name from the context pub fn action_name(&self) -> &str { &self.action_name } /// Get the action arguments from the context pub fn action_args_json(&self) -> &String { &self.action_args_json } /// Set the action name in the context pub fn set_action_name(mut self, action_name: String) -> Self { self.action_name = action_name; self } /// Set the action arguments in the context pub fn set_action_args(mut self, action_args: String) -> Self { self.action_args_json = action_args; self } /// Insert arbitrary data in the context pub fn with_data(mut self, value: T) -> Self { self.data.insert(TypeId::of::(), Arc::new(value)); self } /// Insert arbitrary data as Arc in the context pub fn with_arc_data(mut self, value: Arc) -> Self { self.data.insert(TypeId::of::(), value); self } /// Insert arbitrary data in the context pub fn insert_data(&mut self, value: T) { self.data.insert(TypeId::of::(), Arc::new(value)); } /// Insert arbitrary data as Arc in the context pub fn insert_arc_data(&mut self, value: Arc) { self.data.insert(TypeId::of::(), value); } /// Get arbitrary data from the context pub fn get(&self) -> Option<&T> { self.data .get(&TypeId::of::()) .and_then(|arc| arc.downcast_ref::()) } /// Get arbitrary data as Arc from the context pub fn get_arc(&self) -> Option> { self.data .get(&TypeId::of::()) .and_then(|arc| Arc::clone(arc).downcast::().ok()) } /// Remove and return arbitrary data from the context pub fn remove(&mut self) -> Option> { self.data .remove(&TypeId::of::()) .and_then(|arc| arc.downcast::().ok()) } /// Check if the context contains data of a specific type pub fn contains(&self) -> bool { self.data.contains_key(&TypeId::of::()) } /// Take ownership of the context and extract data of a specific type pub fn take(mut self) -> (Self, Option>) { let value = self .data .remove(&TypeId::of::()) .and_then(|arc| arc.downcast::().ok()); (self, value) } }