From b4661cab407be10e3bcc7f0d6ca02a7098df4cc3 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Thu, 14 Dec 2023 19:04:05 -0700 Subject: [PATCH] wip --- rpc-toolkit/src/context.rs | 104 ++++++- rpc-toolkit/src/handler.rs | 525 ++++++++++++++++------------------- rpc-toolkit/src/lib.rs | 2 +- rpc-toolkit/tests/handler.rs | 61 ++-- 4 files changed, 385 insertions(+), 307 deletions(-) diff --git a/rpc-toolkit/src/context.rs b/rpc-toolkit/src/context.rs index fd7016e..79720f8 100644 --- a/rpc-toolkit/src/context.rs +++ b/rpc-toolkit/src/context.rs @@ -1,8 +1,110 @@ -use std::any::Any; +use std::any::{Any, TypeId}; +use std::collections::BTreeSet; + use tokio::runtime::Handle; +use crate::Handler; + pub trait Context: Any + Send + 'static { fn runtime(&self) -> Handle { Handle::current() } } + +#[allow(private_bounds)] +pub trait IntoContext: sealed::Sealed + Any + Send + Sized + 'static { + fn type_ids_for + ?Sized>(handler: &H) -> Option>; + fn inner_type_id(&self) -> TypeId; + fn upcast(self) -> AnyContext; + fn downcast(value: AnyContext) -> Result; +} + +impl IntoContext for C { + fn type_ids_for + ?Sized>(handler: &H) -> Option> { + let mut set = BTreeSet::new(); + set.insert(TypeId::of::()); + Some(set) + } + fn inner_type_id(&self) -> TypeId { + TypeId::of::() + } + fn upcast(self) -> AnyContext { + AnyContext::new(self) + } + fn downcast(value: AnyContext) -> Result { + if value.0.type_id() == TypeId::of::() { + unsafe { Ok(value.downcast_unchecked::()) } + } else { + Err(value) + } + } +} + +pub enum EitherContext { + C1(C1), + C2(C2), +} +impl IntoContext for EitherContext { + fn type_ids_for + ?Sized>(handler: &H) -> Option> { + let mut set = BTreeSet::new(); + set.insert(TypeId::of::()); + set.insert(TypeId::of::()); + Some(set) + } + fn inner_type_id(&self) -> TypeId { + match self { + EitherContext::C1(c) => c.type_id(), + EitherContext::C2(c) => c.type_id(), + } + } + fn downcast(value: AnyContext) -> Result { + if value.inner_type_id() == TypeId::of::() { + Ok(EitherContext::C1(C1::downcast(value)?)) + } else if value.inner_type_id() == TypeId::of::() { + Ok(EitherContext::C2(C2::downcast(value)?)) + } else { + Err(value) + } + } + fn upcast(self) -> AnyContext { + match self { + Self::C1(c) => AnyContext::new(c), + Self::C2(c) => AnyContext::new(c), + } + } +} + +pub struct AnyContext(Box); +impl AnyContext { + pub fn new(value: C) -> Self { + Self(Box::new(value)) + } + unsafe fn downcast_unchecked(self) -> C { + unsafe { + let raw: *mut dyn Context = Box::into_raw(self.0); + *Box::from_raw(raw as *mut C) + } + } +} + +impl IntoContext for AnyContext { + fn type_ids_for + ?Sized>(_: &H) -> Option> { + None + } + fn inner_type_id(&self) -> TypeId { + self.0.type_id() + } + fn downcast(value: AnyContext) -> Result { + Ok(value) + } + fn upcast(self) -> AnyContext { + self + } +} + +mod sealed { + pub(crate) trait Sealed {} + impl Sealed for C {} + impl Sealed for super::EitherContext {} + impl Sealed for super::AnyContext {} +} diff --git a/rpc-toolkit/src/handler.rs b/rpc-toolkit/src/handler.rs index 2131fe6..0e0c325 100644 --- a/rpc-toolkit/src/handler.rs +++ b/rpc-toolkit/src/handler.rs @@ -1,5 +1,7 @@ -use std::collections::{BTreeMap, VecDeque}; +use std::any::TypeId; +use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::marker::PhantomData; +use std::sync::Arc; use clap::{ArgMatches, Command, CommandFactory, FromArgMatches, Parser}; use imbl_value::Value; @@ -7,16 +9,18 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use yajrc::RpcError; +use crate::context::{AnyContext, IntoContext}; +use crate::handler; use crate::util::{combine, internal_error, invalid_params, Flat}; struct HandleAnyArgs { - context: Box, + context: AnyContext, parent_method: Vec<&'static str>, method: VecDeque<&'static str>, params: Value, } impl HandleAnyArgs { - fn downcast(self) -> Result, imbl_value::Error> + fn downcast(self) -> Result, imbl_value::Error> where H: Handler, H::Params: DeserializeOwned, @@ -29,38 +33,34 @@ impl HandleAnyArgs { params, } = self; Ok(HandleArgs { - context, + context: Context::downcast(context).map_err(|_| imbl_value::Error { + kind: imbl_value::ErrorKind::Deserialization, + source: serde::ser::Error::custom("context does not match expected"), + })?, parent_method, method, params: imbl_value::from_value(params.clone())?, inherited_params: imbl_value::from_value(params.clone())?, }) } -}rams.clone())?, - }) - } } #[async_trait::async_trait] -trait HandleAny { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result; +trait HandleAny { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result; // async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result; } -trait CliBindingsAny { +trait CliBindingsAny { fn cli_command(&self) -> Command; fn cli_parse( &self, matches: &ArgMatches, ) -> Result<(VecDeque<&'static str>, Value), clap::Error>; - fn cli_display( - &self, - handle_args: HandleAnyArgs, - result: Value, - ) -> Result<(), RpcError>; + fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError>; } -pub trait CliBindings: Handler { +pub trait CliBindings: Handler { fn cli_command(&self) -> Command; fn cli_parse( &self, @@ -73,7 +73,7 @@ pub trait CliBindings: Handler { ) -> Result<(), Self::Err>; } -pub trait PrintCliResult: Handler { +pub trait PrintCliResult: Handler { fn print( &self, handle_args: HandleArgs, @@ -83,7 +83,7 @@ pub trait PrintCliResult: Handler { // impl PrintCliResult for H // where -// Context: crate::Context, +// Context: IntoContext, // H: Handler, // H::Ok: Display, // { @@ -103,7 +103,7 @@ struct WithCliBindings { impl Handler for WithCliBindings where - Context: crate::Context, + Context: IntoContext, H: Handler, { type Params = H::Params; @@ -132,7 +132,7 @@ where impl CliBindings for WithCliBindings where - Context: crate::Context, + Context: IntoContext, H: Handler, H::Params: FromArgMatches + CommandFactory + Serialize, H: PrintCliResult, @@ -176,18 +176,16 @@ where } } -trait HandleAnyWithCli: HandleAny + CliBindingsAny {} -impl + CliBindingsAny> - HandleAnyWithCli for T -{ -} +trait HandleAnyWithCli: HandleAny + CliBindingsAny {} +impl HandleAnyWithCli for T {} -enum DynHandler { - WithoutCli(Box>), - WithCli(Box>), +#[derive(Clone)] +enum DynHandler { + WithoutCli(Arc), + WithCli(Arc), } -impl HandleAny for DynHandler { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { +impl HandleAny for DynHandler { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { match self { DynHandler::WithoutCli(h) => h.handle_sync(handle_args), DynHandler::WithCli(h) => h.handle_sync(handle_args), @@ -195,47 +193,23 @@ impl HandleAny for DynHandler { } } -pub struct HandleArgs + ?Sized> { +pub struct HandleArgs + ?Sized> { context: Context, parent_method: Vec<&'static str>, method: VecDeque<&'static str>, params: H::Params, inherited_params: H::InheritedParams, } -impl HandleArgs -where - Context: crate::Context, - H: Handler, - H::Params: Serialize, - H::InheritedParams: Serialize, -{ - fn upcast( - Self { - context, - parent_method, - method, - params, - inherited_params, - }: Self, - ) -> Result, imbl_value::Error> { - Ok(HandleAnyArgs { - context, - parent_method, - method, - params: combine( - imbl_value::to_value(¶ms)?, - imbl_value::to_value(&inherited_params)?, - )?, - }) - } -} -pub trait Handler { +pub trait Handler { type Params; type InheritedParams; type Ok; type Err; fn handle_sync(&self, handle_args: HandleArgs) -> Result; + fn contexts(&self) -> Option> { + Context::type_ids_for(self) + } } struct AnyHandler { @@ -243,14 +217,14 @@ struct AnyHandler { handler: H, } -impl> HandleAny for AnyHandler +impl> HandleAny for AnyHandler where H::Params: DeserializeOwned, H::InheritedParams: DeserializeOwned, H::Ok: Serialize, RpcError: From, { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { imbl_value::to_value( &self .handler @@ -260,8 +234,7 @@ where } } -impl> CliBindingsAny - for AnyHandler +impl> CliBindingsAny for AnyHandler where H::Params: FromArgMatches + CommandFactory + Serialize + DeserializeOwned, H::InheritedParams: DeserializeOwned, @@ -277,11 +250,7 @@ where ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { self.handler.cli_parse(matches) } - fn cli_display( - &self, - handle_args: HandleAnyArgs, - result: Value, - ) -> Result<(), RpcError> { + fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError> { self.handler .cli_display( handle_args.downcast().map_err(invalid_params)?, @@ -295,83 +264,83 @@ where pub struct NoParams {} #[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] -enum Never {} +pub enum Never {} -pub(crate) struct EmptyHandler( - PhantomData<(Params, InheritedParams)>, -); -impl Handler - for EmptyHandler -{ - type Params = Params; - type InheritedParams = InheritedParams; - type Ok = Never; - type Err = RpcError; - fn handle_sync(&self, _: HandleArgs) -> Result { - Err(yajrc::METHOD_NOT_FOUND_ERROR) +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct Name(Option<&'static str>); +impl<'a> std::borrow::Borrow> for Name { + fn borrow(&self) -> &Option<&'a str> { + &self.0 } } -pub struct ParentHandler = EmptyHandler> { - handler: H, - subcommands: BTreeMap<&'static str, DynHandler>, +struct SubcommandMap(BTreeMap, DynHandler>>); +impl SubcommandMap { + fn insert( + &mut self, + ctx_tys: Option>, + name: Option<&'static str>, + handler: DynHandler, + ) { + let mut for_name = self.0.remove(&name).unwrap_or_default(); + if let Some(ctx_tys) = ctx_tys { + for ctx_ty in ctx_tys { + for_name.insert(Some(ctx_ty), handler.clone()); + } + } else { + for_name.insert(None, handler); + } + self.0.insert(Name(name), for_name); + } + + fn get<'a>(&'a self, ctx_ty: TypeId, name: Option<&str>) -> Option<(Name, &'a DynHandler)> { + if let Some((name, for_name)) = self.0.get_key_value(&name) { + if let Some(for_ctx) = for_name.get(&Some(ctx_ty)) { + Some((*name, for_ctx)) + } else { + for_name.get(&None).map(|h| (*name, h)) + } + } else { + None + } + } } -impl ParentHandler -where - EmptyHandler: CliBindings, -{ + +pub struct ParentHandler { + _phantom: PhantomData<(Params, InheritedParams)>, + subcommands: SubcommandMap, +} +impl ParentHandler { pub fn new() -> Self { Self { - handler: WithCliBindings { - _ctx: PhantomData, - handler: EmptyHandler(PhantomData).into(), - }, - subcommands: BTreeMap::new(), - } - } -} - -impl - ParentHandler> -{ - pub fn new_no_cli() -> Self { - Self { - handler: EmptyHandler(PhantomData).into(), - subcommands: BTreeMap::new(), - } - } -} - -impl> From for ParentHandler { - fn from(value: H) -> Self { - Self { - handler: value.into(), - subcommands: BTreeMap::new(), + _phantom: PhantomData, + subcommands: SubcommandMap(BTreeMap::new()), } } } struct InheritanceHandler< - Context: crate::Context, + Context: IntoContext, + Params, + InheritedParams, H: Handler, - SubH: Handler, - F: Fn(H::Params, H::InheritedParams) -> SubH::InheritedParams, + F: Fn(Params, InheritedParams) -> H::InheritedParams, > { - _phantom: PhantomData<(Context, H)>, - handler: SubH, + _phantom: PhantomData<(Context, Params, InheritedParams)>, + handler: H, inherit: F, } -impl< - Context: crate::Context, - H: Handler, - SubH: Handler, - F: Fn(H::Params, H::InheritedParams) -> SubH::InheritedParams, - > Handler for InheritanceHandler +impl Handler + for InheritanceHandler +where + Context: IntoContext, + H: Handler, + F: Fn(Params, InheritedParams) -> H::InheritedParams, { - type Params = SubH::Params; - type InheritedParams = Flat; - type Ok = SubH::Ok; - type Err = SubH::Err; + type Params = H::Params; + type InheritedParams = Flat; + type Ok = H::Ok; + type Err = H::Err; fn handle_sync( &self, HandleArgs { @@ -392,12 +361,12 @@ impl< } } -impl PrintCliResult for InheritanceHandler +impl PrintCliResult + for InheritanceHandler where - Context: crate::Context, - H: Handler, - SubH: Handler + PrintCliResult, - F: Fn(H::Params, H::InheritedParams) -> SubH::InheritedParams, + Context: IntoContext, + H: Handler + PrintCliResult, + F: Fn(Params, InheritedParams) -> H::InheritedParams, { fn print( &self, @@ -423,17 +392,19 @@ where } } -impl> ParentHandler { - pub fn subcommand(mut self, method: &'static str, handler: SubH) -> Self +impl ParentHandler { + pub fn subcommand(mut self, name: Option<&'static str>, handler: H) -> Self where - SubH: Handler + PrintCliResult + 'static, - SubH::Params: FromArgMatches + CommandFactory + Serialize + DeserializeOwned, - SubH::Ok: Serialize + DeserializeOwned, - RpcError: From, + Context: IntoContext, + H: Handler + PrintCliResult + 'static, + H::Params: FromArgMatches + CommandFactory + Serialize + DeserializeOwned, + H::Ok: Serialize + DeserializeOwned, + RpcError: From, { self.subcommands.insert( - method, - DynHandler::WithCli(Box::new(AnyHandler { + handler.contexts(), + name, + DynHandler::WithCli(Arc::new(AnyHandler { _ctx: PhantomData, handler: WithCliBindings { _ctx: PhantomData, @@ -443,29 +414,52 @@ impl> ParentHandler { ); self } - pub fn subcommand_with_inherited( + pub fn subcommand_no_cli(mut self, name: Option<&'static str>, handler: H) -> Self + where + Context: IntoContext, + H: Handler + 'static, + H::Params: DeserializeOwned, + H::Ok: Serialize, + RpcError: From, + { + self.subcommands.insert( + handler.contexts(), + name, + DynHandler::WithoutCli(Arc::new(AnyHandler { + _ctx: PhantomData, + handler, + })), + ); + self + } +} +impl ParentHandler +where + Params: DeserializeOwned + 'static, + InheritedParams: DeserializeOwned + 'static, +{ + pub fn subcommand_with_inherited( mut self, - method: &'static str, - handler: SubH, + name: Option<&'static str>, + handler: H, inherit: F, ) -> Self where - SubH: Handler + PrintCliResult + 'static, - SubH::Params: FromArgMatches + CommandFactory + Serialize + DeserializeOwned, - SubH::Ok: Serialize + DeserializeOwned, - H: 'static, - H::Params: DeserializeOwned, - H::InheritedParams: DeserializeOwned, - RpcError: From, - F: Fn(H::Params, H::InheritedParams) -> SubH::InheritedParams + 'static, + Context: IntoContext, + H: Handler + PrintCliResult + 'static, + H::Params: FromArgMatches + CommandFactory + Serialize + DeserializeOwned, + H::Ok: Serialize + DeserializeOwned, + RpcError: From, + F: Fn(Params, InheritedParams) -> H::InheritedParams + 'static, { self.subcommands.insert( - method, - DynHandler::WithCli(Box::new(AnyHandler { + handler.contexts(), + name, + DynHandler::WithCli(Arc::new(AnyHandler { _ctx: PhantomData, handler: WithCliBindings { _ctx: PhantomData, - handler: InheritanceHandler:: { + handler: InheritanceHandler:: { _phantom: PhantomData, handler, inherit, @@ -475,43 +469,26 @@ impl> ParentHandler { ); self } - pub fn subcommand_no_cli(mut self, method: &'static str, handler: SubH) -> Self - where - SubH: Handler + 'static, - SubH::Params: DeserializeOwned, - SubH::Ok: Serialize, - RpcError: From, - { - self.subcommands.insert( - method, - DynHandler::WithoutCli(Box::new(AnyHandler { - _ctx: PhantomData, - handler, - })), - ); - self - } - pub fn subcommand_with_inherited_no_cli( + pub fn subcommand_with_inherited_no_cli( mut self, - method: &'static str, - handler: SubH, + name: Option<&'static str>, + handler: H, inherit: F, ) -> Self where - SubH: Handler + 'static, - SubH::Params: DeserializeOwned, - SubH::Ok: Serialize, - H: 'static, + Context: IntoContext, + H: Handler + 'static, H::Params: DeserializeOwned, - H::InheritedParams: DeserializeOwned, - RpcError: From, - F: Fn(H::Params, H::InheritedParams) -> SubH::InheritedParams + 'static, + H::Ok: Serialize, + RpcError: From, + F: Fn(Params, InheritedParams) -> H::InheritedParams + 'static, { self.subcommands.insert( - method, - DynHandler::WithoutCli(Box::new(AnyHandler { + handler.contexts(), + name, + DynHandler::WithoutCli(Arc::new(AnyHandler { _ctx: PhantomData, - handler: InheritanceHandler:: { + handler: InheritanceHandler:: { _phantom: PhantomData, handler, inherit, @@ -522,17 +499,11 @@ impl> ParentHandler { } } -impl Handler for ParentHandler -where - Context: crate::Context, - H: Handler, - H::Params: Serialize, - H::InheritedParams: Serialize, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, +impl Handler + for ParentHandler { - type Params = H::Params; - type InheritedParams = H::InheritedParams; + type Params = Params; + type InheritedParams = InheritedParams; type Ok = Value; type Err = RpcError; fn handle_sync( @@ -543,71 +514,74 @@ where mut method, params, inherited_params, - }: HandleArgs, + }: HandleArgs, ) -> Result { - if let Some(cmd) = method.pop_front() { + let cmd = method.pop_front(); + if let Some(cmd) = cmd { parent_method.push(cmd); - if let Some(sub_handler) = self.subcommands.get(cmd) { - sub_handler.handle_sync(HandleAnyArgs { - context, - parent_method, - method, - params: imbl_value::to_value(&Flat(params, inherited_params)) - .map_err(invalid_params)?, - }) - } else { - Err(yajrc::METHOD_NOT_FOUND_ERROR) - } - } else { - self.handler - .handle_sync(HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - }) - .map_err(RpcError::from) - .and_then(|r| imbl_value::to_value(&r).map_err(internal_error)) } + if let Some((_, sub_handler)) = self.subcommands.get(context.inner_type_id(), cmd) { + sub_handler.handle_sync(HandleAnyArgs { + context: context.upcast(), + parent_method, + method, + params: imbl_value::to_value(&Flat(params, inherited_params)) + .map_err(invalid_params)?, + }) + } else { + Err(yajrc::METHOD_NOT_FOUND_ERROR) + } + } + fn contexts(&self) -> Option> { + let mut set = BTreeSet::new(); + for ctx_ty in self.subcommands.0.values().flat_map(|c| c.keys()) { + set.insert((*ctx_ty)?); + } + Some(set) } } -impl CliBindings for ParentHandler +impl CliBindings for ParentHandler where - Context: crate::Context, - H: CliBindings, - H::Params: FromArgMatches + CommandFactory + Serialize, - H::InheritedParams: Serialize, - H::Ok: PrintCliResult + Serialize + DeserializeOwned, - RpcError: From, + Params: FromArgMatches + CommandFactory + Serialize, + InheritedParams: Serialize, { fn cli_command(&self) -> Command { - H::Params::command().subcommands(self.subcommands.iter().filter_map(|(method, handler)| { - match handler { - DynHandler::WithCli(h) => Some(h.cli_command().name(method)), - DynHandler::WithoutCli(_) => None, - } - })) + // Params::command().subcommands(self.subcommands.0.iter().filter_map(|(name, handlers)| { + // handlers.iter().find_map(|(ctx_ty, handler)| { + // if let DynHandler::WithCli(h) = handler { + // h.cli_command() + // } + // }) + // })) + todo!() } fn cli_parse( &self, matches: &ArgMatches, ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - let (_, root_params) = self.handler.cli_parse(matches)?; - if let Some((sub, matches)) = matches.subcommand() { - if let Some((sub, DynHandler::WithCli(h))) = self.subcommands.get_key_value(sub) { - let (mut method, params) = h.cli_parse(matches)?; - method.push_front(*sub); - return Ok(( - method, - combine(root_params, params).map_err(|e| { - clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e) - })?, - )); - } - } - Ok((VecDeque::new(), root_params)) + // let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?) + // .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?; + // let (m, matches) = match matches.subcommand() { + // Some((m, matches)) => (Some(m), matches), + // None => (None, matches), + // }; + // if let Some((SubcommandKey((_, m)), DynHandler::WithCli(h))) = self + // .subcommands + // .get_key_value(&(TypeId::of::(), m)) + // { + // let (mut method, params) = h.cli_parse(matches)?; + // if let Some(m) = m { + // method.push_front(*m); + // } + // return Ok(( + // method, + // combine(root_params, params) + // .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e))?, + // )); + // } + // Ok((VecDeque::new(), root_params)) + todo!() } fn cli_display( &self, @@ -617,39 +591,30 @@ where mut method, params, inherited_params, - }: HandleArgs, + }: HandleArgs, result: Self::Ok, ) -> Result<(), Self::Err> { - if let Some(cmd) = method.pop_front() { - parent_method.push(cmd); - if let Some(DynHandler::WithCli(sub_handler)) = self.subcommands.get(cmd) { - sub_handler.cli_display( - HandleAnyArgs { - context, - parent_method, - method, - params: imbl_value::to_value(&Flat(params, inherited_params)) - .map_err(invalid_params)?, - }, - result, - ) - } else { - Err(yajrc::METHOD_NOT_FOUND_ERROR) - } - } else { - self.handler - .cli_display( - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - }, - imbl_value::from_value(result).map_err(internal_error)?, - ) - .map_err(RpcError::from) - } + // let cmd = method.pop_front(); + // if let Some(cmd) = cmd { + // parent_method.push(cmd); + // } + // if let Some(DynHandler::WithCli(sub_handler)) = + // self.subcommands.get(&(context.inner_type_id(), cmd)) + // { + // sub_handler.cli_display( + // HandleAnyArgs { + // context: AnyContext::new(context), + // parent_method, + // method, + // params: imbl_value::to_value(&Flat(params, inherited_params)) + // .map_err(invalid_params)?, + // }, + // result, + // ) + // } else { + // Err(yajrc::METHOD_NOT_FOUND_ERROR) + // } + todo!() } } @@ -667,7 +632,7 @@ pub fn from_fn(function: F) -> FromFn { impl Handler for FromFn where - Context: crate::Context, + Context: IntoContext, F: Fn() -> Result, { type Params = NoParams; @@ -681,7 +646,7 @@ where impl Handler for FromFn where - Context: crate::Context, + Context: IntoContext, F: Fn(Context) -> Result, { type Params = NoParams; @@ -694,7 +659,7 @@ where } impl Handler for FromFn where - Context: crate::Context, + Context: IntoContext, F: Fn(Context, Params) -> Result, Params: DeserializeOwned, { @@ -712,7 +677,7 @@ where impl Handler for FromFn where - Context: crate::Context, + Context: IntoContext, F: Fn(Context, Params, InheritedParams) -> Result, Params: DeserializeOwned, InheritedParams: DeserializeOwned, diff --git a/rpc-toolkit/src/lib.rs b/rpc-toolkit/src/lib.rs index da703a3..fec86b5 100644 --- a/rpc-toolkit/src/lib.rs +++ b/rpc-toolkit/src/lib.rs @@ -1,6 +1,6 @@ // pub use cli::*; // pub use command::*; -pub use context::Context; +pub use context::*; pub use handler::*; /// `#[command(...)]` /// - `#[command(cli_only)]` -> executed by CLI instead of RPC server (leaf commands only) diff --git a/rpc-toolkit/tests/handler.rs b/rpc-toolkit/tests/handler.rs index d0c643f..5b0eaeb 100644 --- a/rpc-toolkit/tests/handler.rs +++ b/rpc-toolkit/tests/handler.rs @@ -1,15 +1,16 @@ +use std::fmt::Display; +use std::path::PathBuf; use std::sync::Arc; use clap::Parser; -use rpc_toolkit::{Context, ParentHandler}; -use tokio::{ - runtime::{Handle, Runtime}, - sync::OnceCell, -}; +use rpc_toolkit::{from_fn, Context, ParentHandler}; +use serde::Deserialize; +use tokio::runtime::{Handle, Runtime}; +use tokio::sync::OnceCell; use url::Url; use yajrc::RpcError; -#[derive(Parser)] +#[derive(Parser, Deserialize)] #[command( name = "test-cli", version, @@ -17,13 +18,13 @@ use yajrc::RpcError; about = "This is a test cli application." )] struct CliConfig { - host: Option, + host: Option, config: Option, } impl CliConfig { fn load_rec(&mut self) -> Result<(), RpcError> { if let Some(path) = self.config.as_ref() { - let extra_cfg = + let mut extra_cfg: Self = serde_json::from_str(&std::fs::read_to_string(path).map_err(internal_error)?) .map_err(internal_error)?; extra_cfg.load_rec()?; @@ -46,27 +47,37 @@ struct CliContextSeed { struct CliContext(Arc); impl Context for CliContext { fn runtime(&self) -> Handle { - if self.rt.get().is_none() { - self.rt.set(Runtime::new().unwrap()).unwrap(); + if self.0.rt.get().is_none() { + self.0.rt.set(Runtime::new().unwrap()).unwrap(); } - self.rt.get().unwrap().handle() + self.0.rt.get().unwrap().handle().clone() } } -fn make_cli() -> CliApp { - CliApp::new::<_, CliConfig>(|mut config| { - config.load_rec()?; - Ok(CliContext(Arc::new(CliContextSeed { - host: config - .host - .unwrap_or_else("http://localhost:8080/rpc".parse().unwrap()), - rt: OnceCell::new(), - }))) - }) - .subcommands(make_api()) - .subcommands(ParentHandler::new().subcommand("hello", from_fn(|| Ok("world")))); -} +// fn make_cli() -> CliApp { +// CliApp::new::<_, CliConfig>(|mut config| { +// config.load_rec()?; +// Ok(CliContext(Arc::new(CliContextSeed { +// host: config +// .host +// .unwrap_or_else("http://localhost:8080/rpc".parse().unwrap()), +// rt: OnceCell::new(), +// }))) +// }) +// .subcommands(make_api()) +// .subcommands(ParentHandler::new().subcommand("hello", from_fn(|| Ok("world")))); +// } fn make_api() -> ParentHandler { - ParentHandler::new().subcommand("hello", from_fn(|| Ok("world"))) + ParentHandler::new().subcommand_no_cli( + Some("hello"), + from_fn(|_: CliContext| Ok::<_, RpcError>("world")), + ) +} + +pub fn internal_error(e: impl Display) -> RpcError { + RpcError { + data: Some(e.to_string().into()), + ..yajrc::INTERNAL_ERROR + } }