use crate::{ beacon, consensus, error::ApiError, helpers, metrics, network, node, spec, validator, BoxFut, NetworkChannel, }; use beacon_chain::{BeaconChain, BeaconChainTypes}; use client_network::Service as NetworkService; use eth2_config::Eth2Config; use futures::{Future, IntoFuture}; use hyper::{Body, Error, Method, Request, Response}; use slog::debug; use std::path::PathBuf; use std::sync::Arc; fn into_boxfut(item: F) -> BoxFut where F: IntoFuture, Error = ApiError>, F::Future: Send, { Box::new(item.into_future()) } // Allowing more than 7 arguments. #[allow(clippy::too_many_arguments)] pub fn route( req: Request, beacon_chain: Arc>, network_service: Arc>, network_channel: NetworkChannel, eth2_config: Arc, local_log: slog::Logger, db_path: PathBuf, freezer_db_path: PathBuf, ) -> impl Future, Error = Error> { metrics::inc_counter(&metrics::REQUEST_COUNT); let timer = metrics::start_timer(&metrics::REQUEST_RESPONSE_TIME); let path = req.uri().path().to_string(); let log = local_log.clone(); let request_result: Box, Error = _> + Send> = match (req.method(), path.as_ref()) { // Methods for Client (&Method::GET, "/node/version") => into_boxfut(node::get_version(req)), (&Method::GET, "/node/syncing") => { into_boxfut(helpers::implementation_pending_response(req)) } // Methods for Network (&Method::GET, "/network/enr") => { into_boxfut(network::get_enr::(req, network_service)) } (&Method::GET, "/network/peer_count") => { into_boxfut(network::get_peer_count::(req, network_service)) } (&Method::GET, "/network/peer_id") => { into_boxfut(network::get_peer_id::(req, network_service)) } (&Method::GET, "/network/peers") => { into_boxfut(network::get_peer_list::(req, network_service)) } (&Method::GET, "/network/listen_port") => { into_boxfut(network::get_listen_port::(req, network_service)) } (&Method::GET, "/network/listen_addresses") => { into_boxfut(network::get_listen_addresses::(req, network_service)) } // Methods for Beacon Node (&Method::GET, "/beacon/head") => into_boxfut(beacon::get_head::(req, beacon_chain)), (&Method::GET, "/beacon/heads") => { into_boxfut(beacon::get_heads::(req, beacon_chain)) } (&Method::GET, "/beacon/block") => { into_boxfut(beacon::get_block::(req, beacon_chain)) } (&Method::GET, "/beacon/block_root") => { into_boxfut(beacon::get_block_root::(req, beacon_chain)) } (&Method::GET, "/beacon/fork") => into_boxfut(beacon::get_fork::(req, beacon_chain)), (&Method::GET, "/beacon/genesis_time") => { into_boxfut(beacon::get_genesis_time::(req, beacon_chain)) } (&Method::GET, "/beacon/validators") => { into_boxfut(beacon::get_validators::(req, beacon_chain)) } (&Method::POST, "/beacon/validators") => { into_boxfut(beacon::post_validators::(req, beacon_chain)) } (&Method::GET, "/beacon/validators/all") => { into_boxfut(beacon::get_all_validators::(req, beacon_chain)) } (&Method::GET, "/beacon/validators/active") => { into_boxfut(beacon::get_active_validators::(req, beacon_chain)) } (&Method::GET, "/beacon/state") => { into_boxfut(beacon::get_state::(req, beacon_chain)) } (&Method::GET, "/beacon/state_root") => { into_boxfut(beacon::get_state_root::(req, beacon_chain)) } (&Method::GET, "/beacon/state/genesis") => { into_boxfut(beacon::get_genesis_state::(req, beacon_chain)) } (&Method::GET, "/beacon/committees") => { into_boxfut(beacon::get_committees::(req, beacon_chain)) } // Methods for Validator (&Method::POST, "/validator/duties") => { validator::post_validator_duties::(req, beacon_chain) } (&Method::GET, "/validator/duties/all") => { into_boxfut(validator::get_all_validator_duties::(req, beacon_chain)) } (&Method::GET, "/validator/duties/active") => into_boxfut( validator::get_active_validator_duties::(req, beacon_chain), ), (&Method::GET, "/validator/block") => { into_boxfut(validator::get_new_beacon_block::(req, beacon_chain, log)) } (&Method::POST, "/validator/block") => { validator::publish_beacon_block::(req, beacon_chain, network_channel, log) } (&Method::GET, "/validator/attestation") => { into_boxfut(validator::get_new_attestation::(req, beacon_chain)) } (&Method::POST, "/validator/attestation") => { validator::publish_attestation::(req, beacon_chain, network_channel, log) } (&Method::GET, "/consensus/global_votes") => { into_boxfut(consensus::get_vote_count::(req, beacon_chain)) } (&Method::POST, "/consensus/individual_votes") => { consensus::post_individual_votes::(req, beacon_chain) } // Methods for bootstrap and checking configuration (&Method::GET, "/spec") => into_boxfut(spec::get_spec::(req, beacon_chain)), (&Method::GET, "/spec/slots_per_epoch") => { into_boxfut(spec::get_slots_per_epoch::(req)) } (&Method::GET, "/spec/deposit_contract") => { into_boxfut(helpers::implementation_pending_response(req)) } (&Method::GET, "/spec/eth2_config") => { into_boxfut(spec::get_eth2_config::(req, eth2_config)) } (&Method::GET, "/metrics") => into_boxfut(metrics::get_prometheus::( req, beacon_chain, db_path, freezer_db_path, )), _ => Box::new(futures::future::err(ApiError::NotFound( "Request path and/or method not found.".to_owned(), ))), }; // Map the Rust-friendly `Result` in to a http-friendly response. In effect, this ensures that // any `Err` returned from our response handlers becomes a valid http response to the client // (e.g., a response with a 404 or 500 status). request_result.then(move |result| match result { Ok(response) => { debug!(local_log, "HTTP API request successful"; "path" => path); metrics::inc_counter(&metrics::SUCCESS_COUNT); metrics::stop_timer(timer); Ok(response) } Err(e) => { let error_response = e.into(); debug!(local_log, "HTTP API request failure"; "path" => path); metrics::stop_timer(timer); Ok(error_response) } }) }