Skip to content
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

feat: async API when Response has been processed. #1281

Merged
merged 29 commits into from
Feb 6, 2024
Merged

Conversation

niklasad1
Copy link
Member

@niklasad1 niklasad1 commented Jan 30, 2024

Resolves #1279

@niklasad1 niklasad1 changed the title feat: add RpcModule::register_raw_method feat: add RpcModule::register_raw_method + ResponsePayload async API Jan 31, 2024
core/src/server/helpers.rs Outdated Show resolved Hide resolved
proc-macros/src/rpc_macro.rs Outdated Show resolved Hide resolved
core/src/server/helpers.rs Outdated Show resolved Hide resolved
@lexnv
Copy link
Contributor

lexnv commented Feb 1, 2024

Overall looks good to me, nice one 👍 ! And in combination with the polkadot-sdk commit this should resolve any races from happening.

I find the is_sent() method name a bit confusing; in the sense that the message is sent to our internal buffers; but can't think of any other names. This should be fine since this is a niece low-level API

@niklasad1
Copy link
Member Author

niklasad1 commented Feb 1, 2024

I find the is_sent() method name a bit confusing; in the sense that the message is sent to our internal buffers; but can't think of any other names. This should be fine since this is a niece low-level API

Yeah, agree. I don't like it either I thought it was nice wrapper but it makes things more confusing. Removed now thanks.

@niklasad1 niklasad1 marked this pull request as ready for review February 1, 2024 16:55
@niklasad1 niklasad1 requested a review from a team as a code owner February 1, 2024 16:55

/// Optional callback that may be utilized to notify that the method response was a
/// an JSON-RPC error object and processed.
pub fn notify_on_error(mut self, tx: MethodResponseNotifyTx) -> Self {
Copy link
Collaborator

@jsdw jsdw Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How this is set up at the moment means that if somebody does:

response
    .notify_on_success(...)
    .notify_on_error(...)
    .notify_on_response(...)

They get no compile error, and they might expect one of those to fire in each case, but in fact only the last registered one has any chance of ever firing.

I guess I'd prevent this by:

  • Either have more than one callback that can be registered, or
  • Just have notify_on_completion or something and indicate by the channel response whether success or error happened.

Copy link
Collaborator

@jsdw jsdw Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I'd also probably want it so that response.notify_on_completion(a).notify_on_completion(b) also worked and fired both a and b; one could store a vec of things-to-be-notified perhaps? Or change the method name to eg set_on_complete_notifier(..) so that it was a bit more obvious that it set a single thing rather than allowed multiple notifications to be given.

@@ -109,10 +105,20 @@ impl RpcDescription {
let ret_ty = args.last_mut().unwrap();
let err_ty = self.jrps_client_item(quote! { core::client::Error });

quote! { core::result::Result<#ret_ty, #err_ty> }
} else if type_name.ident == "ResponsePayload" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sad that we have to match on the string type names :D

I guess it wasn't possible to use a trait to convert these into results automatically or something; I'm sure it was something like that but can't remember the issue now! But ah well!

Copy link
Member Author

@niklasad1 niklasad1 Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it's that the client codegen is super opinionated and the error type must be jsonrpsee::core::client::Error otherwise it won't compile. Yeah, it's ugly but just proc macro code thank god.

IntoResponse stuff doesn't work there because we have deal with I/O errors and bunch of things in the client code

@jsdw
Copy link
Collaborator

jsdw commented Feb 2, 2024

Looks good to me; the only actual thing I think should be addressed is making res.notify_on_success(..).notify_on_error(..) either impossible or do as you might expect (ie fire all of the provided channels).

@niklasad1 niklasad1 changed the title feat: add async API when a ResponsePayload has been processed. feat: async API when a ResponsePayload has been processed. Feb 4, 2024
@@ -31,7 +30,7 @@ impl IntoResponse for CustomError {
let data = data.map(|val| serde_json::value::to_raw_value(&val).unwrap());

let error_object = jsonrpsee::types::ErrorObjectOwned::owned(code, "custom_error", data);
ResponsePayload::Error(error_object)
ResponsePayload::error(error_object)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the breaking change

Copy link
Collaborator

@jsdw jsdw Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaahhh I see! I was thinking of something else :)

(I guess if you wanted to do a patch release and didn't mind it being a bit ugly you could have an Error method)

@@ -4,8 +4,7 @@ use std::net::SocketAddr;

use jsonrpsee::core::{async_trait, ClientError, Serialize};
use jsonrpsee::proc_macros::rpc;
use jsonrpsee::server::{IntoResponse, ServerBuilder};
use jsonrpsee::types::ResponsePayload;
use jsonrpsee::server::{IntoResponse, ResponsePayload, ServerBuilder};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change as well

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aah I see; it moved! So will you do a proper release then instead of a patch one do you think? Or alias this type in jsonrpsee::types in the release to avoid this break?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to make a proper release because the MethodResponse is also a breaking change and I can't do proper alias in types because then the feature flag core/server needs to be enabled for ResponsePayload to be available.

Copy link
Collaborator

@jsdw jsdw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me offhand!

It feels like we'll need to do a major release given the breaks unless you mangle a couple of things in a patch release to keep the old APIs/imports :)

@@ -0,0 +1,84 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe copyright years need to change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's take of it in another PR

Copy link
Contributor

@lexnv lexnv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@niklasad1 niklasad1 changed the title feat: async API when a ResponsePayload has been processed. feat: async API when Response has been processed. Feb 5, 2024
///
/// This is useful when one only want to return the error and
/// `T` can't resolved by rustc to avoid type annonations.
pub fn unit_error(e: impl Into<ErrorObjectOwned>) -> Self {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @jsdw @lexnv any thoughts on this one?

Basically, I would want a nice wrapper to avoid doing ResponsePayload::<()>::error(err) but maybe unit error is weird because it kind of reads like the error is ()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you first mentioned it I assumed it meant error is () which is what confused me :D

That said, I'm struggling to come up with a better name! I'm ok with just doing ResponsePayload::<()>::error(err) too I guess; if thename for any longer you'd not be saving any chars any more anyways!

server/src/transport/ws.rs Outdated Show resolved Hide resolved
@niklasad1 niklasad1 merged commit 387f52f into master Feb 6, 2024
11 checks passed
@niklasad1 niklasad1 deleted the low-level-api-v1 branch February 6, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add low-level API for method implementations
3 participants