error refactor for user endpoints
This commit is contained in:
parent
8ebe7000ad
commit
305d89ddf4
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -401,6 +401,18 @@ dependencies = [
|
||||
"mime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-macros"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6293dae2ec708e679da6736e857cf8532886ef258e92930f38279c12641628b8"
|
||||
dependencies = [
|
||||
"heck 0.4.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.65"
|
||||
@ -5482,6 +5494,7 @@ dependencies = [
|
||||
"argh",
|
||||
"axum",
|
||||
"axum-client-ip",
|
||||
"axum-macros",
|
||||
"counter",
|
||||
"dashmap",
|
||||
"derive_more",
|
||||
|
@ -21,6 +21,7 @@ arc-swap = "1.5.1"
|
||||
argh = "0.1.8"
|
||||
axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] }
|
||||
axum-client-ip = "0.2.0"
|
||||
axum-macros = "*"
|
||||
counter = "0.5.6"
|
||||
dashmap = "5.3.4"
|
||||
derive_more = "0.99.17"
|
||||
|
@ -1,11 +1,21 @@
|
||||
use crate::jsonrpc::JsonRpcForwardedResponse;
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use serde_json::value::RawValue;
|
||||
use std::error::Error;
|
||||
|
||||
use crate::jsonrpc::JsonRpcForwardedResponse;
|
||||
pub struct ErrorResponse {
|
||||
pub inner: Box<dyn Error>,
|
||||
}
|
||||
|
||||
impl IntoResponse for ErrorResponse {
|
||||
fn into_response(self) -> Response {
|
||||
todo!("into_response based on the error type")
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handler_404() -> Response {
|
||||
let err = anyhow::anyhow!("nothing to see here");
|
||||
@ -13,6 +23,7 @@ pub async fn handler_404() -> Response {
|
||||
anyhow_error_into_response(Some(StatusCode::NOT_FOUND), None, err)
|
||||
}
|
||||
|
||||
/// TODO: generic error?
|
||||
/// 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
|
||||
/// TODO: i think we want a custom result type instead. put the anyhow result inside. then `impl IntoResponse for CustomResult`
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::app::Web3ProxyApp;
|
||||
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::app::Web3ProxyApp;
|
||||
|
||||
/// Health check page for load balancers to use
|
||||
pub async fn health(Extension(app): Extension<Arc<Web3ProxyApp>>) -> impl IntoResponse {
|
||||
if app.balanced_rpcs.synced() {
|
||||
|
@ -1,3 +1,7 @@
|
||||
use super::errors::anyhow_error_into_response;
|
||||
use super::rate_limit::RateLimitResult;
|
||||
use crate::stats::{Protocol, ProxyRequestLabels};
|
||||
use crate::{app::Web3ProxyApp, jsonrpc::JsonRpcRequestEnum};
|
||||
use axum::extract::Path;
|
||||
use axum::response::Response;
|
||||
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
||||
@ -6,11 +10,6 @@ use std::sync::Arc;
|
||||
use tracing::{error_span, Instrument};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::errors::anyhow_error_into_response;
|
||||
use super::rate_limit::RateLimitResult;
|
||||
use crate::stats::{Protocol, ProxyRequestLabels};
|
||||
use crate::{app::Web3ProxyApp, jsonrpc::JsonRpcRequestEnum};
|
||||
|
||||
pub async fn public_proxy_web3_rpc(
|
||||
Json(payload): Json<JsonRpcRequestEnum>,
|
||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||
|
@ -6,10 +6,13 @@ mod rate_limit;
|
||||
mod users;
|
||||
mod ws_proxy;
|
||||
|
||||
use ::http::Request;
|
||||
use crate::app::Web3ProxyApp;
|
||||
use ::http::{Request, StatusCode};
|
||||
use axum::{
|
||||
body::Body,
|
||||
error_handling::HandleError,
|
||||
handler::Handler,
|
||||
response::Response,
|
||||
routing::{get, post},
|
||||
Extension, Router,
|
||||
};
|
||||
@ -19,7 +22,15 @@ use tower_http::trace::TraceLayer;
|
||||
use tower_request_id::{RequestId, RequestIdLayer};
|
||||
use tracing::{error_span, info};
|
||||
|
||||
use crate::app::Web3ProxyApp;
|
||||
// handle errors by converting them into something that implements
|
||||
// `IntoResponse`
|
||||
async fn handle_anyhow_error(err: anyhow::Error) -> (StatusCode, String) {
|
||||
// TODO: i dont like this, but lets see if it works. need to moved to the errors module and replace the version that is there
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", err),
|
||||
)
|
||||
}
|
||||
|
||||
/// http and websocket frontend for customers
|
||||
pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()> {
|
||||
@ -42,6 +53,12 @@ pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()
|
||||
)
|
||||
});
|
||||
|
||||
// create user endpoint needs some work sothat
|
||||
let some_fallible_service = tower::service_fn(|_req| async {
|
||||
// thing_that_might_fail().await?;
|
||||
Ok::<_, anyhow::Error>(Response::new(Body::empty()))
|
||||
});
|
||||
|
||||
// build our application with a route
|
||||
// order most to least common
|
||||
let app = Router::new()
|
||||
@ -51,7 +68,18 @@ pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()
|
||||
.route("/u/:user_key", get(ws_proxy::user_websocket_handler))
|
||||
.route("/health", get(http::health))
|
||||
.route("/status", get(http::status))
|
||||
// .route(
|
||||
// "/login",
|
||||
// HandleError::new(
|
||||
// move |app| async { users::get_login(app).await },
|
||||
// handle_anyhow_error,
|
||||
// ),
|
||||
// )
|
||||
.route("/users", post(users::create_user))
|
||||
.route(
|
||||
"/foo",
|
||||
HandleError::new(some_fallible_service, handle_anyhow_error),
|
||||
)
|
||||
.layer(Extension(proxy_app))
|
||||
// create a unique id for each request and add it to our tracing logs
|
||||
.layer(request_tracing_layer)
|
||||
|
@ -1,3 +1,5 @@
|
||||
use super::errors::anyhow_error_into_response;
|
||||
use crate::app::{UserCacheValue, Web3ProxyApp};
|
||||
use axum::response::Response;
|
||||
use entities::user_keys;
|
||||
use redis_rate_limit::ThrottleResult;
|
||||
@ -10,10 +12,6 @@ use tokio::time::Instant;
|
||||
use tracing::{debug, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::app::{UserCacheValue, Web3ProxyApp};
|
||||
|
||||
use super::errors::anyhow_error_into_response;
|
||||
|
||||
pub enum RateLimitResult {
|
||||
AllowedIp(IpAddr),
|
||||
AllowedUser(u64),
|
||||
|
@ -7,11 +7,14 @@
|
||||
// I wonder how we handle payment
|
||||
// probably have to do manual withdrawals
|
||||
|
||||
use super::{errors::anyhow_error_into_response, rate_limit::RateLimitResult};
|
||||
use crate::app::Web3ProxyApp;
|
||||
use axum::{
|
||||
response::{IntoResponse, Response},
|
||||
Extension, Json,
|
||||
};
|
||||
use axum_client_ip::ClientIp;
|
||||
use axum_macros::debug_handler;
|
||||
use entities::user;
|
||||
use ethers::{prelude::Address, types::Bytes};
|
||||
use reqwest::StatusCode;
|
||||
@ -19,9 +22,15 @@ use sea_orm::ActiveModelTrait;
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::app::Web3ProxyApp;
|
||||
#[debug_handler]
|
||||
pub async fn get_login(Extension(app): Extension<Arc<Web3ProxyApp>>) -> Result<Response, Response> {
|
||||
// let redis: RedisPool = app...;
|
||||
let redis_pool = app.redis_pool.as_ref().unwrap();
|
||||
|
||||
use super::{errors::anyhow_error_into_response, rate_limit::RateLimitResult};
|
||||
let redis_conn = redis_pool.get().await.unwrap();
|
||||
|
||||
todo!("how should this work? probably keep stuff in redis ")
|
||||
}
|
||||
|
||||
pub async fn create_user(
|
||||
// this argument tells axum to parse the request body
|
||||
@ -30,13 +39,14 @@ pub async fn create_user(
|
||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||
ClientIp(ip): ClientIp,
|
||||
) -> Response {
|
||||
// TODO: return a Result instead
|
||||
let _ip = match app.rate_limit_by_ip(ip).await {
|
||||
Ok(x) => match x.try_into_response().await {
|
||||
Ok(RateLimitResult::AllowedIp(x)) => x,
|
||||
Err(err_response) => return err_response,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
Err(err) => return anyhow_error_into_response(None, None, err).into_response(),
|
||||
Err(err) => return anyhow_error_into_response(None, None, err),
|
||||
};
|
||||
|
||||
// TODO: check invite_code against the app's config or database
|
||||
@ -65,7 +75,7 @@ pub async fn create_user(
|
||||
// TODO: proper error message
|
||||
let user = user.insert(db).await.unwrap();
|
||||
|
||||
//
|
||||
// TODO: create
|
||||
|
||||
// TODO: do not expose user ids
|
||||
(StatusCode::CREATED, Json(user)).into_response()
|
||||
|
@ -193,7 +193,7 @@ impl JsonRpcForwardedResponse {
|
||||
id,
|
||||
result: None,
|
||||
error: Some(JsonRpcErrorData {
|
||||
// TODO: set this jsonrpc error code to match the http status code? or maybe the other way around?
|
||||
// TODO: set this jsonrpc error code to match the http status code? or maybe the other way around? maybe take it as an arg
|
||||
code: -32099,
|
||||
// TODO: some errors should be included here. others should not. i think anyhow might not be the right choice
|
||||
// message: "internal server error".to_string(),
|
||||
|
Loading…
Reference in New Issue
Block a user