anvil/server/
mod.rs

1//! Contains the code to launch an Ethereum RPC server.
2
3use crate::{EthApi, IpcTask};
4use anvil_server::{ipc::IpcEndpoint, ServerConfig};
5use axum::Router;
6use futures::StreamExt;
7use handler::{HttpEthRpcHandler, PubSubEthRpcHandler};
8use std::{future::Future, io, net::SocketAddr, pin::pin};
9use tokio::net::TcpListener;
10
11pub mod error;
12mod handler;
13
14/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.
15///
16/// The returned future creates a new server, binding it to the given address, which returns another
17/// future that runs it.
18pub async fn serve(
19    addr: SocketAddr,
20    api: EthApi,
21    config: ServerConfig,
22) -> io::Result<impl Future<Output = io::Result<()>>> {
23    let tcp_listener = TcpListener::bind(addr).await?;
24    Ok(serve_on(tcp_listener, api, config))
25}
26
27/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.
28pub async fn serve_on(
29    tcp_listener: TcpListener,
30    api: EthApi,
31    config: ServerConfig,
32) -> io::Result<()> {
33    axum::serve(tcp_listener, router(api, config).into_make_service()).await
34}
35
36/// Configures an [`axum::Router`] that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.
37pub fn router(api: EthApi, config: ServerConfig) -> Router {
38    let http = HttpEthRpcHandler::new(api.clone());
39    let ws = PubSubEthRpcHandler::new(api);
40    anvil_server::http_ws_router(config, http, ws)
41}
42
43/// Launches an ipc server at the given path in a new task
44///
45/// # Panics
46///
47/// Panics if setting up the IPC connection was unsuccessful.
48#[track_caller]
49pub fn spawn_ipc(api: EthApi, path: String) -> IpcTask {
50    try_spawn_ipc(api, path).expect("failed to establish ipc connection")
51}
52
53/// Launches an ipc server at the given path in a new task.
54pub fn try_spawn_ipc(api: EthApi, path: String) -> io::Result<IpcTask> {
55    let handler = PubSubEthRpcHandler::new(api);
56    let ipc = IpcEndpoint::new(handler, path);
57    let incoming = ipc.incoming()?;
58
59    let task = tokio::task::spawn(async move {
60        let mut incoming = pin!(incoming);
61        while let Some(stream) = incoming.next().await {
62            trace!(target: "ipc", "new ipc connection");
63            tokio::task::spawn(stream);
64        }
65    });
66
67    Ok(task)
68}