-
Notifications
You must be signed in to change notification settings - Fork 173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[proc macros]: client implementations with subscriptions doesn't work for HTTP client #448
Comments
Not sure I understand what this means, can you elaborate? |
Alright, To elaborate a little more, for the clients we have two internal traits to model the capabilities of the client:
If I define a trait #[rpc(server, client, namespace = "state")]
pub trait Rpc<Hash: Clone, StorageKey>
where
Hash: std::fmt::Debug,
{
/// Async method call example.
#[method(name = "getKeys")]
async fn storage_keys(&self, storage_key: StorageKey, hash: Option<Hash>) -> Result<Vec<StorageKey>, Error>;
} Expands to pub trait RpcClient<Hash: Clone, StorageKey>: jsonrpsee::types::traits::Client
where
Hash: Send + Sync + 'static + jsonrpsee::types::Serialize + std::fmt::Debug,
StorageKey:
Send + Sync + 'static + jsonrpsee::types::Serialize + jsonrpsee::types::DeserializeOwned,
{
///Invokes the RPC method `state_getKeys`.
#[must_use]
#[allow(
clippy::let_unit_value,
clippy::type_complexity,
clippy::type_repetition_in_bounds,
clippy::used_underscore_binding
)]
fn storage_keys<'life0, 'async_trait>(
&'life0 self,
storage_key: StorageKey,
hash: Option<Hash>,
) -> ::core::pin::Pin<
Box<
dyn ::core::future::Future<Output = Result<Vec<StorageKey>, Error>>
+ ::core::marker::Send
+ 'async_trait,
>,
>
where
'life0: 'async_trait,
Self: ::core::marker::Sync + 'async_trait,
{
Box::pin(async move {
if let ::core::option::Option::Some(__ret) =
::core::option::Option::None::<Result<Vec<StorageKey>, Error>>
{
return __ret;
}
let __self = self;
let storage_key = storage_key;
let hash = hash;
let __ret: Result<Vec<StorageKey>, Error> = {
__self
.request(
"state_getKeys",
<[_]>::into_vec(box [
jsonrpsee::types::__reexports::serde_json::to_value(&storage_key)?,
jsonrpsee::types::__reexports::serde_json::to_value(&hash)?,
])
.into(),
)
.await
};
#[allow(unreachable_code)]
__ret
})
}
}
impl<T, Hash: Clone, StorageKey> RpcClient<Hash, StorageKey> for T
where
T: jsonrpsee::types::traits::Client,
Hash: Send + Sync + 'static + jsonrpsee::types::Serialize + std::fmt::Debug,
StorageKey:
Send + Sync + 'static + jsonrpsee::types::Serialize + jsonrpsee::types::DeserializeOwned,
{
} If I define a trait #[rpc(server, client, namespace = "state")]
pub trait Rpc<Hash: Clone, StorageKey>
where
Hash: std::fmt::Debug,
{
/// Async method call example.
#[method(name = "getKeys")]
async fn storage_keys(&self, storage_key: StorageKey, hash: Option<Hash>) -> Result<Vec<StorageKey>, Error>;
/// Subscription that takes a `StorageKey` as input and produces a `Vec<Hash>`.
#[subscription(name = "subscribeStorage", item = Vec<Hash>)]
fn subscribe_storage(&self, keys: Option<Vec<StorageKey>>);
} Expands to pub trait RpcClient<Hash: Clone, StorageKey>: jsonrpsee::types::traits::SubscriptionClient
where
Hash: Send
+ Sync
+ 'static
+ jsonrpsee::types::Serialize
+ jsonrpsee::types::DeserializeOwned
+ std::fmt::Debug,
StorageKey:
Send + Sync + 'static + jsonrpsee::types::Serialize + jsonrpsee::types::DeserializeOwned,
{
///Invokes the RPC method `state_getKeys`.
#[must_use]
#[allow(
clippy::let_unit_value,
clippy::type_complexity,
clippy::type_repetition_in_bounds,
clippy::used_underscore_binding
)]
fn storage_keys<'life0, 'async_trait>(
&'life0 self,
storage_key: StorageKey,
hash: Option<Hash>,
) -> ::core::pin::Pin<
Box<
dyn ::core::future::Future<Output = Result<Vec<StorageKey>, Error>>
+ ::core::marker::Send
+ 'async_trait,
>,
>
where
'life0: 'async_trait,
Self: ::core::marker::Sync + 'async_trait,
{
Box::pin(async move {
if let ::core::option::Option::Some(__ret) =
::core::option::Option::None::<Result<Vec<StorageKey>, Error>>
{
return __ret;
}
let __self = self;
let storage_key = storage_key;
let hash = hash;
let __ret: Result<Vec<StorageKey>, Error> = {
__self
.request(
"state_getKeys",
<[_]>::into_vec(box [
jsonrpsee::types::__reexports::serde_json::to_value(&storage_key)?,
jsonrpsee::types::__reexports::serde_json::to_value(&hash)?,
])
.into(),
)
.await
};
#[allow(unreachable_code)]
__ret
})
}
///Subscribes to the RPC method `state_subscribeStorage`.
#[must_use]
#[allow(
clippy::let_unit_value,
clippy::type_complexity,
clippy::type_repetition_in_bounds,
clippy::used_underscore_binding
)]
fn subscribe_storage<'life0, 'async_trait>(
&'life0 self,
keys: Option<Vec<StorageKey>>,
) -> ::core::pin::Pin<
Box<
dyn ::core::future::Future<
Output = Result<
jsonrpsee::types::Subscription<Vec<Hash>>,
jsonrpsee::types::Error,
>,
> + ::core::marker::Send
+ 'async_trait,
>,
>
where
'life0: 'async_trait,
Self: ::core::marker::Sync + 'async_trait,
{
Box::pin(async move {
if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<
Result<jsonrpsee::types::Subscription<Vec<Hash>>, jsonrpsee::types::Error>,
> {
return __ret;
}
let __self = self;
let keys = keys;
let __ret: Result<jsonrpsee::types::Subscription<Vec<Hash>>, jsonrpsee::types::Error> = {
__self
.subscribe(
"state_subscribeStorage",
<[_]>::into_vec(box [jsonrpsee::types::__reexports::serde_json::to_value(
&keys,
)?])
.into(),
"state_unsubscribeStorage",
)
.await
};
#[allow(unreachable_code)]
__ret
})
}
}
impl<T, Hash: Clone, StorageKey> RpcClient<Hash, StorageKey> for T
where
T: jsonrpsee::types::traits::SubscriptionClient,
Hash: Send
+ Sync
+ 'static
+ jsonrpsee::types::Serialize
+ jsonrpsee::types::DeserializeOwned
+ std::fmt::Debug,
StorageKey:
Send + Sync + 'static + jsonrpsee::types::Serialize + jsonrpsee::types::DeserializeOwned,
{
} -> This causes the |
Ah, that was the piece I was missing. Ok, clear now!
It's either that or:
/cc @maciejhirsz |
Closes #448 This PR adds an implementation for `SubscriptionClient` to the `HttpClient` struct, which makes it possible for http clients to use macro-generated RPC servers. If an http client tries to set up a subscription it will fail with a `HttpNotImplemented` error.
Closes #448 This PR adds an implementation for `SubscriptionClient` to the `HttpClient` struct, which makes it possible for http clients to use macro-generated RPC servers. If an http client tries to set up a subscription it will fail with a `HttpNotImplemented` error.
For example if a define a API like this:
Then if I try to use for the
HTTP client
it won't work because the client implementation requiresSubscriptionClient trait bound
when it has at least one subscription in the trait.For those we should just ignore the subscriptions and require the
Client trait bound
instead of possible, thoughts or suggestions?The text was updated successfully, but these errors were encountered: