sz_rust_core/middleware/
request_scope.rs1use axum::http::{Request, Response};
41use axum::response::IntoResponse;
42use std::cell::RefCell;
43use std::future::Future;
44use std::pin::Pin;
45use std::sync::atomic::{AtomicU64, Ordering};
46use std::task::{Context, Poll};
47use tower::Service;
48
49use crate::container::App;
50use crate::container::ScopeId;
51
52thread_local! {
57 static CURRENT_SCOPE_ID: RefCell<ScopeId> = const { RefCell::new(0) };
58}
59
60pub fn current_scope_id() -> Option<ScopeId> {
67 CURRENT_SCOPE_ID.with(|c| {
68 let id = *c.borrow();
69 if id != 0 {
70 Some(id)
71 } else {
72 None
73 }
74 })
75}
76
77static SCOPE_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
79
80fn generate_scope_id() -> ScopeId {
82 SCOPE_ID_COUNTER.fetch_add(1, Ordering::Relaxed)
83}
84
85#[derive(Clone, Default)]
93pub struct RequestScopeLayer;
94
95impl RequestScopeLayer {
96 pub fn new() -> Self {
98 Self
99 }
100}
101
102impl<S> tower::Layer<S> for RequestScopeLayer {
103 type Service = RequestScopeService<S>;
104
105 fn layer(&self, inner: S) -> Self::Service {
106 RequestScopeService { inner }
107 }
108}
109
110#[derive(Clone)]
116pub struct RequestScopeService<S> {
117 inner: S,
118}
119
120impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for RequestScopeService<S>
121where
122 S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
123 S::Future: Send + 'static,
124 ReqBody: Send + 'static,
125 ResBody: axum::body::HttpBody + Send + 'static,
126 ResBody::Data: Send,
127 ResBody::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
128{
129 type Response = Response<ResBody>;
130 type Error = S::Error;
131 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
132
133 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
134 self.inner.poll_ready(cx)
135 }
136
137 fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
138 let scope_id = generate_scope_id();
140
141 CURRENT_SCOPE_ID.with(|c| *c.borrow_mut() = scope_id);
143
144 let future = self.inner.clone().call(req);
146
147 Box::pin(async move {
148 let response = future.await?;
149 CURRENT_SCOPE_ID.with(|c| *c.borrow_mut() = 0);
151 Ok(response)
152 })
153 }
154}
155
156#[cfg(test)]
161mod tests {
162 use super::*;
163 use axum::body::Body;
164 use axum::http::{Method, Request, StatusCode};
165 use http_body_util::BodyExt;
166 use std::sync::Arc;
167 use std::sync::atomic::{AtomicUsize, Ordering};
168 use tower::{Layer, ServiceExt};
169
170 #[derive(Clone)]
172 struct EchoService;
173
174 impl Service<Request<Body>> for EchoService {
175 type Response = Response<Body>;
176 type Error = std::convert::Infallible;
177 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
178
179 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
180 Poll::Ready(Ok(()))
181 }
182
183 fn call(&mut self, _req: Request<Body>) -> Self::Future {
184 Box::pin(async {
185 Ok(Response::builder()
186 .status(StatusCode::OK)
187 .body(Body::from("ok"))
188 .unwrap())
189 })
190 }
191 }
192
193 #[tokio::test]
194 async fn test_p1_arch_di_02_scope_layer_sets_and_clears_scope() {
195 assert!(current_scope_id().is_none(), "请求外 current_scope_id 应为 None");
197
198 let layer = RequestScopeLayer::new();
199 let mut service = layer.layer(EchoService);
200
201 let req = Request::builder()
202 .method(Method::GET)
203 .uri("/")
204 .body(Body::empty())
205 .unwrap();
206 let resp = service.call(req).await.unwrap();
207 assert_eq!(resp.status(), StatusCode::OK);
208
209 assert!(current_scope_id().is_none(), "请求结束后 current_scope_id 应恢复为 None");
211 }
212
213 #[tokio::test]
214 async fn test_p1_arch_di_02_scope_id_unique_per_request() {
215 let layer = RequestScopeLayer::new();
216 let mut service = layer.layer(EchoService);
217
218 let mut seen_ids = Vec::new();
219 for _ in 0..5 {
220 let req = Request::builder().method(Method::GET).uri("/").body(Body::empty()).unwrap();
221 let id1 = generate_scope_id();
224 let id2 = generate_scope_id();
225 assert_ne!(id1, id2, "连续生成的 scope_id 应不同");
226 seen_ids.push(id1);
227 }
228
229 for (i, &id1) in seen_ids.iter().enumerate() {
231 for &id2 in seen_ids.iter().skip(i + 1) {
232 assert_ne!(id1, id2, "scope_id 应全局唯一");
233 }
234 }
235 }
236
237 fn assert_send<T: Send>() {}
239
240 #[test]
241 fn test_p1_arch_di_02_service_is_send() {
242 assert_send::<RequestScopeService<EchoService>>();
243 }
244}