finchers_session/
in_memory.rs1extern crate cookie;
33
34use std::collections::HashMap;
35use std::sync::{Arc, RwLock};
36
37use finchers;
38use finchers::endpoint::{ApplyContext, ApplyResult, Endpoint};
39use finchers::error::Error;
40use finchers::input::Input;
41
42use self::cookie::Cookie;
43use futures::future;
44use uuid::Uuid;
45
46use session::{RawSession, Session};
47
48#[derive(Debug, Default)]
49struct Storage {
50 inner: RwLock<HashMap<Uuid, String>>,
51}
52
53impl Storage {
54 fn get(&self, session_id: &Uuid) -> Result<Option<String>, Error> {
55 let inner = self.inner.read().map_err(|e| format_err!("{}", e))?;
56 Ok(inner.get(&session_id).cloned())
57 }
58
59 fn set(&self, session_id: Uuid, value: String) -> Result<(), Error> {
60 let mut inner = self.inner.write().map_err(|e| format_err!("{}", e))?;
61 inner.insert(session_id, value);
62 Ok(())
63 }
64
65 fn remove(&self, session_id: &Uuid) -> Result<(), Error> {
66 let mut inner = self.inner.write().map_err(|e| format_err!("{}", e))?;
67 inner.remove(&session_id);
68 Ok(())
69 }
70}
71
72#[allow(missing_docs)]
73#[derive(Debug, Clone, Default)]
74pub struct InMemoryBackend {
75 inner: Arc<Inner>,
76}
77
78#[derive(Debug, Default)]
79struct Inner {
80 storage: Storage,
81}
82
83impl InMemoryBackend {
84 fn read_value(&self, input: &mut Input) -> Result<(Option<String>, Option<Uuid>), Error> {
85 match input.cookies()?.get("session-id") {
86 Some(cookie) => {
87 let session_id: Uuid = cookie
88 .value()
89 .parse()
90 .map_err(finchers::error::bad_request)?;
91 let value = self.inner.storage.get(&session_id)?;
92 Ok((value, Some(session_id)))
93 }
94 None => Ok((None, None)),
95 }
96 }
97
98 fn write_value(&self, input: &mut Input, session_id: Uuid, value: String) -> Result<(), Error> {
99 self.inner.storage.set(session_id.clone(), value)?;
100 input
101 .cookies()?
102 .add(Cookie::new("session-id", session_id.to_string()));
103 Ok(())
104 }
105
106 fn remove_value(&self, input: &mut Input, session_id: Uuid) -> Result<(), Error> {
107 self.inner.storage.remove(&session_id)?;
108 input.cookies()?.remove(Cookie::named("session-id"));
109 Ok(())
110 }
111}
112
113impl<'a> Endpoint<'a> for InMemoryBackend {
114 type Output = (Session<InMemorySession>,);
115 type Future = future::FutureResult<Self::Output, Error>;
116
117 fn apply(&self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
118 Ok(future::result(self.read_value(cx.input()).map(
119 |(value, session_id)| {
120 (Session::new(InMemorySession {
121 backend: self.clone(),
122 value,
123 session_id,
124 }),)
125 },
126 )))
127 }
128}
129
130#[allow(missing_docs)]
131#[derive(Debug)]
132pub struct InMemorySession {
133 backend: InMemoryBackend,
134 session_id: Option<Uuid>,
135 value: Option<String>,
136}
137
138impl InMemorySession {
139 fn write_impl(self, input: &mut Input) -> Result<(), Error> {
140 match self.value {
141 Some(value) => {
142 let session_id = self.session_id.unwrap_or_else(Uuid::new_v4);
143 self.backend.write_value(input, session_id, value)
144 }
145 None => match self.session_id {
146 Some(session_id) => self.backend.remove_value(input, session_id),
147 None => Ok(()),
148 },
149 }
150 }
151}
152
153impl RawSession for InMemorySession {
154 type WriteFuture = future::FutureResult<(), Error>;
155
156 fn get(&self) -> Option<&str> {
157 self.value.as_ref().map(|s| s.as_ref())
158 }
159
160 fn set(&mut self, value: String) {
161 self.value = Some(value);
162 }
163
164 fn remove(&mut self) {
165 self.value = None;
166 }
167
168 fn write(self, input: &mut Input) -> Self::WriteFuture {
169 future::result(self.write_impl(input))
170 }
171}