From 40d9f406d03500cc3308d2e1d45abe46db8e62bb Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Sat, 17 Feb 2024 16:14:23 -0700 Subject: [PATCH] pass through raw params --- rpc-toolkit/src/command.rs | 382 ---------------------------- rpc-toolkit/src/handler/adapters.rs | 3 +- 2 files changed, 1 insertion(+), 384 deletions(-) delete mode 100644 rpc-toolkit/src/command.rs diff --git a/rpc-toolkit/src/command.rs b/rpc-toolkit/src/command.rs deleted file mode 100644 index 8ad8645..0000000 --- a/rpc-toolkit/src/command.rs +++ /dev/null @@ -1,382 +0,0 @@ -use std::sync::Arc; - -use clap::{ArgMatches, CommandFactory, FromArgMatches}; -use futures::future::BoxFuture; -use futures::FutureExt; -use imbl_value::Value; -use serde::de::DeserializeOwned; -use serde::ser::Serialize; -use yajrc::RpcError; - -use crate::util::{extract, Flat, PhantomData}; - -/// Stores a command's implementation for a given context -/// Can be created from anything that implements ParentCommand, AsyncCommand, or SyncCommand -pub struct DynCommand { - pub(crate) name: &'static str, - pub(crate) metadata: Context::Metadata, - pub(crate) implementation: Option>, - pub(crate) cli: Option>, - pub(crate) subcommands: Vec, -} - -pub(crate) struct Implementation { - pub(crate) async_impl: Arc< - dyn Fn(Context, Vec<&'static str>, Value) -> BoxFuture<'static, Result> - + Send - + Sync, - >, - pub(crate) sync_impl: - Box, Value) -> Result + Send + Sync>, -} - -pub(crate) struct CliBindings { - pub(crate) cmd: clap::Command, - pub(crate) parser: Box Fn(&'a ArgMatches) -> Result + Send + Sync>, - pub(crate) display: Option< - Box< - dyn Fn(Context, Vec<&'static str>, Value, Value) -> Result<(), imbl_value::Error> - + Send - + Sync, - >, - >, -} -impl CliBindings { - pub(crate) fn from_parent() -> Self { - Self { - cmd: Cmd::command(), - parser: Box::new(|matches| { - imbl_value::to_value(&Cmd::from_arg_matches(matches).map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - })?) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - }) - }), - display: None, - } - } - fn from_leaf>() -> Self - { - Self { - display: Some(Box::new(|ctx, parent_method, params, res| { - let parent_params = imbl_value::from_value(params.clone())?; - Ok(imbl_value::from_value::(params)?.display( - ctx, - ParentInfo { - method: parent_method, - params: parent_params, - }, - imbl_value::from_value(res)?, - )) - })), - ..Self::from_parent::() - } - } -} - -/// Must be implemented for all commands -/// Use `Parent = NoParent` if the implementation requires no arguments from the parent command -pub trait Command: DeserializeOwned + Sized + Send { - const NAME: &'static str; - type Parent: Command; -} - -/// Includes the parent method, and the arguments requested from the parent -/// Arguments are flattened out in the params object, so ensure that there are no collisions between the names of the arguments for your method and its parents -pub struct ParentInfo { - pub method: Vec<&'static str>, - pub params: T, -} - -/// This is automatically generated from a command based on its Parents. -/// It can be used to generate a proof that one of the parents contains the necessary arguments that a subcommand requires. -pub struct ParentChain(PhantomData); -pub struct Contains(PhantomData); -impl Contains { - pub fn none() -> Self { - Self(PhantomData) - } -} -impl From<(Contains, Contains)> for Contains> { - fn from(_: (Contains, Contains)) -> Self { - Self(PhantomData) - } -} - -/// Use this as a Parent if your command does not require any arguments from its parents -#[derive(serde::Deserialize, serde::Serialize)] -pub struct NoParent {} -impl Command for NoParent { - const NAME: &'static str = ""; - type Parent = NoParent; -} -impl ParentChain -where - Cmd: Command, -{ - pub fn child(&self) -> Contains { - Contains(PhantomData) - } - pub fn parent(&self) -> ParentChain { - ParentChain(PhantomData) - } -} - -/// Implement this for a command that has no implementation, but simply exists to organize subcommands -pub trait ParentCommand: Command { - fn metadata() -> Context::Metadata { - Context::Metadata::default() - } - fn subcommands(chain: ParentChain) -> Vec>; -} -impl DynCommand { - pub fn from_parent< - Cmd: ParentCommand + FromArgMatches + CommandFactory + Serialize, - >( - contains: Contains, - ) -> Self { - drop(contains); - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: None, - cli: Some(CliBindings::from_parent::()), - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } - pub fn from_parent_no_cli>( - contains: Contains, - ) -> Self { - drop(contains); - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: None, - cli: None, - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } -} - -/// Implement this for any command with an implementation -pub trait LeafCommand: Command { - type Ok: DeserializeOwned + Serialize + Send; - type Err: From + Into + Send; - fn metadata() -> Context::Metadata { - Context::Metadata::default() - } - fn display(self, ctx: Context, parent: ParentInfo, res: Self::Ok); - fn subcommands(chain: ParentChain) -> Vec> { - drop(chain); - Vec::new() - } -} - -/// Implement this if your Command's implementation is async -#[async_trait::async_trait] -pub trait AsyncCommand: LeafCommand { - async fn implementation( - self, - ctx: Context, - parent: ParentInfo, - ) -> Result; -} -impl Implementation { - fn for_async>(contains: Contains) -> Self { - drop(contains); - Self { - async_impl: Arc::new(|ctx, parent_method, params| { - async move { - let parent_params = extract::(¶ms)?; - imbl_value::to_value( - &extract::(¶ms)? - .implementation( - ctx, - ParentInfo { - method: parent_method, - params: parent_params, - }, - ) - .await - .map_err(|e| e.into())?, - ) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::PARSE_ERROR - }) - } - .boxed() - }), - sync_impl: Box::new(|ctx, parent_method, params| { - let parent_params = extract::(¶ms)?; - imbl_value::to_value( - &ctx.runtime() - .block_on( - extract::(¶ms) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - })? - .implementation( - ctx, - ParentInfo { - method: parent_method, - params: parent_params, - }, - ), - ) - .map_err(|e| e.into())?, - ) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::PARSE_ERROR - }) - }), - } - } -} -impl DynCommand { - pub fn from_async + FromArgMatches + CommandFactory + Serialize>( - contains: Contains, - ) -> Self { - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: Some(Implementation::for_async::(contains)), - cli: Some(CliBindings::from_leaf::()), - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } - pub fn from_async_no_cli>(contains: Contains) -> Self { - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: Some(Implementation::for_async::(contains)), - cli: None, - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } -} - -/// Implement this if your Command's implementation is not async -pub trait SyncCommand: LeafCommand { - const BLOCKING: bool; - fn implementation( - self, - ctx: Context, - parent: ParentInfo, - ) -> Result; -} -impl Implementation { - fn for_sync>(contains: Contains) -> Self { - drop(contains); - Self { - async_impl: if Cmd::BLOCKING { - Arc::new(|ctx, parent_method, params| { - tokio::task::spawn_blocking(move || { - let parent_params = extract::(¶ms)?; - imbl_value::to_value( - &extract::(¶ms) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - })? - .implementation( - ctx, - ParentInfo { - method: parent_method, - params: parent_params, - }, - ) - .map_err(|e| e.into())?, - ) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::PARSE_ERROR - }) - }) - .map(|f| { - f.map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INTERNAL_ERROR - })? - }) - .boxed() - }) - } else { - Arc::new(|ctx, parent_method, params| { - async move { - let parent_params = extract::(¶ms)?; - imbl_value::to_value( - &extract::(¶ms) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - })? - .implementation( - ctx, - ParentInfo { - method: parent_method, - params: parent_params, - }, - ) - .map_err(|e| e.into())?, - ) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::PARSE_ERROR - }) - } - .boxed() - }) - }, - sync_impl: Box::new(|ctx, method, params| { - let parent = extract::(¶ms)?; - imbl_value::to_value( - &extract::(¶ms) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::INVALID_PARAMS_ERROR - })? - .implementation( - ctx, - ParentInfo { - method, - params: parent, - }, - ) - .map_err(|e| e.into())?, - ) - .map_err(|e| RpcError { - data: Some(e.to_string().into()), - ..yajrc::PARSE_ERROR - }) - }), - } - } -} -impl DynCommand { - pub fn from_sync + FromArgMatches + CommandFactory + Serialize>( - contains: Contains, - ) -> Self { - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: Some(Implementation::for_sync::(contains)), - cli: Some(CliBindings::from_leaf::()), - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } - pub fn from_sync_no_cli>(contains: Contains) -> Self { - Self { - name: Cmd::NAME, - metadata: Cmd::metadata(), - implementation: Some(Implementation::for_sync::(contains)), - cli: None, - subcommands: Cmd::subcommands(ParentChain::(PhantomData)), - } - } -} diff --git a/rpc-toolkit/src/handler/adapters.rs b/rpc-toolkit/src/handler/adapters.rs index 7cf1fb1..7f48550 100644 --- a/rpc-toolkit/src/handler/adapters.rs +++ b/rpc-toolkit/src/handler/adapters.rs @@ -502,8 +502,7 @@ where match context .call_remote( &full_method.join("."), - imbl_value::to_value(&Flat(params, inherited_params)) - .map_err(parse_error)?, + imbl_value::to_value(&raw_params).map_err(parse_error)?, ) .await {