use std::time::Duration;
use crate::error::{SaTokenError, SaTokenResult};
use crate::manager::SaTokenManager;
use crate::token::TokenValue;
pub const DEFAULT_SAFE_SERVICE: &str = "";
pub const SAFE_AUTH_VALUE: &str = "ok";
impl SaTokenManager {
fn safe_key(&self, token: &str, service: &str) -> String {
self.config.make_key("safe:", &format!("{}:{}", token, service))
}
pub async fn open_safe(
&self,
token: &TokenValue,
service: &str,
safe_time: i64,
) -> SaTokenResult<()> {
if safe_time < 0 {
return Err(SaTokenError::ConfigError(
"safe_time must be >= 0".to_string(),
));
}
let ttl = if safe_time == 0 {
None
} else {
Some(Duration::from_secs(safe_time as u64))
};
self.storage
.set(
&self.safe_key(token.as_str(), service),
SAFE_AUTH_VALUE,
ttl,
)
.await
.map_err(|e| SaTokenError::StorageError(e.to_string()))?;
self.event_bus
.publish(crate::event::SaTokenEvent::open_safe(token.as_str(), service))
.await;
Ok(())
}
pub async fn is_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<bool> {
if token.as_str().is_empty() {
return Ok(false);
}
if !self.is_valid(token).await {
return Ok(false);
}
let value = self
.storage
.get(&self.safe_key(token.as_str(), service))
.await
.map_err(|e| SaTokenError::StorageError(e.to_string()))?;
Ok(value.is_some())
}
pub async fn check_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
if !self.is_valid(token).await {
return Err(SaTokenError::NotLogin);
}
if !self.is_safe(token, service).await? {
return Err(SaTokenError::NotSafe(service.to_string()));
}
Ok(())
}
pub async fn close_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
self.storage
.delete(&self.safe_key(token.as_str(), service))
.await
.map_err(|e| SaTokenError::StorageError(e.to_string()))?;
self.event_bus
.publish(crate::event::SaTokenEvent::close_safe(token.as_str(), service))
.await;
Ok(())
}
pub async fn get_safe_time(
&self,
token: &TokenValue,
service: &str,
) -> SaTokenResult<Option<i64>> {
match self.storage.ttl(&self.safe_key(token.as_str(), service)).await {
Ok(Some(d)) => Ok(Some(d.as_secs() as i64)),
Ok(None) => Ok(None),
Err(e) => Err(SaTokenError::StorageError(e.to_string())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::SaTokenConfig;
use sa_token_storage_memory::MemoryStorage;
use std::sync::Arc;
fn manager() -> SaTokenManager {
SaTokenManager::new(
Arc::new(MemoryStorage::new()),
SaTokenConfig::default(),
)
}
#[tokio::test]
async fn open_check_close_safe() {
let mgr = manager();
let token = mgr.login("u1").await.unwrap();
assert!(!mgr.is_safe(&token, DEFAULT_SAFE_SERVICE).await.unwrap());
mgr.open_safe(&token, "pay", 120).await.unwrap();
assert!(mgr.is_safe(&token, "pay").await.unwrap());
mgr.check_safe(&token, "pay").await.unwrap();
mgr.close_safe(&token, "pay").await.unwrap();
assert!(!mgr.is_safe(&token, "pay").await.unwrap());
}
}