sa_token_core/context/mod.rs
1// Author: 金书记
2//
3//! 上下文模块 - 用于在请求处理过程中传递 token 信息
4//!
5//! - **`tokio::task_local!`**:跨 `await`、跨 Tokio worker 线程仍与同一异步任务绑定(推荐)。
6//! - **`thread_local`**:兼容旧代码与同步路径([`SaTokenContext::set_current`] / [`SaTokenContext::clear`])。
7//!
8//! Context module — carries token info during a request.
9//! **`tokio::task_local!`**: stays bound to the same logical async task across awaits/workers (preferred).
10//! **`thread_local`**: backward-compatible synchronous path (`set_current` / `clear`).
11
12use std::cell::RefCell;
13use std::future::Future;
14use std::sync::Arc;
15
16use crate::token::{TokenInfo, TokenValue};
17
18thread_local! {
19 static TLS_CTX: RefCell<Option<SaTokenContext>> = const { RefCell::new(None) };
20}
21
22tokio::task_local! {
23 static TASK_CTX: SaTokenContext;
24}
25
26/// sa-token 上下文 | sa-token Context
27///
28/// # 字段说明 | Field Description
29/// - `token`: 当前请求的 token | Current request's token
30/// - `token_info`: Token 详细信息 | Token detailed information
31/// - `login_id`: 登录用户 ID | Logged-in user ID
32#[derive(Debug, Clone)]
33pub struct SaTokenContext {
34 /// 当前请求的 token | Current request's token
35 pub token: Option<TokenValue>,
36
37 /// 当前请求的 token 信息 | Current request's token info
38 pub token_info: Option<Arc<TokenInfo>>,
39
40 /// 登录 ID | Login ID
41 pub login_id: Option<String>,
42}
43
44impl SaTokenContext {
45 pub fn new() -> Self {
46 Self {
47 token: None,
48 token_info: None,
49 login_id: None,
50 }
51 }
52
53 /// Bind `ctx` for the whole lifetime of `fut` (await-safe across worker threads).
54 /// 在 `fut` 全生命周期内绑定 `ctx`(跨 await / 跨 worker 仍有效)。
55 pub async fn scope<F, R>(ctx: SaTokenContext, fut: F) -> R
56 where
57 F: Future<Output = R>,
58 {
59 TASK_CTX.scope(ctx, fut).await
60 }
61
62 /// Clone of current context: **task-local first**, then thread-local fallback.
63 /// 当前上下文副本:**优先 task-local**,再回落 thread-local。
64 pub fn try_current() -> Option<SaTokenContext> {
65 match TASK_CTX.try_with(|c| c.clone()) {
66 Ok(c) => Some(c),
67 Err(_) => TLS_CTX.with(|c| c.borrow().clone()),
68 }
69 }
70
71 /// 设置当前上下文(thread-local 兼容路径)| Set current context (thread-local compat)
72 pub fn set_current(ctx: SaTokenContext) {
73 TLS_CTX.with(|c| {
74 *c.borrow_mut() = Some(ctx);
75 });
76 }
77
78 /// 获取当前上下文 | Get current context
79 pub fn get_current() -> Option<SaTokenContext> {
80 Self::try_current()
81 }
82
83 /// 清除当前上下文(thread-local 兼容路径)| Clear current context (thread-local compat)
84 pub fn clear() {
85 TLS_CTX.with(|c| {
86 *c.borrow_mut() = None;
87 });
88 }
89}
90
91impl Default for SaTokenContext {
92 fn default() -> Self {
93 Self::new()
94 }
95}