Add node/fork
endpoint to HTTP API, tidy
This commit is contained in:
parent
705edf0e45
commit
255590ef3b
@ -18,12 +18,16 @@ slot_clock = { path = "../../eth2/utils/slot_clock" }
|
|||||||
protos = { path = "../../protos" }
|
protos = { path = "../../protos" }
|
||||||
fork_choice = { path = "../../eth2/fork_choice" }
|
fork_choice = { path = "../../eth2/fork_choice" }
|
||||||
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
|
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
|
||||||
|
persistent = "^0.4"
|
||||||
protobuf = "2.0.2"
|
protobuf = "2.0.2"
|
||||||
prometheus = "^0.6"
|
prometheus = "^0.6"
|
||||||
clap = "2.32.0"
|
clap = "2.32.0"
|
||||||
store = { path = "../store" }
|
store = { path = "../store" }
|
||||||
dirs = "1.0.3"
|
dirs = "1.0.3"
|
||||||
futures = "0.1.23"
|
futures = "0.1.23"
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
slog = "^2.2.3"
|
slog = "^2.2.3"
|
||||||
slog-term = "^2.4.0"
|
slog-term = "^2.4.0"
|
||||||
slog-async = "^2.3.0"
|
slog-async = "^2.3.0"
|
||||||
|
69
beacon_node/http_server/src/api.rs
Normal file
69
beacon_node/http_server/src/api.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use crate::key::BeaconChainKey;
|
||||||
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
|
use iron::prelude::*;
|
||||||
|
use iron::{
|
||||||
|
headers::{CacheControl, CacheDirective, ContentType},
|
||||||
|
status::Status,
|
||||||
|
AfterMiddleware, Handler, IronResult, Request, Response,
|
||||||
|
};
|
||||||
|
use persistent::Read;
|
||||||
|
use router::Router;
|
||||||
|
use serde_json::json;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn build_handler<T: BeaconChainTypes + 'static>(
|
||||||
|
beacon_chain: Arc<BeaconChain<T>>,
|
||||||
|
) -> impl Handler {
|
||||||
|
let mut router = Router::new();
|
||||||
|
|
||||||
|
router.get("/node/fork", handle_fork::<T>, "fork");
|
||||||
|
|
||||||
|
let mut chain = Chain::new(router);
|
||||||
|
|
||||||
|
// Insert `BeaconChain` so it may be accessed in a request.
|
||||||
|
chain.link(Read::<BeaconChainKey<T>>::both(beacon_chain.clone()));
|
||||||
|
// Set the content-type headers.
|
||||||
|
chain.link_after(SetJsonContentType);
|
||||||
|
// Set the cache headers.
|
||||||
|
chain.link_after(SetCacheDirectives);
|
||||||
|
|
||||||
|
chain
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `cache-control` headers on _all_ responses, unless they are already set.
|
||||||
|
struct SetCacheDirectives;
|
||||||
|
impl AfterMiddleware for SetCacheDirectives {
|
||||||
|
fn after(&self, _req: &mut Request, mut resp: Response) -> IronResult<Response> {
|
||||||
|
// This is run for every requests, AFTER all handlers have been executed
|
||||||
|
if resp.headers.get::<CacheControl>() == None {
|
||||||
|
resp.headers.set(CacheControl(vec![
|
||||||
|
CacheDirective::NoCache,
|
||||||
|
CacheDirective::NoStore,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `content-type` headers on _all_ responses, unless they are already set.
|
||||||
|
struct SetJsonContentType;
|
||||||
|
impl AfterMiddleware for SetJsonContentType {
|
||||||
|
fn after(&self, _req: &mut Request, mut resp: Response) -> IronResult<Response> {
|
||||||
|
if resp.headers.get::<ContentType>() == None {
|
||||||
|
resp.headers.set(ContentType::json());
|
||||||
|
}
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_fork<T: BeaconChainTypes + 'static>(req: &mut Request) -> IronResult<Response> {
|
||||||
|
// TODO: investigate unwrap - I'm _guessing_ we'll never hit it but we should check to be sure.
|
||||||
|
let beacon_chain = req.get::<Read<BeaconChainKey<T>>>().unwrap();
|
||||||
|
|
||||||
|
let response = json!({
|
||||||
|
"fork": beacon_chain.head().beacon_state.fork,
|
||||||
|
"chain_id": beacon_chain.spec.chain_id
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Response::with((Status::Ok, response.to_string())))
|
||||||
|
}
|
12
beacon_node/http_server/src/key.rs
Normal file
12
beacon_node/http_server/src/key.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
|
use iron::typemap::Key;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct BeaconChainKey<T> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BeaconChainTypes + 'static> Key for BeaconChainKey<T> {
|
||||||
|
type Value = Arc<BeaconChain<T>>;
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
mod prometheus_handler;
|
mod api;
|
||||||
|
mod key;
|
||||||
|
mod metrics;
|
||||||
|
|
||||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
use iron::{status::Status, Handler, IronResult, Request, Response};
|
|
||||||
use network::NetworkMessage;
|
use network::NetworkMessage;
|
||||||
use prometheus_handler::PrometheusHandler;
|
|
||||||
use router::Router;
|
use router::Router;
|
||||||
use slog::{info, o, warn};
|
use slog::{info, o, warn};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -26,32 +26,26 @@ impl Default for HttpServerConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IndexHandler {
|
/// Build the `iron` HTTP server, defining the core routes.
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handler for IndexHandler {
|
|
||||||
fn handle(&self, _: &mut Request) -> IronResult<Response> {
|
|
||||||
Ok(Response::with((Status::Ok, self.message.clone())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_iron_http_server<T: BeaconChainTypes + 'static>(
|
pub fn create_iron_http_server<T: BeaconChainTypes + 'static>(
|
||||||
beacon_chain: Arc<BeaconChain<T>>,
|
beacon_chain: Arc<BeaconChain<T>>,
|
||||||
) -> Iron<Router> {
|
) -> Iron<Router> {
|
||||||
let index_handler = IndexHandler {
|
|
||||||
message: "Hello world".to_string(),
|
|
||||||
};
|
|
||||||
let prom_handler = PrometheusHandler {
|
|
||||||
beacon_chain: beacon_chain,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut router = Router::new();
|
let mut router = Router::new();
|
||||||
router.get("/", index_handler, "index");
|
|
||||||
router.get("/metrics", prom_handler, "metrics");
|
// A `GET` request to `/metrics` is handled by the `metrics` module.
|
||||||
|
router.get(
|
||||||
|
"/metrics",
|
||||||
|
metrics::build_handler(beacon_chain.clone()),
|
||||||
|
"metrics",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Any request to all other endpoints is handled by the `api` module.
|
||||||
|
router.any("/*", api::build_handler(beacon_chain.clone()), "api");
|
||||||
|
|
||||||
Iron::new(router)
|
Iron::new(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start the HTTP service on the tokio `TaskExecutor`.
|
||||||
pub fn start_service<T: BeaconChainTypes + 'static>(
|
pub fn start_service<T: BeaconChainTypes + 'static>(
|
||||||
config: &HttpServerConfig,
|
config: &HttpServerConfig,
|
||||||
executor: &TaskExecutor,
|
executor: &TaskExecutor,
|
||||||
|
57
beacon_node/http_server/src/metrics.rs
Normal file
57
beacon_node/http_server/src/metrics.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use crate::key::BeaconChainKey;
|
||||||
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
|
use iron::prelude::*;
|
||||||
|
use iron::{status::Status, Handler, IronResult, Request, Response};
|
||||||
|
use persistent::Read;
|
||||||
|
use prometheus::{Encoder, IntCounter, Opts, Registry, TextEncoder};
|
||||||
|
use slot_clock::SlotClock;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use types::Slot;
|
||||||
|
|
||||||
|
pub fn build_handler<T: BeaconChainTypes + 'static>(
|
||||||
|
beacon_chain: Arc<BeaconChain<T>>,
|
||||||
|
) -> impl Handler {
|
||||||
|
let mut chain = Chain::new(handle_metrics::<T>);
|
||||||
|
|
||||||
|
chain.link(Read::<BeaconChainKey<T>>::both(beacon_chain));
|
||||||
|
|
||||||
|
chain
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle a request for Prometheus metrics.
|
||||||
|
///
|
||||||
|
/// Returns a text string containing all metrics.
|
||||||
|
fn handle_metrics<T: BeaconChainTypes + 'static>(req: &mut Request) -> IronResult<Response> {
|
||||||
|
let beacon_chain = req.get::<Read<BeaconChainKey<T>>>().unwrap();
|
||||||
|
|
||||||
|
let r = Registry::new();
|
||||||
|
|
||||||
|
let present_slot = if let Ok(Some(slot)) = beacon_chain.slot_clock.present_slot() {
|
||||||
|
slot
|
||||||
|
} else {
|
||||||
|
Slot::new(0)
|
||||||
|
};
|
||||||
|
register_and_set_slot(
|
||||||
|
&r,
|
||||||
|
"present_slot",
|
||||||
|
"direct_slock_clock_reading",
|
||||||
|
present_slot,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Gather the metrics.
|
||||||
|
let mut buffer = vec![];
|
||||||
|
let encoder = TextEncoder::new();
|
||||||
|
let metric_families = r.gather();
|
||||||
|
encoder.encode(&metric_families, &mut buffer).unwrap();
|
||||||
|
|
||||||
|
let prom_string = String::from_utf8(buffer).unwrap();
|
||||||
|
|
||||||
|
Ok(Response::with((Status::Ok, prom_string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_and_set_slot(registry: &Registry, name: &str, help: &str, slot: Slot) {
|
||||||
|
let counter_opts = Opts::new(name, help);
|
||||||
|
let counter = IntCounter::with_opts(counter_opts).unwrap();
|
||||||
|
registry.register(Box::new(counter.clone())).unwrap();
|
||||||
|
counter.inc_by(slot.as_u64() as i64);
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
|
||||||
use iron::{status::Status, Handler, IronResult, Request, Response};
|
|
||||||
use prometheus::{Encoder, IntCounter, Opts, Registry, TextEncoder};
|
|
||||||
use slot_clock::SlotClock;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use types::Slot;
|
|
||||||
|
|
||||||
pub struct PrometheusHandler<T: BeaconChainTypes> {
|
|
||||||
pub beacon_chain: Arc<BeaconChain<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: BeaconChainTypes> PrometheusHandler<T> {}
|
|
||||||
|
|
||||||
impl<T: BeaconChainTypes + 'static> Handler for PrometheusHandler<T> {
|
|
||||||
fn handle(&self, _: &mut Request) -> IronResult<Response> {
|
|
||||||
let r = Registry::new();
|
|
||||||
|
|
||||||
let present_slot = if let Ok(Some(slot)) = self.beacon_chain.slot_clock.present_slot() {
|
|
||||||
slot
|
|
||||||
} else {
|
|
||||||
Slot::new(0)
|
|
||||||
};
|
|
||||||
register_and_set_slot(
|
|
||||||
&r,
|
|
||||||
"present_slot",
|
|
||||||
"direct_slock_clock_reading",
|
|
||||||
present_slot,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Gather the metrics.
|
|
||||||
let mut buffer = vec![];
|
|
||||||
let encoder = TextEncoder::new();
|
|
||||||
let metric_families = r.gather();
|
|
||||||
encoder.encode(&metric_families, &mut buffer).unwrap();
|
|
||||||
|
|
||||||
let prom_string = String::from_utf8(buffer).unwrap();
|
|
||||||
|
|
||||||
Ok(Response::with((Status::Ok, prom_string)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_and_set_slot(registry: &Registry, name: &str, help: &str, slot: Slot) {
|
|
||||||
let counter_opts = Opts::new(name, help);
|
|
||||||
let counter = IntCounter::with_opts(counter_opts).unwrap();
|
|
||||||
registry.register(Box::new(counter.clone())).unwrap();
|
|
||||||
counter.inc_by(slot.as_u64() as i64);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user