split frontend code up

This commit is contained in:
Bryan Stitt 2022-06-05 19:58:47 +00:00
parent 7e3e28fbc1
commit 8427004516
5 changed files with 122 additions and 101 deletions

@ -0,0 +1,31 @@
use crate::jsonrpc::JsonRpcForwardedResponse;
use axum::{http::StatusCode, response::IntoResponse, Json};
use serde_json::value::RawValue;
use tracing::warn;
/// TODO: pretty 404 page? or us a json error fine?
pub async fn handler_404() -> impl IntoResponse {
let err = anyhow::anyhow!("nothing to see here");
handle_anyhow_error(err, Some(StatusCode::NOT_FOUND)).await
}
/// handle errors by converting them into something that implements `IntoResponse`
/// TODO: use this. i can't get https://docs.rs/axum/latest/axum/error_handling/index.html to work
pub async fn handle_anyhow_error(
err: anyhow::Error,
code: Option<StatusCode>,
) -> impl IntoResponse {
// TODO: what id can we use? how do we make sure the incoming id gets attached to this?
let id = RawValue::from_string("0".to_string()).unwrap();
let err = JsonRpcForwardedResponse::from_anyhow_error(err, id);
warn!("Responding with error: {:?}", err);
let code = code.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
(code, Json(err))
}
// i think we want a custom result type. it has an anyhow result inside. if it impl IntoResponse I think we'll get this for free

@ -0,0 +1,29 @@
use crate::app::Web3ProxyApp;
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
use serde_json::json;
use std::sync::Arc;
/// a page for configuring your wallet with all the rpcs
/// TODO: check auth (from authp?) here
/// TODO: return actual html
pub async fn index() -> impl IntoResponse {
"Hello, World!"
}
/// Very basic status page
pub async fn status(app: Extension<Arc<Web3ProxyApp>>) -> impl IntoResponse {
let app = app.0.as_ref();
let balanced_rpcs = app.get_balanced_rpcs();
let private_rpcs = app.get_private_rpcs();
let num_active_requests = app.get_active_requests().len();
// TODO: what else should we include? uptime? prometheus?
let body = json!({
"balanced_rpcs": balanced_rpcs,
"private_rpcs": private_rpcs,
"num_active_requests": num_active_requests,
});
(StatusCode::INTERNAL_SERVER_ERROR, Json(body))
}

@ -0,0 +1,14 @@
use super::errors::handle_anyhow_error;
use crate::{app::Web3ProxyApp, jsonrpc::JsonRpcRequestEnum};
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
use std::sync::Arc;
pub async fn proxy_web3_rpc(
payload: Json<JsonRpcRequestEnum>,
app: Extension<Arc<Web3ProxyApp>>,
) -> impl IntoResponse {
match app.0.proxy_web3_rpc(payload.0).await {
Ok(response) => (StatusCode::OK, Json(&response)).into_response(),
Err(err) => handle_anyhow_error(err, None).await.into_response(),
}
}

@ -0,0 +1,41 @@
/// this should move into web3-proxy once the basics are working
mod errors;
mod http;
mod http_proxy;
mod ws_proxy;
use axum::{
handler::Handler,
routing::{get, post},
Extension, Router,
};
use std::net::SocketAddr;
use std::sync::Arc;
use crate::app::Web3ProxyApp;
pub async fn run(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()> {
// TODO: check auth (from authp?) here
// build our application with a route
let app = Router::new()
// `POST /` goes to `proxy_web3_rpc`
.route("/", post(http_proxy::proxy_web3_rpc))
// `websocket /` goes to `proxy_web3_ws`
.route("/", get(ws_proxy::websocket_handler))
// `GET /index.html` goes to `index`
.route("/index.html", get(http::index))
// `GET /status` goes to `status`
.route("/status", get(http::status))
.layer(Extension(proxy_app));
// 404 for any unknown routes
let app = app.fallback(errors::handler_404.into_service());
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
let addr = SocketAddr::from(([0, 0, 0, 0], port));
tracing::info!("listening on port {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.map_err(Into::into)
}

@ -1,11 +1,11 @@
/// this should move into web3-proxy once the basics are working use crate::{
app::Web3ProxyApp,
jsonrpc::{JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcRequest},
};
use axum::{ use axum::{
extract::ws::{Message, WebSocket, WebSocketUpgrade}, extract::ws::{Message, WebSocket, WebSocketUpgrade},
handler::Handler,
http::StatusCode,
response::IntoResponse, response::IntoResponse,
routing::{get, post}, Extension,
Extension, Json, Router,
}; };
use futures::SinkExt; use futures::SinkExt;
use futures::{ use futures::{
@ -13,64 +13,12 @@ use futures::{
stream::{SplitSink, SplitStream, StreamExt}, stream::{SplitSink, SplitStream, StreamExt},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use serde_json::json;
use serde_json::value::RawValue; use serde_json::value::RawValue;
use std::net::SocketAddr;
use std::str::from_utf8_mut; use std::str::from_utf8_mut;
use std::sync::Arc; use std::sync::Arc;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info};
use crate::{ pub async fn websocket_handler(
app::Web3ProxyApp,
jsonrpc::{
JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcRequest, JsonRpcRequestEnum,
},
};
pub async fn run(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()> {
// build our application with a route
let app = Router::new()
// `GET /` goes to `root`
.route("/", get(root))
// `POST /` goes to `proxy_web3_rpc`
.route("/", post(proxy_web3_rpc))
// `websocket /` goes to `proxy_web3_ws`
.route("/ws", get(websocket_handler))
// `GET /status` goes to `status`
.route("/status", get(status))
.layer(Extension(proxy_app));
// 404 for any unknown routes
let app = app.fallback(handler_404.into_service());
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
let addr = SocketAddr::from(([0, 0, 0, 0], port));
tracing::info!("listening on port {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.map_err(Into::into)
}
/// a page for configuring your wallet with all the rpcs
/// TODO: check auth (from authp?) here
async fn root() -> impl IntoResponse {
"Hello, World!"
}
/// TODO: check auth (from authp?) here
async fn proxy_web3_rpc(
payload: Json<JsonRpcRequestEnum>,
app: Extension<Arc<Web3ProxyApp>>,
) -> impl IntoResponse {
match app.0.proxy_web3_rpc(payload.0).await {
Ok(response) => (StatusCode::OK, Json(&response)).into_response(),
Err(err) => _handle_anyhow_error(err, None).await.into_response(),
}
}
async fn websocket_handler(
app: Extension<Arc<Web3ProxyApp>>, app: Extension<Arc<Web3ProxyApp>>,
ws: WebSocketUpgrade, ws: WebSocketUpgrade,
) -> impl IntoResponse { ) -> impl IntoResponse {
@ -212,45 +160,3 @@ async fn write_web3_socket(
}; };
} }
} }
/// Very basic status page
async fn status(app: Extension<Arc<Web3ProxyApp>>) -> impl IntoResponse {
let app = app.0.as_ref();
let balanced_rpcs = app.get_balanced_rpcs();
let private_rpcs = app.get_private_rpcs();
let num_active_requests = app.get_active_requests().len();
// TODO: what else should we include? uptime? prometheus?
let body = json!({
"balanced_rpcs": balanced_rpcs,
"private_rpcs": private_rpcs,
"num_active_requests": num_active_requests,
});
(StatusCode::INTERNAL_SERVER_ERROR, Json(body))
}
/// TODO: pretty 404 page? or us a json error fine?
async fn handler_404() -> impl IntoResponse {
let err = anyhow::anyhow!("nothing to see here");
_handle_anyhow_error(err, Some(StatusCode::NOT_FOUND)).await
}
/// handle errors by converting them into something that implements `IntoResponse`
/// TODO: use this. i can't get https://docs.rs/axum/latest/axum/error_handling/index.html to work
async fn _handle_anyhow_error(err: anyhow::Error, code: Option<StatusCode>) -> impl IntoResponse {
// TODO: what id can we use? how do we make sure the incoming id gets attached to this?
let id = RawValue::from_string("0".to_string()).unwrap();
let err = JsonRpcForwardedResponse::from_anyhow_error(err, id);
warn!("Responding with error: {:?}", err);
let code = code.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
(code, Json(err))
}
// i think we want a custom result type. it has an anyhow result inside. it impl IntoResponse