jsonrpsee

repository·master·Indexed 21 days ago

https://github.com/paritytech/jsonrpsee

A high-performance, async/await-native JSON-RPC library for Rust. It supports multiple transport protocols including HTTP, HTTP2, and WebSocket, and is compatible with both backend servers and frontend web clients via WASM support. The library provides a transport abstraction layer for custom implementations, middleware support for intercepting requests and responses, and tools like HttpClientBuilder for configuring timeouts, headers, and TLS settings.

Tokens
36.8K
Snippets
104
Records
147
Agent score
74%

What's inside jsonrpsee

  1. Overview of jsonrpsee features

    master

    jsonrpsee is an asynchronous JSON-RPC library for Rust designed for async/await workflows. It serves as the successor to the ParityTech JSONRPC crate and provides high-performance implementations for various transport protocols and environments.

    Key capabilities include:

    • Client/Server Support: Full support for HTTP, HTTP2, and WebSocket protocols.
    • WASM Support: Client-side support for WebAssembly via web-sys.
    • Extensibility: A transport abstraction layer that allows developers to implement and provide custom transports.
    • Middleware: Support for middleware to intercept or modify requests and responses.
  2. Profile CPU usage with flamegraphs

    master

    To generate a flamegraph for CPU profiling, run the benchmark with the --profile-time flag. The resulting flamegraph will be located at ./target/criterion/<your benchmark>/profile/flamegraph.svg.

    # Profile all benchmarks for 60 seconds
    $ cargo bench --bench bench -- --profile-time=60
    
    # Profile a specific benchmark for 60 seconds
    $ cargo bench --bench bench -- --profile-time=60 sync/http_concurrent_conn_calls/1024
  3. Run benchmarks with tokio-console

    master

    To inspect task execution using tokio-console, you must first install the tool and then run the benchmarks with the tokio_unstable cfg flag enabled via RUSTFLAGS.

    # Install tokio-console
    $ cargo install --locked tokio-console && tokio-console
    
    # Run benchmarks with tokio-console support
    $ RUSTFLAGS="--cfg tokio_unstable" cargo bench
  4. Prepare MacOS for running benchmarks

    master

    Running jsonrpsee benchmarks involves testing server implementations with many concurrent connections, which opens a large number of sockets and file descriptors. On MacOS, you may need to increase system limits to prevent errors. It is generally recommended to run benchmarks on a Linux machine if possible, as MacOS hits limits more quickly.

    To increase limits on MacOS, use the following commands:

    sudo sysctl -w kern.maxfiles=100000
    sudo sysctl -w kern.maxfilesperproc=100000
    ulimit -n 100000
    sudo sysctl -w kern.ipc.somaxconn=100000
    sudo sysctl -w kern.ipc.maxsockbuf=16777216
  5. Explore jsonrpsee usage examples

    master

    The repository contains several practical examples demonstrating different ways to use the library. You can find these in the ./examples/examples/ directory:

    • HTTP: Implementing HTTP client/server communication.
    • WebSocket: Standard WebSocket communication.
    • WebSocket pubsub: Using WebSocket pubsub broadcast features.
    • API generation with proc macro: Using procedural macros to automatically generate JSON-RPC APIs.
    • CORS server: Configuring a server with Cross-Origin Resource Sharing.
    • Core client: Using the low-level core client functionality.
    • HTTP proxy middleware: Implementing middleware that acts as an HTTP proxy.
    • jsonrpsee as service: Integrating jsonrpsee as a service within a larger application.
    • Low level API: Interacting with the server via the low-level API.
    • Websocket dual-stack: Serving WebSockets over both IPv4 and IPv6 sockets.
  6. Run jsonrpsee benchmarks

    master

    You can run the benchmarks using cargo bench. You can run the entire suite or target specific benchmarks.

    # Run all benchmarks
    $ cargo bench
    
    # Run a specific benchmark
    $ cargo bench --bench bench jsonrpsee_types_v2_array_ref
    
    # Run all benchmarks against jsonrpc crate servers
    $ cargo bench --features jsonpc-crate
  7. What is `TwoPointZero`?

    master
    The TwoPointZero struct is a marker type used to represent the JSON-RPC v2.0 version string ("2.0"). It implements Serialize and Deserialize so it can be used directly in JSON-RPC request/response structures to ensure compliance with the v2.0 specification.
  8. Handle connection limits and errors

    master

    When using ConnectionGuard, you may encounter scenarios where connections are rejected.

    • ConnectionPermit: This is an OwnedSemaphorePermit. It must be kept in scope for the duration of the connection to ensure the slot is not released prematurely. Once the permit is dropped, the connection slot becomes available again.
    • Capacity Monitoring: You can monitor server load using available_connections() to decide whether to apply backpressure or reject new requests.
  9. Manage server lifecycle with `ServerHandle` and `StopHandle`

    master

    The jsonrpsee-server crate provides handles to control the server's execution state.

    • ServerHandle: Used to interact with or manage the running server instance.
    • StopHandle: Used to trigger a shutdown of the server.
    • stop_channel: A utility to create communication channels for stopping the server.
    • ConnectionGuard and ConnectionPermit: Used for managing the lifecycle and state of individual connections.
  10. Implement RPC Middleware

    master

    You can intercept every JSON-RPC call by providing custom RPC middleware. This is done via set_rpc_middleware on the ServerBuilder.

    Unlike standard tower middleware, RpcMiddleware uses a service trait that takes &self instead of &mut self. Consequently, any state required by your middleware must use interior mutability (e.g., Arc<Mutex<T>> or Arc<AtomicUsize>).

    To implement it, define a struct that implements RpcServiceT and use RpcServiceBuilder::layer_fn to wrap it.

    use jsonrpsee_server::middleware::rpc::{RpcService, RpcServiceBuilder, RpcServiceT, Request, MethodResponse, Notification, Batch};
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    
    #[derive(Clone)]
    struct MyMiddleware<S> {
        service: S,
        count: Arc<AtomicUsize>,
    }
    
    impl<S> RpcServiceT for MyMiddleware<S>
    where
        S: RpcServiceT + Clone + Send + Sync + 'static,
    {
        type MethodResponse = S::MethodResponse;
        type NotificationResponse = S::NotificationResponse;
        type BatchResponse = S::BatchResponse;
    
        fn call<'a>(&self, req: Request<'a>) -> impl Future<Output = Self::MethodResponse> + Send + 'a {
            let count = self.count.clone();
            let service = self.service.clone();
            async move {
                let rp = service.call(req).await;
                count.fetch_add(1, Ordering::Relaxed);
                rp
            }
        }
    
        fn batch<'a>(&self, batch: Batch<'a>) -> impl Future<Output = Self::BatchResponse> + Send + 'a {
            self.service.batch(batch)
        }
    
        fn notification<'a>(&self, notif: Notification<'a>) -> impl Future<Output = Self::NotificationResponse> + Send + 'a {
            self.service.notification(notif)
        }
    }
    
    // Usage:
    // let m = RpcServiceBuilder::new().layer_fn(move |service: ()| MyMiddleware { service, count: Arc::new(AtomicUsize::new(0)) });
    // let builder = ServerBuilder::default().set_rpc_middleware(m);
  11. Configure RpcService subscription support

    master

    The RpcService can be configured in two modes via its internal RpcServiceCfg:

    1. OnlyCalls: The server only supports standard method calls. Any attempt to use subscription-based methods will result in an InternalError.
    2. CallsAndSubscriptions: The server supports both method calls and subscriptions. This mode requires providing:
      • bounded_subscriptions: To limit the number of active subscriptions.
      • sink: To handle subscription updates.
      • id_provider: To manage subscription IDs.
      • _pending_calls: A mechanism to track pending operations.
  12. Understand JSON-RPC batching limits

    master

    When using handle_rpc_call, the server's ability to process multiple requests in one payload is governed by the BatchRequestConfig enum. This is critical for preventing resource exhaustion attacks via massive JSON arrays.

    • Disabled: The server will reject any batch request.
    • Limit(n): The server accepts batches containing up to n requests.
    • Unlimited: The server accepts batches of any size (use with caution).

    If a batch is too large, the server returns a MethodResponse::error using the appropriate error code for rejected batches.