Skip to main content

xyz_rust/
ctx.rs

1// Ctx 是贯穿三个前端的取消信号:Go 侧 context.Context 的 Rust 对应物。
2// 零依赖(Arc<AtomicBool>)——核心不为取消机制引入任何运行时依赖,
3// 各前端用自己的方式接线(tokio signal / ctrlc)。
4
5use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8/// 可克隆的取消上下文。handler 用 `ctx.cancelled()` 做周期检查,
9/// 长任务可在退出前排空。
10#[derive(Clone, Debug, Default)]
11pub struct Ctx {
12    cancelled: Arc<AtomicBool>,
13    /// 逐请求界面语言(spec §11.7):HTTP 前端从 Accept-Language 解析后经
14    /// [`Ctx::with_language`] 派生到请求上下文;其余通道为 None(用进程
15    /// 语言,§15.5)。handler 经 `xyz_rust::language_from_ctx` 读取。
16    language: Option<Arc<str>>,
17}
18
19impl Ctx {
20    /// 新建一个未取消的上下文。
21    pub fn new() -> Self {
22        Ctx::default()
23    }
24
25    /// 报告是否已收到取消(SIGINT/SIGTERM 或显式 cancel)。
26    pub fn cancelled(&self) -> bool {
27        self.cancelled.load(Ordering::Relaxed)
28    }
29
30    /// 发出取消信号(幂等;由信号接线与测试调用)。
31    pub fn cancel(&self) {
32        self.cancelled.store(true, Ordering::Relaxed);
33    }
34
35    /// 返回一个可以在线程/任务间共享的底层句柄(信号线程用)。
36    pub fn raw(&self) -> Arc<AtomicBool> {
37        Arc::clone(&self.cancelled)
38    }
39
40    /// 派生一个携带指定界面语言的上下文(spec §11.7 的逐请求语言载体)。
41    pub fn with_language(&self, lang: &str) -> Ctx {
42        let mut c = self.clone();
43        c.language = Some(Arc::from(lang));
44        c
45    }
46
47    /// 本上下文携带的界面语言;None = 未绑定(用进程语言)。
48    pub fn language(&self) -> Option<&str> {
49        self.language.as_deref()
50    }
51}
52
53#[cfg(feature = "http-stack")]
54impl Ctx {
55    /// 在 tokio 任务里等待取消(HTTP/MCP 模式的优雅关停 select 用)。
56    pub async fn cancelled_async(&self) {
57        let raw = self.raw();
58        tokio::task::yield_now().await;
59        while !raw.load(Ordering::Relaxed) {
60            tokio::time::sleep(std::time::Duration::from_millis(50)).await;
61        }
62    }
63}