1use async_trait::async_trait;
6
7use crate::error::SaTokenResult;
8
9#[async_trait]
12pub trait SloNotifier: Send + Sync {
13 async fn notify_logout(&self, logout_url: &str, login_id: &str) -> SaTokenResult<()>;
16}
17
18pub struct NoopSloNotifier;
21
22#[async_trait]
23impl SloNotifier for NoopSloNotifier {
24 async fn notify_logout(&self, _logout_url: &str, _login_id: &str) -> SaTokenResult<()> {
25 Ok(())
26 }
27}
28
29impl std::fmt::Debug for NoopSloNotifier {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.write_str("NoopSloNotifier { .. }")
32 }
33}
34
35#[cfg(feature = "sso-http")]
38pub struct HttpSloNotifier {
39 client: reqwest::Client,
40}
41
42#[cfg(feature = "sso-http")]
43impl HttpSloNotifier {
44 pub fn new() -> Self {
47 Self {
48 client: reqwest::Client::new(),
49 }
50 }
51}
52
53#[cfg(feature = "sso-http")]
54impl Default for HttpSloNotifier {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60#[cfg(feature = "sso-http")]
61#[async_trait]
62impl SloNotifier for HttpSloNotifier {
63 async fn notify_logout(&self, logout_url: &str, login_id: &str) -> SaTokenResult<()> {
64 let resp = self
65 .client
66 .post(logout_url)
67 .form(&[("loginId", login_id)])
68 .send()
69 .await
70 .map_err(|e| {
71 crate::error::SaTokenError::StorageError(format!("SLO notify failed: {e}"))
72 })?;
73 if resp.status().is_success() {
74 Ok(())
75 } else {
76 Err(crate::error::SaTokenError::StorageError(format!(
77 "SLO notify HTTP {}",
78 resp.status()
79 )))
80 }
81 }
82}