arcly_http/web/
context.rs1use std::sync::Arc;
5
6use axum::http::{HeaderMap, Method};
7use bytes::Bytes;
8use smallvec::SmallVec;
9use smol_str::SmolStr;
10
11use crate::core::engine::{FrozenDiContainer, RouteSpec};
12use crate::session::Session;
13use crate::web::tenant::TenantConfig;
14
15pub type Claims = serde_json::Map<String, serde_json::Value>;
17
18#[derive(Clone)]
27pub struct RequestContext {
28 method: Method,
29 raw_path: SmolStr,
30 query: SmolStr,
31 params: SmallVec<[(SmolStr, SmolStr); 4]>,
32 headers: HeaderMap,
33 body: Bytes,
34 claims: Option<Arc<Claims>>,
35 session: Option<Arc<Session>>,
36 tenant: Option<std::sync::Arc<TenantConfig>>,
37 trace_id: [u8; 16],
38 span_id: [u8; 8],
39 parent_span_id: [u8; 8],
40 container: &'static FrozenDiContainer,
41 route_pattern: &'static str,
44 route_spec: Option<&'static RouteSpec>,
46 extensions: axum::http::Extensions,
50}
51
52impl RequestContext {
53 #[inline]
54 pub fn method(&self) -> &Method {
55 &self.method
56 }
57 #[inline]
58 pub fn path(&self) -> &str {
59 &self.raw_path
60 }
61
62 #[inline]
63 pub fn query_string(&self) -> Option<&str> {
64 if self.query.is_empty() {
65 None
66 } else {
67 Some(&self.query)
68 }
69 }
70
71 #[inline]
72 pub fn body(&self) -> &Bytes {
73 &self.body
74 }
75 #[inline]
76 pub fn trace_id(&self) -> [u8; 16] {
77 self.trace_id
78 }
79
80 #[inline]
82 pub fn span_id(&self) -> [u8; 8] {
83 self.span_id
84 }
85
86 #[inline]
88 pub fn parent_span_id(&self) -> Option<[u8; 8]> {
89 if self.parent_span_id == [0u8; 8] {
90 None
91 } else {
92 Some(self.parent_span_id)
93 }
94 }
95
96 #[inline]
97 pub fn claims(&self) -> Option<&Claims> {
98 self.claims.as_deref()
99 }
100
101 #[inline]
106 pub fn session(&self) -> Option<&Arc<Session>> {
107 self.session.as_ref()
108 }
109
110 #[inline]
117 pub fn tenant(&self) -> Option<&TenantConfig> {
118 self.tenant.as_deref()
119 }
120
121 #[inline]
122 pub fn header(&self, key: &str) -> Option<&str> {
123 self.headers.get(key).and_then(|v| v.to_str().ok())
124 }
125
126 #[inline]
127 pub fn param(&self, name: &str) -> Option<&str> {
128 self.params
129 .iter()
130 .find(|(k, _)| k == name)
131 .map(|(_, v)| v.as_str())
132 }
133
134 #[inline]
137 pub fn inject<T: Send + Sync + 'static>(&self) -> &'static T {
138 self.container.get::<T>()
139 }
140
141 #[inline]
144 pub fn try_inject<T: Send + Sync + 'static>(&self) -> Option<&'static T> {
145 self.container.try_get::<T>()
146 }
147
148 #[inline]
151 pub fn route(&self) -> &'static str {
152 self.route_pattern
153 }
154
155 #[inline]
157 pub fn route_spec(&self) -> Option<&'static RouteSpec> {
158 self.route_spec
159 }
160
161 pub fn traceparent(&self) -> String {
167 format!(
168 "00-{}-{}-01",
169 hex_encode_16(&self.trace_id),
170 hex_encode_8(&self.span_id)
171 )
172 }
173
174 pub fn trace_id_hex(&self) -> String {
177 hex_encode_16(&self.trace_id)
178 }
179
180 #[doc(hidden)]
182 #[inline]
183 pub(crate) fn __with_claims(mut self, claims: Option<Arc<Claims>>) -> Self {
184 self.claims = claims;
185 self
186 }
187
188 #[doc(hidden)]
190 #[inline]
191 pub(crate) fn __with_session(mut self, session: Option<Arc<Session>>) -> Self {
192 self.session = session;
193 self
194 }
195
196 #[doc(hidden)]
198 #[inline]
199 pub(crate) fn __with_tenant(mut self, tenant: Option<std::sync::Arc<TenantConfig>>) -> Self {
200 self.tenant = tenant;
201 self
202 }
203
204 #[doc(hidden)]
206 #[allow(clippy::too_many_arguments)]
207 pub fn __new(
208 method: Method,
209 raw_path: SmolStr,
210 query: SmolStr,
211 params: SmallVec<[(SmolStr, SmolStr); 4]>,
212 headers: HeaderMap,
213 body: Bytes,
214 trace_id: [u8; 16],
215 span_id: [u8; 8],
216 parent_span_id: [u8; 8],
217 container: &'static FrozenDiContainer,
218 route_pattern: &'static str,
219 route_spec: Option<&'static RouteSpec>,
220 ) -> Self {
221 Self {
222 method,
223 raw_path,
224 query,
225 params,
226 headers,
227 body,
228 claims: None,
229 session: None,
230 tenant: None,
231 trace_id,
232 span_id,
233 parent_span_id,
234 container,
235 route_pattern,
236 route_spec,
237 extensions: axum::http::Extensions::new(),
238 }
239 }
240
241 #[inline]
244 pub fn extensions(&self) -> &axum::http::Extensions {
245 &self.extensions
246 }
247
248 #[inline]
252 pub fn extensions_mut(&mut self) -> &mut axum::http::Extensions {
253 &mut self.extensions
254 }
255}
256
257#[inline]
258pub(crate) fn hex_encode_16(b: &[u8; 16]) -> String {
259 b.iter().map(|x| format!("{x:02x}")).collect()
260}
261
262#[inline]
263pub(crate) fn hex_encode_8(b: &[u8; 8]) -> String {
264 b.iter().map(|x| format!("{x:02x}")).collect()
265}