#![allow(clippy::field_reassign_with_default)]
use std::str;
use futures::{future::BoxFuture, FutureExt};
use http::Response;
use hyper::Body;
use once_cell::sync::Lazy;
use schemars::JsonSchema;
use semver::Version;
use serde::{Deserialize, Serialize};
use tracing::info;
use warp_json_rpc::Builder;
use casper_types::ExecutionResult;
use super::{
docs::DocExample, Error, ErrorCode, ReactorEventT, RpcRequest, RpcWithParams, RpcWithParamsExt,
RpcWithoutParams, RpcWithoutParamsExt,
};
use crate::{
components::CLIENT_API_VERSION,
effect::EffectBuilder,
reactor::QueueKind,
types::{Block, BlockHash, Deploy, DeployHash, GetStatusResult, Item, PeersMap},
};
static GET_DEPLOY_PARAMS: Lazy<GetDeployParams> = Lazy::new(|| GetDeployParams {
deploy_hash: *Deploy::doc_example().id(),
});
static GET_DEPLOY_RESULT: Lazy<GetDeployResult> = Lazy::new(|| GetDeployResult {
api_version: CLIENT_API_VERSION.clone(),
deploy: Deploy::doc_example().clone(),
execution_results: vec![JsonExecutionResult {
block_hash: Block::doc_example().id(),
result: ExecutionResult::example().clone(),
}],
});
static GET_PEERS_RESULT: Lazy<GetPeersResult> = Lazy::new(|| GetPeersResult {
api_version: CLIENT_API_VERSION.clone(),
peers: GetStatusResult::doc_example().peers.clone(),
});
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GetDeployParams {
pub deploy_hash: DeployHash,
}
impl DocExample for GetDeployParams {
fn doc_example() -> &'static Self {
&*GET_DEPLOY_PARAMS
}
}
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct JsonExecutionResult {
pub block_hash: BlockHash,
pub result: ExecutionResult,
}
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GetDeployResult {
#[schemars(with = "String")]
pub api_version: Version,
pub deploy: Deploy,
pub execution_results: Vec<JsonExecutionResult>,
}
impl DocExample for GetDeployResult {
fn doc_example() -> &'static Self {
&*GET_DEPLOY_RESULT
}
}
pub struct GetDeploy {}
impl RpcWithParams for GetDeploy {
const METHOD: &'static str = "info_get_deploy";
type RequestParams = GetDeployParams;
type ResponseResult = GetDeployResult;
}
impl RpcWithParamsExt for GetDeploy {
fn handle_request<REv: ReactorEventT>(
effect_builder: EffectBuilder<REv>,
response_builder: Builder,
params: Self::RequestParams,
) -> BoxFuture<'static, Result<Response<Body>, Error>> {
async move {
let maybe_deploy_and_metadata = effect_builder
.make_request(
|responder| RpcRequest::GetDeploy {
hash: params.deploy_hash,
responder,
},
QueueKind::Api,
)
.await;
let (deploy, metadata) = match maybe_deploy_and_metadata {
Some((deploy, metadata)) => (deploy, metadata),
None => {
info!(
"failed to get {} and metadata from storage",
params.deploy_hash
);
return Ok(response_builder.error(warp_json_rpc::Error::custom(
ErrorCode::NoSuchDeploy as i64,
"deploy not known",
))?);
}
};
let execution_results = metadata
.execution_results
.into_iter()
.map(|(block_hash, result)| JsonExecutionResult { block_hash, result })
.collect();
let result = Self::ResponseResult {
api_version: CLIENT_API_VERSION.clone(),
deploy,
execution_results,
};
Ok(response_builder.success(result)?)
}
.boxed()
}
}
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GetPeersResult {
#[schemars(with = "String")]
pub api_version: Version,
pub peers: PeersMap,
}
impl DocExample for GetPeersResult {
fn doc_example() -> &'static Self {
&*GET_PEERS_RESULT
}
}
pub struct GetPeers {}
impl RpcWithoutParams for GetPeers {
const METHOD: &'static str = "info_get_peers";
type ResponseResult = GetPeersResult;
}
impl RpcWithoutParamsExt for GetPeers {
fn handle_request<REv: ReactorEventT>(
effect_builder: EffectBuilder<REv>,
response_builder: Builder,
) -> BoxFuture<'static, Result<Response<Body>, Error>> {
async move {
let peers = effect_builder
.make_request(
|responder| RpcRequest::GetPeers { responder },
QueueKind::Api,
)
.await;
let result = Self::ResponseResult {
api_version: CLIENT_API_VERSION.clone(),
peers: PeersMap::from(peers),
};
Ok(response_builder.success(result)?)
}
.boxed()
}
}
pub struct GetStatus {}
impl RpcWithoutParams for GetStatus {
const METHOD: &'static str = "info_get_status";
type ResponseResult = GetStatusResult;
}
impl RpcWithoutParamsExt for GetStatus {
fn handle_request<REv: ReactorEventT>(
effect_builder: EffectBuilder<REv>,
response_builder: Builder,
) -> BoxFuture<'static, Result<Response<Body>, Error>> {
async move {
let status_feed = effect_builder
.make_request(
|responder| RpcRequest::GetStatus { responder },
QueueKind::Api,
)
.await;
let mut body = Self::ResponseResult::from(status_feed);
body.set_api_version(CLIENT_API_VERSION.clone());
Ok(response_builder.success(body)?)
}
.boxed()
}
}