use crate::api::rpc::RpcHandler; use crate::config::Config; use anyhow::Result; use http_body_util::{BodyExt, Full}; use hyper::body::Bytes; use hyper::{Method, Request, Response, StatusCode}; use hyper_util::rt::TokioIo; use std::sync::Arc; use tracing::debug; pub struct ApiHandler { config: Config, rpc_handler: Arc, // Add other handlers here (websocket, static files, etc.) } impl ApiHandler { pub async fn new(config: Config) -> Result { let rpc_handler = Arc::new(RpcHandler::new(config.clone()).await?); Ok(Self { config, rpc_handler, }) } pub async fn handle_request(&self, req: Request) -> Result>> where B: http_body::Body + Send + 'static, B::Error: std::fmt::Display, { let path = req.uri().path(); let method = req.method(); // Convert Incoming body to bytes using http_body_util::BodyExt let (parts, body) = req.into_parts(); // hyper::body::Incoming implements http_body::Body, and BodyExt extends it use http_body_util::BodyExt; let collected = body.collect().await .map_err(|_e| anyhow::anyhow!("Failed to read body"))?; let body_bytes = collected.to_bytes(); // Reconstruct request with Full body for RPC handler let req_with_bytes = Request::from_parts(parts, Full::new(body_bytes)); debug!("{} {}", method, path); // Route requests match (method, path.as_str()) { (&Method::POST, "/rpc/v1") => { self.rpc_handler.handle(req_with_bytes).await } (&Method::GET, "/health") => { Ok(Response::builder() .status(StatusCode::OK) .body(Full::new(Bytes::from("OK"))) .unwrap()) } _ => { Ok(Response::builder() .status(StatusCode::NOT_FOUND) .body(Full::new(Bytes::from("Not Found"))) .unwrap()) } } } }