mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-18 05:18:30 +00:00
[Remote signer] Fold signer into Lighthouse repository (#1852)
The remote signer relies on the `types` and `crypto/bls` crates from Lighthouse. Moreover, a number of tests of the remote signer consumption of LH leverages this very signer, making any important update a potential dependency nightmare. Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
113
remote_signer/client/src/handler.rs
Normal file
113
remote_signer/client/src/handler.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use crate::api_error::{ApiError, ApiResult};
|
||||
use crate::rest_api::Context;
|
||||
use hyper::{Body, Request, Response, StatusCode};
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use types::EthSpec;
|
||||
|
||||
/// Provides a HTTP request handler with specific functionality.
|
||||
pub struct Handler<E: EthSpec, S: Send + Sync> {
|
||||
req: Request<()>,
|
||||
body: Body,
|
||||
ctx: Arc<Context<E, S>>,
|
||||
allow_body: bool,
|
||||
}
|
||||
|
||||
impl<E: EthSpec, S: 'static + Send + Sync> Handler<E, S> {
|
||||
/// Start handling a new request.
|
||||
pub fn new(req: Request<Body>, ctx: Arc<Context<E, S>>) -> Result<Self, ApiError> {
|
||||
let (req_parts, body) = req.into_parts();
|
||||
let req = Request::from_parts(req_parts, ());
|
||||
|
||||
Ok(Self {
|
||||
req,
|
||||
body,
|
||||
ctx,
|
||||
allow_body: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a simple static value.
|
||||
///
|
||||
/// Does not use the blocking executor.
|
||||
pub async fn static_value<V>(self, value: V) -> Result<HandledRequest<V>, ApiError> {
|
||||
// Always check and disallow a body for a static value.
|
||||
let _ = Self::get_body(self.body, false).await?;
|
||||
|
||||
Ok(HandledRequest { value })
|
||||
}
|
||||
|
||||
/// The default behaviour is to return an error if any body is supplied in the request. Calling
|
||||
/// this function disables that error.
|
||||
pub fn allow_body(mut self) -> Self {
|
||||
self.allow_body = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Spawns `func` on the blocking executor.
|
||||
///
|
||||
/// This method is suitable for handling long-running or intensive tasks.
|
||||
pub async fn in_blocking_task<F, V>(self, func: F) -> Result<HandledRequest<V>, ApiError>
|
||||
where
|
||||
V: Send + Sync + 'static,
|
||||
F: Fn(Request<Vec<u8>>, Arc<Context<E, S>>) -> Result<V, ApiError> + Send + Sync + 'static,
|
||||
{
|
||||
let ctx = self.ctx;
|
||||
let executor = ctx.executor.clone();
|
||||
let body = Self::get_body(self.body, self.allow_body).await?;
|
||||
let (req_parts, _) = self.req.into_parts();
|
||||
let req = Request::from_parts(req_parts, body);
|
||||
|
||||
let value = executor
|
||||
.runtime_handle()
|
||||
.spawn_blocking(move || func(req, ctx))
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ApiError::ServerError(format!(
|
||||
"Failed to get blocking join handle: {}",
|
||||
e.to_string()
|
||||
))
|
||||
})??;
|
||||
|
||||
Ok(HandledRequest { value })
|
||||
}
|
||||
|
||||
/// Downloads the bytes for `body`.
|
||||
async fn get_body(body: Body, allow_body: bool) -> Result<Vec<u8>, ApiError> {
|
||||
let bytes = hyper::body::to_bytes(body)
|
||||
.await
|
||||
.map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e)))?;
|
||||
|
||||
if !allow_body && !bytes[..].is_empty() {
|
||||
Err(ApiError::BadRequest(
|
||||
"The request body must be empty".to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(bytes.into_iter().collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A request that has been "handled" and now a result (`value`) needs to be serialized and
|
||||
/// returned.
|
||||
pub struct HandledRequest<V> {
|
||||
value: V,
|
||||
}
|
||||
|
||||
impl<V: Serialize> HandledRequest<V> {
|
||||
/// Suitable for items which only implement `serde`.
|
||||
pub fn serde_encodings(self) -> ApiResult {
|
||||
let body = Body::from(serde_json::to_string(&self.value).map_err(|e| {
|
||||
ApiError::ServerError(format!(
|
||||
"Unable to serialize response body as JSON: {:?}",
|
||||
e
|
||||
))
|
||||
})?);
|
||||
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header("content-type", "application/json")
|
||||
.body(body)
|
||||
.map_err(|e| ApiError::ServerError(format!("Failed to build response: {:?}", e)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user