mirror of
https://github.com/Start9Labs/rpc-toolkit.git
synced 2026-03-30 12:21:58 +00:00
finish cli
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
use clap::ArgMatches;
|
use std::ffi::OsString;
|
||||||
|
|
||||||
|
use clap::{ArgMatches, CommandFactory, FromArgMatches};
|
||||||
|
use futures::future::BoxFuture;
|
||||||
|
use futures::{Future, FutureExt};
|
||||||
use imbl_value::Value;
|
use imbl_value::Value;
|
||||||
use reqwest::{Client, Method};
|
use reqwest::{Client, Method};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
@@ -8,11 +12,178 @@ use yajrc::{GenericRpcMethod, Id, RpcError, RpcRequest};
|
|||||||
|
|
||||||
use crate::command::{AsyncCommand, DynCommand, LeafCommand, ParentInfo};
|
use crate::command::{AsyncCommand, DynCommand, LeafCommand, ParentInfo};
|
||||||
use crate::util::{combine, invalid_params, parse_error};
|
use crate::util::{combine, invalid_params, parse_error};
|
||||||
use crate::ParentChain;
|
use crate::{CliBindings, ParentChain};
|
||||||
|
|
||||||
pub struct CliApp<Context> {
|
impl<Context> DynCommand<Context> {
|
||||||
pub(crate) command: DynCommand<Context>,
|
fn cli_app(&self) -> Option<clap::Command> {
|
||||||
pub(crate) make_ctx: Box<dyn FnOnce(&ArgMatches) -> Result<Context, RpcError>>,
|
if let Some(cli) = &self.cli {
|
||||||
|
Some(
|
||||||
|
cli.cmd
|
||||||
|
.clone()
|
||||||
|
.name(self.name)
|
||||||
|
.subcommands(self.subcommands.iter().filter_map(|c| c.cli_app())),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn cmd_from_cli_matches(
|
||||||
|
&self,
|
||||||
|
matches: &ArgMatches,
|
||||||
|
parent: ParentInfo<Value>,
|
||||||
|
) -> Result<(Vec<&'static str>, Value, &DynCommand<Context>), RpcError> {
|
||||||
|
let params = combine(
|
||||||
|
parent.params,
|
||||||
|
(self
|
||||||
|
.cli
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.parser)(matches)?,
|
||||||
|
)?;
|
||||||
|
if let Some((cmd, matches)) = matches.subcommand() {
|
||||||
|
let mut method = parent.method;
|
||||||
|
method.push(self.name);
|
||||||
|
self.subcommands
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.name == cmd)
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.cmd_from_cli_matches(matches, ParentInfo { method, params })
|
||||||
|
} else {
|
||||||
|
Ok((parent.method, params, self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CliApp<Context> {
|
||||||
|
cli: CliBindings,
|
||||||
|
commands: Vec<DynCommand<Context>>,
|
||||||
|
}
|
||||||
|
impl<Context> CliApp<Context> {
|
||||||
|
pub fn new<Cmd: FromArgMatches + CommandFactory + Serialize>(
|
||||||
|
commands: Vec<DynCommand<Context>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
cli: CliBindings::from_parent::<Cmd>(),
|
||||||
|
commands,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn cmd_from_cli_matches(
|
||||||
|
&self,
|
||||||
|
matches: &ArgMatches,
|
||||||
|
) -> Result<(Vec<&'static str>, Value, &DynCommand<Context>), RpcError> {
|
||||||
|
if let Some((cmd, matches)) = matches.subcommand() {
|
||||||
|
Ok(self
|
||||||
|
.commands
|
||||||
|
.iter()
|
||||||
|
.find(|c| c.name == cmd)
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.cmd_from_cli_matches(
|
||||||
|
matches,
|
||||||
|
ParentInfo {
|
||||||
|
method: Vec::new(),
|
||||||
|
params: Value::Object(Default::default()),
|
||||||
|
},
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CliAppAsync<Context> {
|
||||||
|
app: CliApp<Context>,
|
||||||
|
make_ctx: Box<dyn FnOnce(Value) -> BoxFuture<'static, Result<Context, RpcError>> + Send>,
|
||||||
|
}
|
||||||
|
impl<Context> CliAppAsync<Context> {
|
||||||
|
pub fn new<
|
||||||
|
Cmd: FromArgMatches + CommandFactory + Serialize + DeserializeOwned + Send,
|
||||||
|
F: FnOnce(Cmd) -> Fut + Send + 'static,
|
||||||
|
Fut: Future<Output = Result<Context, RpcError>> + Send,
|
||||||
|
>(
|
||||||
|
make_ctx: F,
|
||||||
|
commands: Vec<DynCommand<Context>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
app: CliApp::new::<Cmd>(commands),
|
||||||
|
make_ctx: Box::new(|args| {
|
||||||
|
async { make_ctx(imbl_value::from_value(args).map_err(parse_error)?).await }.boxed()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn run(self, args: Vec<OsString>) -> Result<(), RpcError> {
|
||||||
|
let cmd = self
|
||||||
|
.app
|
||||||
|
.cli
|
||||||
|
.cmd
|
||||||
|
.clone()
|
||||||
|
.subcommands(self.app.commands.iter().filter_map(|c| c.cli_app()));
|
||||||
|
let matches = cmd.get_matches_from(args);
|
||||||
|
let make_ctx_args = (self.app.cli.parser)(&matches)?;
|
||||||
|
let ctx = (self.make_ctx)(make_ctx_args).await?;
|
||||||
|
let (parent_method, params, cmd) = self.app.cmd_from_cli_matches(&matches)?;
|
||||||
|
let display = &cmd
|
||||||
|
.cli
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.display;
|
||||||
|
let res = (cmd
|
||||||
|
.implementation
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.async_impl)(ctx, parent_method, params)
|
||||||
|
.await?;
|
||||||
|
if let Some(display) = display {
|
||||||
|
display(res).map_err(parse_error)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CliAppSync<Context> {
|
||||||
|
app: CliApp<Context>,
|
||||||
|
make_ctx: Box<dyn FnOnce(Value) -> Result<Context, RpcError> + Send>,
|
||||||
|
}
|
||||||
|
impl<Context> CliAppSync<Context> {
|
||||||
|
pub fn new<
|
||||||
|
Cmd: FromArgMatches + CommandFactory + Serialize + DeserializeOwned + Send,
|
||||||
|
F: FnOnce(Cmd) -> Result<Context, RpcError> + Send + 'static,
|
||||||
|
>(
|
||||||
|
make_ctx: F,
|
||||||
|
commands: Vec<DynCommand<Context>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
app: CliApp::new::<Cmd>(commands),
|
||||||
|
make_ctx: Box::new(|args| make_ctx(imbl_value::from_value(args).map_err(parse_error)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn run(self, args: Vec<OsString>) -> Result<(), RpcError> {
|
||||||
|
let cmd = self
|
||||||
|
.app
|
||||||
|
.cli
|
||||||
|
.cmd
|
||||||
|
.clone()
|
||||||
|
.subcommands(self.app.commands.iter().filter_map(|c| c.cli_app()));
|
||||||
|
let matches = cmd.get_matches_from(args);
|
||||||
|
let make_ctx_args = (self.app.cli.parser)(&matches)?;
|
||||||
|
let ctx = (self.make_ctx)(make_ctx_args)?;
|
||||||
|
let (parent_method, params, cmd) = self.app.cmd_from_cli_matches(&matches)?;
|
||||||
|
let display = &cmd
|
||||||
|
.cli
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.display;
|
||||||
|
let res = (cmd
|
||||||
|
.implementation
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
||||||
|
.sync_impl)(ctx, parent_method, params)?;
|
||||||
|
if let Some(display) = display {
|
||||||
|
display(res).map_err(parse_error)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@@ -98,7 +269,7 @@ where
|
|||||||
&method.join("."),
|
&method.join("."),
|
||||||
combine(
|
combine(
|
||||||
imbl_value::to_value(&self).map_err(invalid_params)?,
|
imbl_value::to_value(&self).map_err(invalid_params)?,
|
||||||
imbl_value::to_value(&parent.args).map_err(invalid_params)?,
|
imbl_value::to_value(&parent.params).map_err(invalid_params)?,
|
||||||
)?,
|
)?,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use clap::{ArgMatches, CommandFactory, FromArgMatches};
|
use clap::{ArgMatches, CommandFactory, FromArgMatches};
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
@@ -7,10 +6,9 @@ use futures::FutureExt;
|
|||||||
use imbl_value::Value;
|
use imbl_value::Value;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::ser::Serialize;
|
use serde::ser::Serialize;
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
use yajrc::RpcError;
|
use yajrc::RpcError;
|
||||||
|
|
||||||
use crate::util::{combine, extract, Flat};
|
use crate::util::{extract, Flat};
|
||||||
|
|
||||||
/// Stores a command's implementation for a given context
|
/// Stores a command's implementation for a given context
|
||||||
/// Can be created from anything that implements ParentCommand, AsyncCommand, or SyncCommand
|
/// Can be created from anything that implements ParentCommand, AsyncCommand, or SyncCommand
|
||||||
@@ -20,68 +18,21 @@ pub struct DynCommand<Context> {
|
|||||||
pub(crate) cli: Option<CliBindings>,
|
pub(crate) cli: Option<CliBindings>,
|
||||||
pub(crate) subcommands: Vec<Self>,
|
pub(crate) subcommands: Vec<Self>,
|
||||||
}
|
}
|
||||||
impl<Context> DynCommand<Context> {
|
|
||||||
pub(crate) fn cli_app(&self) -> Option<clap::Command> {
|
|
||||||
if let Some(cli) = &self.cli {
|
|
||||||
Some(
|
|
||||||
cli.cmd
|
|
||||||
.clone()
|
|
||||||
.name(self.name)
|
|
||||||
.subcommands(self.subcommands.iter().filter_map(|c| c.cli_app())),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) fn impl_from_cli_matches(
|
|
||||||
&self,
|
|
||||||
matches: &ArgMatches,
|
|
||||||
parent: Value,
|
|
||||||
) -> Result<Implementation<Context>, RpcError> {
|
|
||||||
let args = combine(
|
|
||||||
parent,
|
|
||||||
(self
|
|
||||||
.cli
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
|
||||||
.parser)(matches)?,
|
|
||||||
)?;
|
|
||||||
if let Some((cmd, matches)) = matches.subcommand() {
|
|
||||||
self.subcommands
|
|
||||||
.iter()
|
|
||||||
.find(|c| c.name == cmd)
|
|
||||||
.ok_or(yajrc::METHOD_NOT_FOUND_ERROR)?
|
|
||||||
.impl_from_cli_matches(matches, args)
|
|
||||||
} else if let Some(implementation) = self.implementation.clone() {
|
|
||||||
Ok(implementation)
|
|
||||||
} else {
|
|
||||||
Err(yajrc::METHOD_NOT_FOUND_ERROR)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Implementation<Context> {
|
pub(crate) struct Implementation<Context> {
|
||||||
pub(crate) async_impl: Arc<
|
pub(crate) async_impl: Box<
|
||||||
dyn Fn(Context, Vec<&'static str>, Value) -> BoxFuture<'static, Result<Value, RpcError>>,
|
dyn Fn(Context, Vec<&'static str>, Value) -> BoxFuture<'static, Result<Value, RpcError>>,
|
||||||
>,
|
>,
|
||||||
pub(crate) sync_impl: Arc<dyn Fn(Context, Vec<&'static str>, Value) -> Result<Value, RpcError>>,
|
pub(crate) sync_impl: Box<dyn Fn(Context, Vec<&'static str>, Value) -> Result<Value, RpcError>>,
|
||||||
}
|
|
||||||
impl<Context> Clone for Implementation<Context> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
async_impl: self.async_impl.clone(),
|
|
||||||
sync_impl: self.sync_impl.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CliBindings {
|
pub(crate) struct CliBindings {
|
||||||
cmd: clap::Command,
|
pub(crate) cmd: clap::Command,
|
||||||
parser: Box<dyn for<'a> Fn(&'a ArgMatches) -> Result<Value, RpcError> + Send + Sync>,
|
pub(crate) parser: Box<dyn for<'a> Fn(&'a ArgMatches) -> Result<Value, RpcError> + Send + Sync>,
|
||||||
display: Option<Box<dyn Fn(Value) -> Result<(), imbl_value::Error> + Send + Sync>>,
|
pub(crate) display: Option<Box<dyn Fn(Value) -> Result<(), imbl_value::Error> + Send + Sync>>,
|
||||||
}
|
}
|
||||||
impl CliBindings {
|
impl CliBindings {
|
||||||
fn from_parent<Cmd: FromArgMatches + CommandFactory + Serialize>() -> Self {
|
pub(crate) fn from_parent<Cmd: FromArgMatches + CommandFactory + Serialize>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cmd: Cmd::command(),
|
cmd: Cmd::command(),
|
||||||
parser: Box::new(|matches| {
|
parser: Box::new(|matches| {
|
||||||
@@ -118,13 +69,18 @@ pub trait Command: DeserializeOwned + Sized + Send {
|
|||||||
/// 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
|
/// 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<T> {
|
pub struct ParentInfo<T> {
|
||||||
pub method: Vec<&'static str>,
|
pub method: Vec<&'static str>,
|
||||||
pub args: T,
|
pub params: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is automatically generated from a command based on its Parents.
|
/// 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.
|
/// It can be used to generate a proof that one of the parents contains the necessary arguments that a subcommand requires.
|
||||||
pub struct ParentChain<Cmd: Command>(PhantomData<Cmd>);
|
pub struct ParentChain<Cmd: Command>(PhantomData<Cmd>);
|
||||||
pub struct Contains<T>(PhantomData<T>);
|
pub struct Contains<T>(PhantomData<T>);
|
||||||
|
impl Contains<NoParent> {
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<T, U> From<(Contains<T>, Contains<U>)> for Contains<Flat<T, U>> {
|
impl<T, U> From<(Contains<T>, Contains<U>)> for Contains<Flat<T, U>> {
|
||||||
fn from(_: (Contains<T>, Contains<U>)) -> Self {
|
fn from(_: (Contains<T>, Contains<U>)) -> Self {
|
||||||
Self(PhantomData)
|
Self(PhantomData)
|
||||||
@@ -142,9 +98,6 @@ impl<Cmd> ParentChain<Cmd>
|
|||||||
where
|
where
|
||||||
Cmd: Command,
|
Cmd: Command,
|
||||||
{
|
{
|
||||||
pub fn none(&self) -> Contains<NoParent> {
|
|
||||||
Contains(PhantomData)
|
|
||||||
}
|
|
||||||
pub fn child(&self) -> Contains<Cmd> {
|
pub fn child(&self) -> Contains<Cmd> {
|
||||||
Contains(PhantomData)
|
Contains(PhantomData)
|
||||||
}
|
}
|
||||||
@@ -198,20 +151,20 @@ pub trait AsyncCommand<Context>: LeafCommand {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Context: Send + 'static> Implementation<Context> {
|
impl<Context: crate::Context> Implementation<Context> {
|
||||||
fn for_async<Cmd: AsyncCommand<Context>>(contains: Contains<Cmd::Parent>) -> Self {
|
fn for_async<Cmd: AsyncCommand<Context>>(contains: Contains<Cmd::Parent>) -> Self {
|
||||||
drop(contains);
|
drop(contains);
|
||||||
Self {
|
Self {
|
||||||
async_impl: Arc::new(|ctx, method, params| {
|
async_impl: Box::new(|ctx, parent_method, params| {
|
||||||
async move {
|
async move {
|
||||||
let parent = extract::<Cmd::Parent>(¶ms)?;
|
let parent_params = extract::<Cmd::Parent>(¶ms)?;
|
||||||
imbl_value::to_value(
|
imbl_value::to_value(
|
||||||
&extract::<Cmd>(¶ms)?
|
&extract::<Cmd>(¶ms)?
|
||||||
.implementation(
|
.implementation(
|
||||||
ctx,
|
ctx,
|
||||||
ParentInfo {
|
ParentInfo {
|
||||||
method,
|
method: parent_method,
|
||||||
args: parent,
|
params: parent_params,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -224,11 +177,10 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
}),
|
}),
|
||||||
sync_impl: Arc::new(|ctx, method, params| {
|
sync_impl: Box::new(|ctx, parent_method, params| {
|
||||||
let parent = extract::<Cmd::Parent>(¶ms)?;
|
let parent_params = extract::<Cmd::Parent>(¶ms)?;
|
||||||
imbl_value::to_value(
|
imbl_value::to_value(
|
||||||
&Runtime::new()
|
&ctx.runtime()
|
||||||
.unwrap()
|
|
||||||
.block_on(
|
.block_on(
|
||||||
extract::<Cmd>(¶ms)
|
extract::<Cmd>(¶ms)
|
||||||
.map_err(|e| RpcError {
|
.map_err(|e| RpcError {
|
||||||
@@ -238,8 +190,8 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
.implementation(
|
.implementation(
|
||||||
ctx,
|
ctx,
|
||||||
ParentInfo {
|
ParentInfo {
|
||||||
method,
|
method: parent_method,
|
||||||
args: parent,
|
params: parent_params,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -253,7 +205,7 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<Context: Send + 'static> DynCommand<Context> {
|
impl<Context: crate::Context> DynCommand<Context> {
|
||||||
pub fn from_async<Cmd: AsyncCommand<Context> + FromArgMatches + CommandFactory + Serialize>(
|
pub fn from_async<Cmd: AsyncCommand<Context> + FromArgMatches + CommandFactory + Serialize>(
|
||||||
contains: Contains<Cmd::Parent>,
|
contains: Contains<Cmd::Parent>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -292,9 +244,9 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
drop(contains);
|
drop(contains);
|
||||||
Self {
|
Self {
|
||||||
async_impl: if Cmd::BLOCKING {
|
async_impl: if Cmd::BLOCKING {
|
||||||
Arc::new(|ctx, method, params| {
|
Box::new(|ctx, parent_method, params| {
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let parent = extract::<Cmd::Parent>(¶ms)?;
|
let parent_params = extract::<Cmd::Parent>(¶ms)?;
|
||||||
imbl_value::to_value(
|
imbl_value::to_value(
|
||||||
&extract::<Cmd>(¶ms)
|
&extract::<Cmd>(¶ms)
|
||||||
.map_err(|e| RpcError {
|
.map_err(|e| RpcError {
|
||||||
@@ -304,8 +256,8 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
.implementation(
|
.implementation(
|
||||||
ctx,
|
ctx,
|
||||||
ParentInfo {
|
ParentInfo {
|
||||||
method,
|
method: parent_method,
|
||||||
args: parent,
|
params: parent_params,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| e.into())?,
|
.map_err(|e| e.into())?,
|
||||||
@@ -324,9 +276,9 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
.boxed()
|
.boxed()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Arc::new(|ctx, method, params| {
|
Box::new(|ctx, parent_method, params| {
|
||||||
async move {
|
async move {
|
||||||
let parent = extract::<Cmd::Parent>(¶ms)?;
|
let parent_params = extract::<Cmd::Parent>(¶ms)?;
|
||||||
imbl_value::to_value(
|
imbl_value::to_value(
|
||||||
&extract::<Cmd>(¶ms)
|
&extract::<Cmd>(¶ms)
|
||||||
.map_err(|e| RpcError {
|
.map_err(|e| RpcError {
|
||||||
@@ -336,8 +288,8 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
.implementation(
|
.implementation(
|
||||||
ctx,
|
ctx,
|
||||||
ParentInfo {
|
ParentInfo {
|
||||||
method,
|
method: parent_method,
|
||||||
args: parent,
|
params: parent_params,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| e.into())?,
|
.map_err(|e| e.into())?,
|
||||||
@@ -350,7 +302,7 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
.boxed()
|
.boxed()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
sync_impl: Arc::new(|ctx, method, params| {
|
sync_impl: Box::new(|ctx, method, params| {
|
||||||
let parent = extract::<Cmd::Parent>(¶ms)?;
|
let parent = extract::<Cmd::Parent>(¶ms)?;
|
||||||
imbl_value::to_value(
|
imbl_value::to_value(
|
||||||
&extract::<Cmd>(¶ms)
|
&extract::<Cmd>(¶ms)
|
||||||
@@ -362,7 +314,7 @@ impl<Context: Send + 'static> Implementation<Context> {
|
|||||||
ctx,
|
ctx,
|
||||||
ParentInfo {
|
ParentInfo {
|
||||||
method,
|
method,
|
||||||
args: parent,
|
params: parent,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| e.into())?,
|
.map_err(|e| e.into())?,
|
||||||
|
|||||||
@@ -1,57 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use tokio::runtime::Handle;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
pub trait Context: Send + 'static {
|
||||||
use reqwest::Client;
|
fn runtime(&self) -> Handle {
|
||||||
use tokio::runtime::Runtime;
|
Handle::current()
|
||||||
use url::{Host, Url};
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref DEFAULT_CLIENT: Client = Client::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Context: Send {
|
|
||||||
fn runtime(&self) -> Arc<Runtime> {
|
|
||||||
Arc::new(Runtime::new().unwrap())
|
|
||||||
}
|
|
||||||
fn protocol(&self) -> &str {
|
|
||||||
"http"
|
|
||||||
}
|
|
||||||
fn host(&self) -> Host<&str> {
|
|
||||||
Host::Ipv4([127, 0, 0, 1].into())
|
|
||||||
}
|
|
||||||
fn port(&self) -> u16 {
|
|
||||||
8080
|
|
||||||
}
|
|
||||||
fn path(&self) -> &str {
|
|
||||||
"/"
|
|
||||||
}
|
|
||||||
fn url(&self) -> Url {
|
|
||||||
let mut url: Url = "http://localhost".parse().unwrap();
|
|
||||||
url.set_scheme(self.protocol()).expect("protocol");
|
|
||||||
url.set_host(Some(&self.host().to_string())).expect("host");
|
|
||||||
url.set_port(Some(self.port())).expect("port");
|
|
||||||
url.set_path(self.path());
|
|
||||||
url
|
|
||||||
}
|
|
||||||
fn client(&self) -> &Client {
|
|
||||||
&*DEFAULT_CLIENT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context for () {}
|
|
||||||
|
|
||||||
impl<'a, T: Context + 'a> From<T> for Box<dyn Context + 'a> {
|
|
||||||
fn from(ctx: T) -> Self {
|
|
||||||
Box::new(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Context for (T, U)
|
|
||||||
where
|
|
||||||
T: Context,
|
|
||||||
U: Send,
|
|
||||||
{
|
|
||||||
fn runtime(&self) -> Arc<Runtime> {
|
|
||||||
self.0.runtime()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub use cli::*;
|
pub use cli::*;
|
||||||
pub use command::*;
|
pub use command::*;
|
||||||
|
pub use context::Context;
|
||||||
/// `#[command(...)]`
|
/// `#[command(...)]`
|
||||||
/// - `#[command(cli_only)]` -> executed by CLI instead of RPC server (leaf commands only)
|
/// - `#[command(cli_only)]` -> executed by CLI instead of RPC server (leaf commands only)
|
||||||
/// - `#[command(rpc_only)]` -> no CLI bindings (leaf commands only)
|
/// - `#[command(rpc_only)]` -> no CLI bindings (leaf commands only)
|
||||||
@@ -24,10 +25,10 @@ pub use command::*;
|
|||||||
pub use rpc_toolkit_macro::command;
|
pub use rpc_toolkit_macro::command;
|
||||||
pub use {clap, futures, hyper, reqwest, serde, serde_json, tokio, url, yajrc};
|
pub use {clap, futures, hyper, reqwest, serde, serde_json, tokio, url, yajrc};
|
||||||
|
|
||||||
pub(crate) mod cli;
|
mod cli;
|
||||||
pub(crate) mod command;
|
mod command;
|
||||||
// pub mod command_helpers;
|
// pub mod command_helpers;
|
||||||
// mod context;
|
mod context;
|
||||||
// mod metadata;
|
// mod metadata;
|
||||||
// pub mod rpc_server_helpers;
|
// pub mod rpc_server_helpers;
|
||||||
pub(crate) mod util;
|
mod util;
|
||||||
|
|||||||
Reference in New Issue
Block a user