diff --git a/Cargo.toml b/Cargo.toml index 00c354309..b4d53d420 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "beacon_node", "beacon_node/store", "beacon_node/client", + "beacon_node/http_server", "beacon_node/network", "beacon_node/eth2-libp2p", "beacon_node/rpc", diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 4a976eec4..6634e260d 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } store = { path = "../store" } +http_server = { path = "../http_server" } rpc = { path = "../rpc" } fork_choice = { path = "../../eth2/fork_choice" } types = { path = "../../eth2/types" } diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index 8d7176c2c..32722e124 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -1,5 +1,6 @@ use clap::ArgMatches; use fork_choice::ForkChoiceAlgorithm; +use http_server::HttpServerConfig; use network::NetworkConfig; use slog::error; use std::fs; @@ -27,7 +28,7 @@ pub struct ClientConfig { pub db_type: DBType, pub db_name: PathBuf, pub rpc_conf: rpc::RPCConfig, - //pub ipc_conf: + pub http_conf: HttpServerConfig, //pub ipc_conf: } impl Default for ClientConfig { @@ -55,6 +56,7 @@ impl Default for ClientConfig { // default db name for disk-based dbs db_name: data_dir.join("chain_db"), rpc_conf: rpc::RPCConfig::default(), + http_conf: HttpServerConfig::default(), } } } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 71d4013d3..6433b94e2 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -98,7 +98,7 @@ impl Client { Some(rpc::start_server( &config.rpc_conf, executor, - network_send, + network_send.clone(), beacon_chain.clone(), &log, )) @@ -106,6 +106,17 @@ impl Client { None }; + // Start the `http_server` service. + // + // Note: presently we are ignoring the config and _always_ starting a HTTP server. + http_server::start_service( + &config.http_conf, + executor, + network_send, + beacon_chain.clone(), + &log, + ); + let (slot_timer_exit_signal, exit) = exit_future::signal(); if let Ok(Some(duration_to_next_slot)) = beacon_chain.slot_clock.duration_to_next_slot() { // set up the validator work interval - start at next slot and proceed every slot diff --git a/beacon_node/http_server/Cargo.toml b/beacon_node/http_server/Cargo.toml new file mode 100644 index 000000000..5d5d7e492 --- /dev/null +++ b/beacon_node/http_server/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "http_server" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dependencies] +bls = { path = "../../eth2/utils/bls" } +beacon_chain = { path = "../beacon_chain" } +iron = "^0.6" +router = "^0.6" +network = { path = "../network" } +eth2-libp2p = { path = "../eth2-libp2p" } +version = { path = "../version" } +types = { path = "../../eth2/types" } +ssz = { path = "../../eth2/utils/ssz" } +slot_clock = { path = "../../eth2/utils/slot_clock" } +protos = { path = "../../protos" } +fork_choice = { path = "../../eth2/fork_choice" } +grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] } +protobuf = "2.0.2" +clap = "2.32.0" +store = { path = "../store" } +dirs = "1.0.3" +futures = "0.1.23" +slog = "^2.2.3" +slog-term = "^2.4.0" +slog-async = "^2.3.0" +tokio = "0.1.17" +exit-future = "0.1.4" +crossbeam-channel = "0.3.8" diff --git a/beacon_node/http_server/src/lib.rs b/beacon_node/http_server/src/lib.rs new file mode 100644 index 000000000..676928ce6 --- /dev/null +++ b/beacon_node/http_server/src/lib.rs @@ -0,0 +1,115 @@ +use beacon_chain::BeaconChain; +use futures::Future; +use grpcio::{Environment, ServerBuilder}; +use network::NetworkMessage; +use protos::services_grpc::{ + create_attestation_service, create_beacon_block_service, create_beacon_node_service, + create_validator_service, +}; +use slog::{info, o, warn}; +use std::net::Ipv4Addr; +use std::sync::Arc; +use tokio::runtime::TaskExecutor; +use types::EthSpec; + +use iron::prelude::*; +use iron::{status::Status, Handler, IronResult, Request, Response}; +use router::Router; + +#[derive(PartialEq, Clone, Debug)] +pub struct HttpServerConfig { + pub enabled: bool, + pub listen_address: String, + /* + pub listen_address: Ipv4Addr, + pub port: u16, + */ +} + +impl Default for HttpServerConfig { + fn default() -> Self { + Self { + enabled: false, + listen_address: "127.0.0.1:5051".to_string(), + /* + listen_address: Ipv4Addr::new(127, 0, 0, 1), + port: 5051, + */ + } + } +} + +pub struct IndexHandler { + message: String, +} + +impl Handler for IndexHandler { + fn handle(&self, _: &mut Request) -> IronResult { + Ok(Response::with((Status::Ok, self.message.clone()))) + } +} + +pub fn create_iron_http_server() -> Iron { + let index_handler = IndexHandler { + message: "Hello world".to_string(), + }; + + let mut router = Router::new(); + router.get("/", index_handler, "index"); + Iron::new(router) +} + +pub fn start_service( + config: &HttpServerConfig, + executor: &TaskExecutor, + network_chan: crossbeam_channel::Sender, + beacon_chain: Arc>, + log: &slog::Logger, +) -> exit_future::Signal +where + T: store::Store, + U: slot_clock::SlotClock, + F: fork_choice::ForkChoice, + E: EthSpec, +{ + let log = log.new(o!("Service"=>"RPC")); + let env = Arc::new(Environment::new(1)); + + // Create: + // - `shutdown_trigger` a one-shot to shut down this service. + // - `wait_for_shutdown` a future that will wait until someone calls shutdown. + let (shutdown_trigger, wait_for_shutdown) = exit_future::signal(); + + let iron = create_iron_http_server(); + + let spawn_rpc = { + let result = iron.http(config.listen_address.clone()); + + if result.is_ok() { + info!(log, "HTTP server running on {}", config.listen_address); + } else { + warn!( + log, + "HTTP server failed to start on {}", config.listen_address + ); + } + + wait_for_shutdown.and_then(move |_| { + info!(log, "HTTP server shutting down"); + + // TODO: shutdown server. + /* + server + .shutdown() + .wait() + .map(|_| ()) + .map_err(|e| warn!(log, "RPC server failed to shutdown: {:?}", e))?; + Ok(()) + */ + info!(log, "HTTP server exited"); + Ok(()) + }) + }; + executor.spawn(spawn_rpc); + shutdown_trigger +}