actix_cloud/session/
session.rs1use std::{
2 cell::{Ref, RefCell},
3 collections::HashMap,
4 mem,
5 rc::Rc,
6};
7
8use actix_utils::future::{ready, Ready};
9use actix_web::{
10 dev::{Extensions, Payload, ServiceRequest, ServiceResponse},
11 error::Error,
12 FromRequest, HttpMessage, HttpRequest,
13};
14use serde::{de::DeserializeOwned, Serialize};
15
16use crate::Result;
17
18#[derive(Clone)]
28pub struct Session(Rc<RefCell<SessionInner>>);
29
30#[derive(Debug, Clone, Default, PartialEq, Eq)]
32pub enum SessionStatus {
33 Changed,
35
36 Purged,
41
42 Renewed,
47
48 #[default]
50 Unchanged,
51}
52
53#[derive(Default)]
54struct SessionInner {
55 state: HashMap<String, String>,
56 status: SessionStatus,
57}
58
59impl Session {
60 pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
64 if let Some(val_str) = self.0.borrow().state.get(key) {
65 Ok(Some(serde_json::from_str(val_str)?))
66 } else {
67 Ok(None)
68 }
69 }
70
71 pub fn entries(&self) -> Ref<'_, HashMap<String, String>> {
75 Ref::map(self.0.borrow(), |inner| &inner.state)
76 }
77
78 pub fn status(&self) -> SessionStatus {
80 Ref::map(self.0.borrow(), |inner| &inner.status).clone()
81 }
82
83 pub fn insert<T: Serialize>(&self, key: impl Into<String>, value: T) -> Result<()> {
90 let mut inner = self.0.borrow_mut();
91
92 if inner.status != SessionStatus::Purged {
93 if inner.status != SessionStatus::Renewed {
94 inner.status = SessionStatus::Changed;
95 }
96
97 let key = key.into();
98 let val = serde_json::to_string(&value)?;
99
100 inner.state.insert(key, val);
101 }
102
103 Ok(())
104 }
105
106 pub fn remove(&self, key: &str) -> Option<String> {
110 let mut inner = self.0.borrow_mut();
111
112 if inner.status != SessionStatus::Purged {
113 if inner.status != SessionStatus::Renewed {
114 inner.status = SessionStatus::Changed;
115 }
116 return inner.state.remove(key);
117 }
118
119 None
120 }
121
122 pub fn remove_as<T: DeserializeOwned>(&self, key: &str) -> Option<Result<T, String>> {
127 self.remove(key)
128 .map(|val_str| match serde_json::from_str(&val_str) {
129 Ok(val) => Ok(val),
130 Err(_err) => Err(val_str),
131 })
132 }
133
134 pub fn clear(&self) {
136 let mut inner = self.0.borrow_mut();
137
138 if inner.status != SessionStatus::Purged {
139 if inner.status != SessionStatus::Renewed {
140 inner.status = SessionStatus::Changed;
141 }
142 inner.state.clear()
143 }
144 }
145
146 pub fn purge(&self) {
148 let mut inner = self.0.borrow_mut();
149 inner.status = SessionStatus::Purged;
150 inner.state.clear();
151 }
152
153 pub fn renew(&self) {
155 let mut inner = self.0.borrow_mut();
156
157 if inner.status != SessionStatus::Purged {
158 inner.status = SessionStatus::Renewed;
159 }
160 }
161
162 #[allow(clippy::needless_pass_by_ref_mut)]
167 pub(crate) fn set_session(
168 req: &mut ServiceRequest,
169 data: impl IntoIterator<Item = (String, String)>,
170 ) {
171 let session = Session::get_session(&mut req.extensions_mut());
172 let mut inner = session.0.borrow_mut();
173 inner.state.extend(data);
174 }
175
176 #[allow(clippy::needless_pass_by_ref_mut)]
182 pub(crate) fn get_changes<B>(
183 res: &mut ServiceResponse<B>,
184 ) -> (SessionStatus, HashMap<String, String>) {
185 if let Some(s_impl) = res
186 .request()
187 .extensions()
188 .get::<Rc<RefCell<SessionInner>>>()
189 {
190 let state = mem::take(&mut s_impl.borrow_mut().state);
191 (s_impl.borrow().status.clone(), state)
192 } else {
193 (SessionStatus::Unchanged, HashMap::new())
194 }
195 }
196
197 pub(crate) fn get_session(extensions: &mut Extensions) -> Session {
198 if let Some(s_impl) = extensions.get::<Rc<RefCell<SessionInner>>>() {
199 return Session(Rc::clone(s_impl));
200 }
201
202 let inner = Rc::new(RefCell::new(SessionInner::default()));
203 extensions.insert(inner.clone());
204
205 Session(inner)
206 }
207}
208
209impl FromRequest for Session {
211 type Error = Error;
212 type Future = Ready<Result<Session, Error>>;
213
214 #[inline]
215 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
216 ready(Ok(Session::get_session(&mut req.extensions_mut())))
217 }
218}