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",
|
"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]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.65"
|
version = "0.3.65"
|
||||||
@ -5482,6 +5494,7 @@ dependencies = [
|
|||||||
"argh",
|
"argh",
|
||||||
"axum",
|
"axum",
|
||||||
"axum-client-ip",
|
"axum-client-ip",
|
||||||
|
"axum-macros",
|
||||||
"counter",
|
"counter",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
@ -21,6 +21,7 @@ arc-swap = "1.5.1"
|
|||||||
argh = "0.1.8"
|
argh = "0.1.8"
|
||||||
axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] }
|
axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] }
|
||||||
axum-client-ip = "0.2.0"
|
axum-client-ip = "0.2.0"
|
||||||
|
axum-macros = "*"
|
||||||
counter = "0.5.6"
|
counter = "0.5.6"
|
||||||
dashmap = "5.3.4"
|
dashmap = "5.3.4"
|
||||||
derive_more = "0.99.17"
|
derive_more = "0.99.17"
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
|
use crate::jsonrpc::JsonRpcForwardedResponse;
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
Json,
|
Json,
|
||||||
};
|
};
|
||||||
use serde_json::value::RawValue;
|
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 {
|
pub async fn handler_404() -> Response {
|
||||||
let err = anyhow::anyhow!("nothing to see here");
|
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)
|
anyhow_error_into_response(Some(StatusCode::NOT_FOUND), None, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: generic error?
|
||||||
/// handle errors by converting them into something that implements `IntoResponse`
|
/// 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: 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`
|
/// 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 axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::app::Web3ProxyApp;
|
|
||||||
|
|
||||||
/// Health check page for load balancers to use
|
/// Health check page for load balancers to use
|
||||||
pub async fn health(Extension(app): Extension<Arc<Web3ProxyApp>>) -> impl IntoResponse {
|
pub async fn health(Extension(app): Extension<Arc<Web3ProxyApp>>) -> impl IntoResponse {
|
||||||
if app.balanced_rpcs.synced() {
|
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::extract::Path;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
use axum::{http::StatusCode, response::IntoResponse, Extension, Json};
|
||||||
@ -6,11 +10,6 @@ use std::sync::Arc;
|
|||||||
use tracing::{error_span, Instrument};
|
use tracing::{error_span, Instrument};
|
||||||
use uuid::Uuid;
|
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(
|
pub async fn public_proxy_web3_rpc(
|
||||||
Json(payload): Json<JsonRpcRequestEnum>,
|
Json(payload): Json<JsonRpcRequestEnum>,
|
||||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||||
|
@ -6,10 +6,13 @@ mod rate_limit;
|
|||||||
mod users;
|
mod users;
|
||||||
mod ws_proxy;
|
mod ws_proxy;
|
||||||
|
|
||||||
use ::http::Request;
|
use crate::app::Web3ProxyApp;
|
||||||
|
use ::http::{Request, StatusCode};
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
|
error_handling::HandleError,
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
|
response::Response,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Extension, Router,
|
Extension, Router,
|
||||||
};
|
};
|
||||||
@ -19,7 +22,15 @@ use tower_http::trace::TraceLayer;
|
|||||||
use tower_request_id::{RequestId, RequestIdLayer};
|
use tower_request_id::{RequestId, RequestIdLayer};
|
||||||
use tracing::{error_span, info};
|
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
|
/// http and websocket frontend for customers
|
||||||
pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()> {
|
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
|
// build our application with a route
|
||||||
// order most to least common
|
// order most to least common
|
||||||
let app = Router::new()
|
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("/u/:user_key", get(ws_proxy::user_websocket_handler))
|
||||||
.route("/health", get(http::health))
|
.route("/health", get(http::health))
|
||||||
.route("/status", get(http::status))
|
.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("/users", post(users::create_user))
|
||||||
|
.route(
|
||||||
|
"/foo",
|
||||||
|
HandleError::new(some_fallible_service, handle_anyhow_error),
|
||||||
|
)
|
||||||
.layer(Extension(proxy_app))
|
.layer(Extension(proxy_app))
|
||||||
// create a unique id for each request and add it to our tracing logs
|
// create a unique id for each request and add it to our tracing logs
|
||||||
.layer(request_tracing_layer)
|
.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 axum::response::Response;
|
||||||
use entities::user_keys;
|
use entities::user_keys;
|
||||||
use redis_rate_limit::ThrottleResult;
|
use redis_rate_limit::ThrottleResult;
|
||||||
@ -10,10 +12,6 @@ use tokio::time::Instant;
|
|||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::app::{UserCacheValue, Web3ProxyApp};
|
|
||||||
|
|
||||||
use super::errors::anyhow_error_into_response;
|
|
||||||
|
|
||||||
pub enum RateLimitResult {
|
pub enum RateLimitResult {
|
||||||
AllowedIp(IpAddr),
|
AllowedIp(IpAddr),
|
||||||
AllowedUser(u64),
|
AllowedUser(u64),
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
// I wonder how we handle payment
|
// I wonder how we handle payment
|
||||||
// probably have to do manual withdrawals
|
// probably have to do manual withdrawals
|
||||||
|
|
||||||
|
use super::{errors::anyhow_error_into_response, rate_limit::RateLimitResult};
|
||||||
|
use crate::app::Web3ProxyApp;
|
||||||
use axum::{
|
use axum::{
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_client_ip::ClientIp;
|
use axum_client_ip::ClientIp;
|
||||||
|
use axum_macros::debug_handler;
|
||||||
use entities::user;
|
use entities::user;
|
||||||
use ethers::{prelude::Address, types::Bytes};
|
use ethers::{prelude::Address, types::Bytes};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
@ -19,9 +22,15 @@ use sea_orm::ActiveModelTrait;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
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(
|
pub async fn create_user(
|
||||||
// this argument tells axum to parse the request body
|
// this argument tells axum to parse the request body
|
||||||
@ -30,13 +39,14 @@ pub async fn create_user(
|
|||||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||||
ClientIp(ip): ClientIp,
|
ClientIp(ip): ClientIp,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
|
// TODO: return a Result instead
|
||||||
let _ip = match app.rate_limit_by_ip(ip).await {
|
let _ip = match app.rate_limit_by_ip(ip).await {
|
||||||
Ok(x) => match x.try_into_response().await {
|
Ok(x) => match x.try_into_response().await {
|
||||||
Ok(RateLimitResult::AllowedIp(x)) => x,
|
Ok(RateLimitResult::AllowedIp(x)) => x,
|
||||||
Err(err_response) => return err_response,
|
Err(err_response) => return err_response,
|
||||||
_ => unimplemented!(),
|
_ => 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
|
// TODO: check invite_code against the app's config or database
|
||||||
@ -65,7 +75,7 @@ pub async fn create_user(
|
|||||||
// TODO: proper error message
|
// TODO: proper error message
|
||||||
let user = user.insert(db).await.unwrap();
|
let user = user.insert(db).await.unwrap();
|
||||||
|
|
||||||
//
|
// TODO: create
|
||||||
|
|
||||||
// TODO: do not expose user ids
|
// TODO: do not expose user ids
|
||||||
(StatusCode::CREATED, Json(user)).into_response()
|
(StatusCode::CREATED, Json(user)).into_response()
|
||||||
|
@ -193,7 +193,7 @@ impl JsonRpcForwardedResponse {
|
|||||||
id,
|
id,
|
||||||
result: None,
|
result: None,
|
||||||
error: Some(JsonRpcErrorData {
|
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,
|
code: -32099,
|
||||||
// TODO: some errors should be included here. others should not. i think anyhow might not be the right choice
|
// 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(),
|
// message: "internal server error".to_string(),
|
||||||
|
Loading…
Reference in New Issue
Block a user