1use crate::types::{AuthRequest, HttpMethod, RequestExtensions, RequestMeta};
2
3#[derive(Debug, Clone)]
5pub struct RequestHookContext {
6 pub request: AuthRequest,
8 pub method: HttpMethod,
9 pub path: String,
10 pub url: Option<url::Url>,
12 pub headers: std::collections::HashMap<String, String>,
13 pub query: std::collections::HashMap<String, String>,
14 pub body: Option<Vec<u8>>,
16 pub meta: RequestMeta,
17 pub extensions: RequestExtensions,
19}
20
21impl RequestHookContext {
22 #[must_use]
24 pub fn from_request(request: &AuthRequest) -> Self {
25 Self {
26 request: request.clone(),
27 method: request.method().clone(),
28 path: request.path().to_owned(),
29 url: request.url().cloned(),
30 headers: request.headers.clone(),
31 query: request.query.clone(),
32 body: request.body.clone(),
33 meta: RequestMeta::from_request(request),
34 extensions: request.extensions().clone(),
35 }
36 }
37}
38
39tokio::task_local! {
40 static REQUEST_HOOK_CONTEXT: Option<RequestHookContext>;
41}
42
43pub async fn with_request_hook_context<T>(
45 request: &AuthRequest,
46 future: impl Future<Output = T>,
47) -> T {
48 with_request_hook_context_value(RequestHookContext::from_request(request), future).await
49}
50
51pub async fn with_request_hook_context_value<T>(
53 request_context: RequestHookContext,
54 future: impl Future<Output = T>,
55) -> T {
56 with_optional_request_hook_context(Some(request_context), future).await
57}
58
59pub async fn with_optional_request_hook_context<T>(
61 request_context: Option<RequestHookContext>,
62 future: impl Future<Output = T>,
63) -> T {
64 REQUEST_HOOK_CONTEXT.scope(request_context, future).await
65}
66
67pub fn current_request_hook_context() -> Option<RequestHookContext> {
68 REQUEST_HOOK_CONTEXT.try_with(Clone::clone).ok().flatten()
69}
70
71#[derive(Clone, Debug)]
74pub struct ValidatedRequestBody(pub crate::utils::json::JsValue);
75
76#[derive(Clone, Debug)]
79pub struct TransformedRequestBody(pub crate::utils::json::JsValue);
80
81#[derive(Clone)]
85pub struct CallbackContext {
86 pub request: Option<AuthRequest>,
87 pub request_hook: Option<RequestHookContext>,
88 pub endpoint: Option<crate::endpoint::EndpointCall>,
89 context: std::sync::Arc<dyn std::any::Any + Send + Sync>,
90}
91
92impl CallbackContext {
93 #[must_use]
94 pub fn new<S: crate::AuthSchema>(
95 context: &crate::AuthContext<S>,
96 request: Option<&AuthRequest>,
97 ) -> Self {
98 let endpoint = crate::endpoint::current_endpoint_call_context();
99 let request_hook = current_request_hook_context();
100 Self {
101 request: request
102 .or_else(|| {
103 endpoint
104 .as_ref()
105 .and_then(crate::endpoint::EndpointCall::request)
106 })
107 .or_else(|| request_hook.as_ref().map(|hook| &hook.request))
108 .cloned(),
109 request_hook,
110 endpoint,
111 context: std::sync::Arc::new(context.clone()),
112 }
113 }
114
115 #[must_use]
117 pub fn context<S: crate::AuthSchema>(&self) -> Option<&crate::AuthContext<S>> {
118 self.context.downcast_ref()
119 }
120}