diff --git a/ft-derive/src/lib.rs b/ft-derive/src/lib.rs index d9d48fd..ff91aa5 100644 --- a/ft-derive/src/lib.rs +++ b/ft-derive/src/lib.rs @@ -8,6 +8,14 @@ pub fn processor( handle(item, "processor", "handler") } +#[proc_macro_attribute] +pub fn raw_data( + _attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + handle(item, "data", "raw_bytes_handler") +} + #[proc_macro_attribute] pub fn wrapped_processor( _attr: proc_macro::TokenStream, diff --git a/ft-sdk/src/from_request/headers.rs b/ft-sdk/src/from_request/headers.rs index 7ca68a0..5b7bae6 100644 --- a/ft-sdk/src/from_request/headers.rs +++ b/ft-sdk/src/from_request/headers.rs @@ -3,3 +3,10 @@ impl ft_sdk::FromRequest for http::HeaderMap { Ok(req.headers().clone()) } } + + +impl ft_sdk::FromRawRequest for http::HeaderMap { + fn from_request(req: &http::Request) -> Result { + Ok(req.headers().clone()) + } +} diff --git a/ft-sdk/src/from_request/mod.rs b/ft-sdk/src/from_request/mod.rs index 4b8a5aa..ca7f551 100644 --- a/ft-sdk/src/from_request/mod.rs +++ b/ft-sdk/src/from_request/mod.rs @@ -16,8 +16,11 @@ mod query; #[cfg(feature = "field-extractors")] mod required; pub mod wrapped_processor; +mod text; +pub mod raw_bytes_handler; pub use form::Form; +pub use text::Text; pub use host::Host; pub use mountpoint::Mountpoint; pub use path::Path; @@ -28,6 +31,11 @@ pub trait FromRequest: Sized { fn from_request(req: &http::Request) -> Result; } + +pub trait FromRawRequest: Sized { + fn from_request(req: &http::Request) -> Result; +} + impl FromRequest for chrono::DateTime { fn from_request(_req: &http::Request) -> Result { Ok(ft_sdk::env::now()) @@ -40,6 +48,12 @@ impl FromRequest for ft_sdk::Connection { } } +impl FromRawRequest for ft_sdk::Connection { + fn from_request(_req: &http::Request) -> Result { + Ok(ft_sdk::default_connection()?) + } +} + // TODO: need better name pub trait WrappedFromRequest: FromRequest { fn wrap(self, output: serde_json::Value) -> Result; diff --git a/ft-sdk/src/from_request/raw_bytes_handler.rs b/ft-sdk/src/from_request/raw_bytes_handler.rs new file mode 100644 index 0000000..d909d37 --- /dev/null +++ b/ft-sdk/src/from_request/raw_bytes_handler.rs @@ -0,0 +1,312 @@ + +// https://github.com/alexpusch/rust-magic-patterns/blob/master/axum-style-magic-function-param/Readme.md +// https://joshchoo.com/writing/how-actix-web-app-state-and-data-extractor-works +pub fn handle, ft_sdk::Error>>, H: RawHandler>( + h: H, +) { + let req = ft_sys::http::current_request(); + let resp = h.call(&req).and_then(Into::into).unwrap_or_else(|e| { + ft_sdk::println!("Error: {:?}", e); + ft_sdk::error::handle_error(e) + }); + ft_sdk::http::send_response(resp); +} + +pub trait RawHandler: Sized { + fn call(self, req: &http::Request) -> Result; +} + +impl RawHandler<(), O> for F +where + F: Fn() -> Result, +{ + fn call(self, _req: &http::Request) -> Result { + (self)() + } +} + +impl RawHandler for F +where + F: Fn(T) -> Result, + T: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + (self)(T::from_request(req)?) + } +} + +impl RawHandler<(T1, T2), O> for F +where + F: Fn(T1, T2) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)(T1::from_request(req)?, T2::from_request(req)?) + } +} + +impl RawHandler<(T1, T2, T3), O> for F +where + F: Fn(T1, T2, T3) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4), O> for F +where + F: Fn(T1, T2, T3, T4) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4, T5), O> for F +where + F: Fn(T1, T2, T3, T4, T5) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4, T5, T6), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4, T5, T6, T7), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4, T5, T6, T7, T8), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7, T8) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, + T8: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + T8::from_request(req)?, + ) + } +} + +impl RawHandler<(T1, T2, T3, T4, T5, T6, T7, T8, T9), O> + for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, + T8: ft_sdk::FromRawRequest, + T9: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + T8::from_request(req)?, + T9::from_request(req)?, + ) + } +} + +impl + RawHandler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, + T8: ft_sdk::FromRawRequest, + T9: ft_sdk::FromRawRequest, + T10: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + T8::from_request(req)?, + T9::from_request(req)?, + T10::from_request(req)?, + ) + } +} + +impl + RawHandler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, + T8: ft_sdk::FromRawRequest, + T9: ft_sdk::FromRawRequest, + T10: ft_sdk::FromRawRequest, + T11: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + T8::from_request(req)?, + T9::from_request(req)?, + T10::from_request(req)?, + T11::from_request(req)?, + ) + } +} + +impl + RawHandler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12), O> for F +where + F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) -> Result, + T1: ft_sdk::FromRawRequest, + T2: ft_sdk::FromRawRequest, + T3: ft_sdk::FromRawRequest, + T4: ft_sdk::FromRawRequest, + T5: ft_sdk::FromRawRequest, + T6: ft_sdk::FromRawRequest, + T7: ft_sdk::FromRawRequest, + T8: ft_sdk::FromRawRequest, + T9: ft_sdk::FromRawRequest, + T10: ft_sdk::FromRawRequest, + T11: ft_sdk::FromRawRequest, + T12: ft_sdk::FromRawRequest, +{ + fn call(self, req: &http::Request) -> Result { + // TODO: try to parse both t1 and t2 and return result for both together to clients + (self)( + T1::from_request(req)?, + T2::from_request(req)?, + T3::from_request(req)?, + T4::from_request(req)?, + T5::from_request(req)?, + T6::from_request(req)?, + T7::from_request(req)?, + T8::from_request(req)?, + T9::from_request(req)?, + T10::from_request(req)?, + T11::from_request(req)?, + T12::from_request(req)?, + ) + } +} diff --git a/ft-sdk/src/from_request/text.rs b/ft-sdk/src/from_request/text.rs new file mode 100644 index 0000000..6a989c2 --- /dev/null +++ b/ft-sdk/src/from_request/text.rs @@ -0,0 +1,7 @@ +pub struct Text(pub String); + +impl ft_sdk::FromRawRequest for Text { + fn from_request(req: &http::Request) -> Result { + Ok(Text(String::from_utf8(req.body().as_ref().to_vec())?)) + } +} diff --git a/ft-sdk/src/lib.rs b/ft-sdk/src/lib.rs index 83bf571..6fa5fa3 100644 --- a/ft-sdk/src/lib.rs +++ b/ft-sdk/src/lib.rs @@ -30,8 +30,8 @@ pub use email::{send_email, EmailError}; pub use error::{not_found_, server_error_, single_error, unauthorised_, SpecialError}; #[cfg(feature = "field-extractors")] pub use from_request::{Cookie, Hidden, Optional, Query, Required}; -pub use from_request::{Form, FromRequest, Host, Mountpoint, Path, WrappedFromRequest}; -pub use ft_derive::{data, form, processor, wrapped_processor}; +pub use from_request::{Form, Text, FromRequest, FromRawRequest, Host, Mountpoint, Path, WrappedFromRequest}; +pub use ft_derive::{data, form, processor, wrapped_processor, raw_data}; #[cfg(feature = "postgres")] pub use ft_sys::PgConnection; #[cfg(feature = "sqlite")]