Skip to main content

ServerBuilder

Struct ServerBuilder 

Source
pub struct ServerBuilder<HttpMiddleware, RpcMiddleware> { /* private fields */ }
Expand description

Builder to configure and create a JSON-RPC server.

Implementations§

Source§

impl Builder<Identity, Identity>

Source

pub fn new() -> Self

Create a default server builder.

Source

pub fn with_config(config: ServerConfig) -> Self

Create a server builder with the given ServerConfig.

Source§

impl<HttpMiddleware, RpcMiddleware> Builder<HttpMiddleware, RpcMiddleware>

Source

pub fn set_config(self, cfg: ServerConfig) -> Self

Configure the ServerConfig.

Source

pub fn set_rpc_middleware<T>( self, rpc_middleware: RpcServiceBuilder<T>, ) -> Builder<HttpMiddleware, T>

Enable middleware that is invoked on every JSON-RPC call.

The middleware itself is very similar to the tower middleware but it has a different service trait which takes &self instead &mut self which means that you can’t use built-in middleware from tower.

Another consequence of &self is that you must wrap any of the middleware state in a type which is Send and provides interior mutability such as Arc<Mutex>.

The builder itself exposes a similar API as the [tower::ServiceBuilder] where it is possible to compose layers to the middleware.

To add middleware RpcServiceBuilder exposes a few different layer APIs that are wrapped on top of the [tower::ServiceBuilder].

When the server is started these layers are wrapped in the RpcService and that’s why the service APIs is not exposed.

use std::{
    net::SocketAddr,
    sync::{
        atomic::{AtomicUsize, Ordering},
        Arc,
    },
    time::Instant,
};

use jsonrpsee_server::{
    middleware::rpc::{
        Batch, MethodResponse, Notification, Request, RpcService, RpcServiceBuilder,
        RpcServiceT,
    },
    ServerBuilder,
};

#[derive(Clone)]
struct MyMiddleware<S> {
    service: S,
    count: Arc<AtomicUsize>,
}

impl<S> RpcServiceT for MyMiddleware<S>
where
    S: RpcServiceT + Clone + Send + Sync + 'static,
{
    fn call<'a>(&self, req: Request<'a>) -> impl Future<Output = MethodResponse> + Send + 'a {
        tracing::info!("MyMiddleware processed call {}", req.method);
        let count = self.count.clone();
        let service = self.service.clone();

        async move {
            let rp = service.call(req).await;
            // Modify the state.
            count.fetch_add(1, Ordering::Relaxed);
            rp
        }
    }

    fn batch<'a>(&self, batch: Batch<'a>) -> impl Future<Output = MethodResponse> + Send + 'a {
        self.service.batch(batch)
    }

    fn notification<'a>(
        &self,
        notif: Notification<'a>,
    ) -> impl Future<Output = MethodResponse> + Send + 'a {
        self.service.notification(notif)
    }
}

// Create a state per connection
// NOTE: The service type can be omitted once `start` is called on the server.
let m = RpcServiceBuilder::new().layer_fn(move |service: ()| MyMiddleware {
    service,
    count: Arc::new(AtomicUsize::new(0)),
});
let builder = ServerBuilder::default().set_rpc_middleware(m);
Source

pub fn set_http_middleware<T>( self, http_middleware: ServiceBuilder<T>, ) -> Builder<T, RpcMiddleware>

Configure a custom [tower::ServiceBuilder] middleware for composing layers to be applied to the RPC service.

Default: No tower layers are applied to the RPC service.

§Examples
use std::{net::SocketAddr, time::Duration};

#[tokio::main]
async fn main() {
    let builder = tower::ServiceBuilder::new().timeout(Duration::from_secs(2));

    let server = jsonrpsee_server::ServerBuilder::new()
        .set_http_middleware(builder)
        .build("127.0.0.1:0".parse::<SocketAddr>().unwrap())
        .await
        .unwrap();
}
Source

pub async fn build( self, addrs: impl ToSocketAddrs, ) -> Result<Server<HttpMiddleware, RpcMiddleware>>

Finalize the configuration of the server. Consumes the Builder.

#[tokio::main]
async fn main() {
    let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
    let occupied_addr = listener.local_addr().unwrap();
    let addrs: &[std::net::SocketAddr] = &[occupied_addr, "127.0.0.1:0".parse().unwrap()];
    assert!(jsonrpsee_server::ServerBuilder::default().build(occupied_addr).await.is_err());
    assert!(jsonrpsee_server::ServerBuilder::default().build(addrs).await.is_ok());
}

Trait Implementations§

Source§

impl<HttpMiddleware: Debug, RpcMiddleware: Debug> Debug for Builder<HttpMiddleware, RpcMiddleware>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Builder<Identity, Identity>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<HttpMiddleware, RpcMiddleware> !RefUnwindSafe for Builder<HttpMiddleware, RpcMiddleware>

§

impl<HttpMiddleware, RpcMiddleware> !UnwindSafe for Builder<HttpMiddleware, RpcMiddleware>

§

impl<HttpMiddleware, RpcMiddleware> Freeze for Builder<HttpMiddleware, RpcMiddleware>
where RpcServiceBuilder<RpcMiddleware>: Freeze, ServiceBuilder<HttpMiddleware>: Freeze,

§

impl<HttpMiddleware, RpcMiddleware> Send for Builder<HttpMiddleware, RpcMiddleware>
where RpcServiceBuilder<RpcMiddleware>: Send, ServiceBuilder<HttpMiddleware>: Send,

§

impl<HttpMiddleware, RpcMiddleware> Sync for Builder<HttpMiddleware, RpcMiddleware>
where RpcServiceBuilder<RpcMiddleware>: Sync, ServiceBuilder<HttpMiddleware>: Sync,

§

impl<HttpMiddleware, RpcMiddleware> Unpin for Builder<HttpMiddleware, RpcMiddleware>
where RpcServiceBuilder<RpcMiddleware>: Unpin, ServiceBuilder<HttpMiddleware>: Unpin,

§

impl<HttpMiddleware, RpcMiddleware> UnsafeUnpin for Builder<HttpMiddleware, RpcMiddleware>
where RpcServiceBuilder<RpcMiddleware>: UnsafeUnpin, ServiceBuilder<HttpMiddleware>: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more

Layout§

Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.