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: jsonrpsee as service and low-level API for more fine-grained API to disconnect peers etc #1224

Merged
merged 61 commits into from
Nov 16, 2023

Conversation

niklasad1
Copy link
Member

@niklasad1 niklasad1 commented Oct 23, 2023

This PR adds two new APIs (in order for users to manage the state themselves):

  1. "low-level API to jsonrpsee": to give the ability to terminate connections
  2. "jsonrpsee as a service": to expose the jsonrpsee tower service that may be used to get access to the HTTP request and to implement full functionality of the old RpcLogger, this API can be used.

Limitations

The API to manage the websocket connection is quite high-level, such that this design doesn't allow to disconnect peers because of lower-level WebSocket details such as if the ping wasn't answered in time, send took longer than some hard limit, message buffer was exceeded x times, and similar.

Annoyance

As demonstrated in the added examples, it's a bit annoying for folks to bother with "server handle and stop handles" but I don't want to make such big refactor for that.

To implement "grafana metrics or something equivalent to the old RpcLogger" then the jsonrpsee as service must be used which is a bit harder to implement I reckon.

Examples

Two examples of how to use the hyper::service fn to utilize the jsonrpsee TowerService

  1. Utilize the jsonrpsee::TowerService to get access to the HTTP request (example/jsonrpsee_service.rs)
  2. Utilize the jsonrpsee low-level API to disconnect misbehaving peers. A few helper functions are exposed from the jsonrpsee::server to help with this.

Basically, we want people to be able to disconnect misbehaving peers, and this is probably the cleanest way to keep jsonrpsee
as simple as possible.

Resolves #1016, resolves #1014, resolves #1000

@niklasad1 niklasad1 changed the title WIP: PoC jsonrpsee service for more fine-grained API WIP: jsonrpsee service for more fine-grained API to disconnect peers etc Nov 2, 2023
@@ -0,0 +1,264 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
Copy link
Member Author

@niklasad1 niklasad1 Nov 3, 2023

Choose a reason for hiding this comment

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

//cc @xlc

This is the suggested API to disconnect peers etc, it's still just a PoC and I need to polish it.
Is it sufficient for your proxy/load balancer implementation?

This example just "disconnects peers" that don't comply with the "dummy rate limit middleware" and blacklists the IP addr.

methods: impl Into<Methods>,
stop_handle: StopHandle,
) -> TowerService<RpcMiddleware, HttpMiddleware> {
let conn_id = self.conn_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
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 could have been a u32 but it's so annoying with mutable stuff in FnMut closure's such as hyper::service_fn

}

/// See [`Builder::max_request_body_size`](method@Builder::max_request_body_size) for documentation.
pub fn max_request_body_size(mut self, size: u32) -> 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.

this is duplicated :(

we could add a trait for but it doesn't seems worth it for now

///
/// # Note
/// This is similar to [`hyper::service::service_fn`].
#[derive(Debug, Clone)]
pub struct TowerService<L> {
pub struct TowerServiceNoHttp<L> {
Copy link
Member Author

@niklasad1 niklasad1 Nov 8, 2023

Choose a reason for hiding this comment

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

bikeshed on naming,

I think this shouldn't be used by external user in the "normal case" because the http middleware from jsonrpsee::ServerBuilder isn't used then

Copy link
Member Author

Choose a reason for hiding this comment

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

but it may be possible that someone wants to wrap this on-top of their own tower http middleware

Copy link
Member Author

Choose a reason for hiding this comment

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

changed this to jsonrpsee internal thingy now

/// if you want only to enable `rpc_middleware` then [`TowerServiceNoHttp`]
/// can be used.
#[derive(Debug)]
pub struct TowerService<RpcMiddleware, HttpMiddleware> {
Copy link
Member Author

Choose a reason for hiding this comment

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

Introduced this to enable both rpc_middleware and http_middleware this is useful for instance when using the hyper_service_fn see the jsonrpsee_as_service example which is using this

server/src/server.rs Outdated Show resolved Hide resolved
content_type.and_then(|val| val.to_str().ok()).map_or(false, |content| {
content.eq_ignore_ascii_case("application/json")
|| content.eq_ignore_ascii_case("application/json; charset=utf-8")
|| content.eq_ignore_ascii_case("application/json;charset=utf-8")
})
}

pub(crate) async fn reject_connection(socket: tokio::net::TcpStream) {
Copy link
Member Author

Choose a reason for hiding this comment

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

moved to the jsonrpsee::TowerService

@niklasad1 niklasad1 changed the title jsonrpsee as service and low-level API for more fine-grained API to disconnect peers etc feat: jsonrpsee as service and low-level API for more fine-grained API to disconnect peers etc Nov 9, 2023
Copy link
Contributor

@tadeohepperle tadeohepperle left a comment

Choose a reason for hiding this comment

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

I did read the code and give it a tick, but I do not feel able to give any feedback :)

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.

LGTM! I believe the low-level API enables users to implement all use-cases, and handles most future requests for other features. Being low-level API seems worth it to me, especially when most users will not bother implementing it! 👍

@niklasad1 niklasad1 merged commit 87313c3 into master Nov 16, 2023
9 checks passed
@niklasad1 niklasad1 deleted the na-jsonrpsee-service branch November 16, 2023 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants