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}
47
48impl RequestContext {
49 #[inline]
50 pub fn method(&self) -> &Method {
51 &self.method
52 }
53 #[inline]
54 pub fn path(&self) -> &str {
55 &self.raw_path
56 }
57
58 #[inline]
59 pub fn query_string(&self) -> Option<&str> {
60 if self.query.is_empty() {
61 None
62 } else {
63 Some(&self.query)
64 }
65 }
66
67 #[inline]
68 pub fn body(&self) -> &Bytes {
69 &self.body
70 }
71 #[inline]
72 pub fn trace_id(&self) -> [u8; 16] {
73 self.trace_id
74 }
75
76 #[inline]
78 pub fn span_id(&self) -> [u8; 8] {
79 self.span_id
80 }
81
82 #[inline]
84 pub fn parent_span_id(&self) -> Option<[u8; 8]> {
85 if self.parent_span_id == [0u8; 8] {
86 None
87 } else {
88 Some(self.parent_span_id)
89 }
90 }
91
92 #[inline]
93 pub fn claims(&self) -> Option<&Claims> {
94 self.claims.as_deref()
95 }
96
97 #[inline]
102 pub fn session(&self) -> Option<&Arc<Session>> {
103 self.session.as_ref()
104 }
105
106 #[inline]
113 pub fn tenant(&self) -> Option<&TenantConfig> {
114 self.tenant.as_deref()
115 }
116
117 #[inline]
118 pub fn header(&self, key: &str) -> Option<&str> {
119 self.headers.get(key).and_then(|v| v.to_str().ok())
120 }
121
122 #[inline]
123 pub fn param(&self, name: &str) -> Option<&str> {
124 self.params
125 .iter()
126 .find(|(k, _)| k == name)
127 .map(|(_, v)| v.as_str())
128 }
129
130 #[inline]
133 pub fn inject<T: Send + Sync + 'static>(&self) -> &'static T {
134 self.container.get::<T>()
135 }
136
137 #[inline]
140 pub fn try_inject<T: Send + Sync + 'static>(&self) -> Option<&'static T> {
141 self.container.try_get::<T>()
142 }
143
144 #[inline]
147 pub fn route(&self) -> &'static str {
148 self.route_pattern
149 }
150
151 #[inline]
153 pub fn route_spec(&self) -> Option<&'static RouteSpec> {
154 self.route_spec
155 }
156
157 pub fn traceparent(&self) -> String {
163 format!(
164 "00-{}-{}-01",
165 hex_encode_16(&self.trace_id),
166 hex_encode_8(&self.span_id)
167 )
168 }
169
170 pub fn trace_id_hex(&self) -> String {
173 hex_encode_16(&self.trace_id)
174 }
175
176 #[doc(hidden)]
178 #[inline]
179 pub(crate) fn __with_claims(mut self, claims: Option<Arc<Claims>>) -> Self {
180 self.claims = claims;
181 self
182 }
183
184 #[doc(hidden)]
186 #[inline]
187 pub(crate) fn __with_session(mut self, session: Option<Arc<Session>>) -> Self {
188 self.session = session;
189 self
190 }
191
192 #[doc(hidden)]
194 #[inline]
195 pub(crate) fn __with_tenant(mut self, tenant: Option<std::sync::Arc<TenantConfig>>) -> Self {
196 self.tenant = tenant;
197 self
198 }
199
200 #[doc(hidden)]
202 #[allow(clippy::too_many_arguments)]
203 pub fn __new(
204 method: Method,
205 raw_path: SmolStr,
206 query: SmolStr,
207 params: SmallVec<[(SmolStr, SmolStr); 4]>,
208 headers: HeaderMap,
209 body: Bytes,
210 trace_id: [u8; 16],
211 span_id: [u8; 8],
212 parent_span_id: [u8; 8],
213 container: &'static FrozenDiContainer,
214 route_pattern: &'static str,
215 route_spec: Option<&'static RouteSpec>,
216 ) -> Self {
217 Self {
218 method,
219 raw_path,
220 query,
221 params,
222 headers,
223 body,
224 claims: None,
225 session: None,
226 tenant: None,
227 trace_id,
228 span_id,
229 parent_span_id,
230 container,
231 route_pattern,
232 route_spec,
233 }
234 }
235}
236
237#[inline]
238pub(crate) fn hex_encode_16(b: &[u8; 16]) -> String {
239 b.iter().map(|x| format!("{x:02x}")).collect()
240}
241
242#[inline]
243pub(crate) fn hex_encode_8(b: &[u8; 8]) -> String {
244 b.iter().map(|x| format!("{x:02x}")).collect()
245}