Skip to content

Commit

Permalink
ugly hack: temporarily force JSON decoding (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
m1guelpf authored Nov 15, 2023
1 parent 3217997 commit 39a6139
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 5 deletions.
27 changes: 25 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ redis = { version = "0.23.0", features = ["tokio-comp", "connection-manager"] }
tracing-subscriber = { version = "0.3", default-features = false, features = [
"fmt",
] }
serde_path_to_error = "0.1.14"
async-trait = "0.1.74"
thiserror = "1.0.50"

[build-dependencies]
chrono = "0.4.26"
62 changes: 62 additions & 0 deletions src/axum/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::time::SystemTime;

use async_trait::async_trait;
use axum::{
body::{Bytes, HttpBody},
extract::FromRequest,
http::Request,
response::IntoResponse,
BoxError,
};
use serde::de::DeserializeOwned;

#[derive(Debug, thiserror::Error)]
pub enum JsonError {
#[error("failed to deserialize json")]
Deserialize(#[from] serde_path_to_error::Error<serde_json::Error>),

#[error("failed to extract body")]
Body(#[from] axum::extract::rejection::BytesRejection),
}

impl IntoResponse for JsonError {
fn into_response(self) -> axum::response::Response {
unimplemented!()
}
}

#[derive(Debug, Clone, Copy, Default)]
#[must_use]
pub struct TemporaryForceDecodeJson<T>(pub T);

#[async_trait]
impl<T, S, B> FromRequest<S, B> for TemporaryForceDecodeJson<T>
where
T: DeserializeOwned,
B: HttpBody + Send + 'static,
B::Data: Send,
B::Error: Into<BoxError>,
S: Send + Sync,
{
type Rejection = JsonError;

async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
assert!(
!is_after_nov_30(),
"This was supposed to be a very temporary hack you fools!!!! Time to use proper JSON headers."
);

let bytes = Bytes::from_request(req, state).await?;
let deserializer = &mut serde_json::Deserializer::from_slice(&bytes);

Ok(Self(serde_path_to_error::deserialize(deserializer)?))
}
}

fn is_after_nov_30() -> bool {
SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
> 1_701_331_200
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use dotenvy::dotenv;
use redis::aio::ConnectionManager;
use std::env;

mod axum;
mod routes;
mod server;
mod utils;
Expand Down
9 changes: 6 additions & 3 deletions src/routes/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ use std::str;
use tower_http::cors::{AllowHeaders, Any, CorsLayer};
use uuid::Uuid;

use crate::utils::{
handle_redis_error, RequestPayload, RequestStatus, EXPIRE_AFTER_SECONDS, REQ_STATUS_PREFIX,
use crate::{
axum::TemporaryForceDecodeJson,
utils::{
handle_redis_error, RequestPayload, RequestStatus, EXPIRE_AFTER_SECONDS, REQ_STATUS_PREFIX,
},
};

const RES_PREFIX: &str = "res:";
Expand Down Expand Up @@ -81,7 +84,7 @@ async fn get_response(
async fn insert_response(
Path(request_id): Path<Uuid>,
Extension(mut redis): Extension<ConnectionManager>,
Json(request): Json<RequestPayload>,
TemporaryForceDecodeJson(request): TemporaryForceDecodeJson<RequestPayload>,
) -> Result<StatusCode, StatusCode> {
//ANCHOR - Store the response
if !redis
Expand Down

0 comments on commit 39a6139

Please sign in to comment.