use super::utils::w;
use crate::chain::{Chain, SyncState, SyncStatus};
use crate::p2p;
use crate::rest::*;
use crate::router::{Handler, ResponseFuture};
use crate::types::*;
use crate::web::*;
use hyper::{Body, Request, StatusCode};
use mwc_core::global;
use serde_json::json;
use std::convert::TryInto;
use std::sync::atomic::Ordering;
use std::sync::Weak;
pub struct IndexHandler {
pub list: Vec<String>,
}
impl IndexHandler {}
impl Handler for IndexHandler {
fn get(&self, _req: Request<Body>) -> ResponseFuture {
json_response_pretty(&self.list)
}
}
pub struct StatusHandler {
pub chain: Weak<Chain>,
pub peers: Weak<p2p::Peers>,
pub sync_state: Weak<SyncState>,
pub allow_to_stop: bool, }
impl StatusHandler {
pub fn get_status(&self) -> Result<Status, Error> {
let head = w(&self.chain)?
.head()
.map_err(|e| Error::Internal(format!("Unable to get chain tip, {}", e)))?;
let sync_status = w(&self.sync_state)?.status();
let (api_sync_status, api_sync_info) = sync_status_to_api(sync_status);
Ok(Status::from_tip_and_peers(
head,
w(&self.peers)?
.iter()
.connected()
.count()
.try_into()
.unwrap(),
api_sync_status,
api_sync_info,
))
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StatusOutput {
pub processed: Vec<String>,
}
impl StatusOutput {
pub fn new(processed: &Vec<String>) -> StatusOutput {
StatusOutput {
processed: processed.clone(),
}
}
}
impl Handler for StatusHandler {
fn get(&self, _req: Request<Body>) -> ResponseFuture {
result_to_response(self.get_status())
}
fn post(&self, req: Request<Body>) -> ResponseFuture {
if let Some(query) = req.uri().query() {
let mut commitments: Vec<String> = vec![];
let params = QueryParams::from(query);
params.process_multival_param("action", |id| commitments.push(id.to_owned()));
let mut processed = vec![];
for action_str in commitments {
if self.allow_to_stop && action_str == "stop_node" {
warn!("Stopping the node by API request...");
processed.push(action_str);
global::get_server_running_controller().store(false, Ordering::SeqCst);
}
}
result_to_response(Ok(StatusOutput::new(&processed)))
} else {
response(
StatusCode::BAD_REQUEST,
format!("Expected 'action' parameter at request"),
)
}
}
}
fn sync_status_to_api(sync_status: SyncStatus) -> (String, Option<serde_json::Value>) {
match sync_status {
SyncStatus::NoSync => ("no_sync".to_string(), None),
SyncStatus::AwaitingPeers => ("awaiting_peers".to_string(), None),
SyncStatus::HeaderSync {
current_height,
archive_height,
..
} => (
"header_sync".to_string(),
Some(json!({ "current_height": current_height, "highest_height": archive_height })),
),
SyncStatus::TxHashsetRangeProofsValidation {
rproofs,
rproofs_total,
} => (
"txhashset_rangeproofs_validation".to_string(),
Some(json!({ "rproofs": rproofs, "rproofs_total": rproofs_total })),
),
SyncStatus::TxHashsetKernelsValidation {
kernels,
kernels_total,
} => (
"txhashset_kernels_validation".to_string(),
Some(json!({ "kernels": kernels, "kernels_total": kernels_total })),
),
SyncStatus::BodySync {
archive_height,
current_height,
highest_height,
} => (
"body_sync".to_string(),
Some(
json!({ "archive_height":archive_height, "current_height": current_height, "highest_height": highest_height }),
),
),
SyncStatus::Shutdown => ("shutdown".to_string(), None),
_ => ("syncing".to_string(), None),
}
}