From c00e3fb55994001eaa9dcc5fdeb5ea66d798158d Mon Sep 17 00:00:00 2001 From: Chrislearn Young Date: Fri, 2 Jan 2026 18:37:23 +0800 Subject: [PATCH 1/5] w --- Cargo.toml | 32 +++---- README.md | 49 ++--------- src/cookie_store.rs | 6 +- src/lib.rs | 5 +- src/memory_store.rs | 18 ++-- src/session.rs | 200 ++++++++++++++++++++++++++------------------ tests/test.rs | 1 - 7 files changed, 155 insertions(+), 156 deletions(-) delete mode 100644 tests/test.rs diff --git a/Cargo.toml b/Cargo.toml index 7e9442a..8365fde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,31 +1,32 @@ [package] -name = "async-session" +name = "saysion" version = "3.0.0" license = "MIT OR Apache-2.0" -repository = "https://github.com/http-rs/async-session" -documentation = "https://docs.rs/async-session" +repository = "https://github.com/salvo-rs/saysion" +documentation = "https://docs.rs/saysion" description = "Async session support with pluggable stores" readme = "README.md" -edition = "2021" +edition = "2024" +rust-version = "1.89" keywords = [] categories = [] authors = [ "Yoshua Wuyts ", - "Jacob Rothstein " + "Jacob Rothstein ", ] [dependencies] async-trait = "0.1.59" -rand = "0.8.5" -base64 = "0.20.0" -sha2 = "0.10.6" +rand = "0.9.2" +base64 = "0.22.1" +sha2 = "0.10.9" hmac = "0.12.1" serde_json = "1.0.89" -bincode = "1.3.3" -anyhow = "1.0.66" -blake3 = "1.3.3" -async-lock = "2.6.0" -log = "0.4.17" +postcard = { version = "1.1.3", default-features = false, features = ["use-std"] } +anyhow = "1.0.100" +blake3 = "1.8.2" +async-lock = "3.4.2" +tracing = "0.1.44" [dependencies.serde] version = "1.0.150" @@ -35,6 +36,5 @@ features = ["rc", "derive"] version = "0.3.17" features = ["serde"] -[dev-dependencies.async-std] -version = "1.12.0" -features = ["attributes"] +[dev-dependencies] +tokio = { version = "1.36.0", features = ["macros"] } \ No newline at end of file diff --git a/README.md b/README.md index 50bad23..6c023fe 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,30 @@ -

async-session

+

saysion

- Async session support with pluggable middleware + Session support with pluggable middleware

-
- - - Crates.io version - - - - Download - - - - docs.rs docs - -
-

- + API Docs | - + Releases | - + Contributing

-## Available session stores - -* [async-sqlx-session](https://crates.io/crates/async-sqlx-session) postgres, mysql & sqlite -* [async-redis-session](https://crates.io/crates/async-redis-session) -* [async-mongodb-session](https://crates.io/crates/async-mongodb-session) -* [async-session-r2d2](https://crates.io/crates/async-session-r2d2) - sqlite only -## Framework implementations - -* [`tide::sessions`](https://docs.rs/tide/latest/tide/sessions/index.html) -* [warp-sessions](https://docs.rs/warp-sessions/latest/warp_sessions/) -* [trillium-sessions](https://docs.trillium.rs/trillium_sessions) -* [axum-sessions](https://docs.rs/axum_sessions) -* [salvo-sessions](https://docs.rs/salvo_extra/latest/salvo_extra/session/index.html) +*Fork from: https://github.com/http-rs/async-session* ## Safety This crate uses ``#![deny(unsafe_code)]`` to ensure everything is implemented in @@ -64,13 +34,6 @@ This crate uses ``#![deny(unsafe_code)]`` to ensure everything is implemented in Want to join us? Check out our ["Contributing" guide][contributing] and take a look at some of these issues: -- [Issues labeled "good first issue"][good-first-issue] -- [Issues labeled "help wanted"][help-wanted] - -[contributing]: https://github.com/http-rs/async-session/blob/main/.github/CONTRIBUTING.md -[good-first-issue]: https://github.com/http-rs/async-session/labels/good%20first%20issue -[help-wanted]: https://github.com/http-rs/async-session/labels/help%20wanted - ## Acknowledgements This work is based on the work initiated by diff --git a/src/cookie_store.rs b/src/cookie_store.rs index ff6eaa5..31b95e3 100644 --- a/src/cookie_store.rs +++ b/src/cookie_store.rs @@ -1,4 +1,4 @@ -use crate::{async_trait, Result, Session, SessionStore}; +use crate::{Result, Session, SessionStore, async_trait}; /// A session store that serializes the entire session into a Cookie. /// @@ -33,12 +33,12 @@ impl CookieStore { impl SessionStore for CookieStore { async fn load_session(&self, cookie_value: String) -> Result> { let serialized = base64::decode(cookie_value)?; - let session: Session = bincode::deserialize(&serialized)?; + let session: Session = postcard::from_bytes(&serialized)?; Ok(session.validate()) } async fn store_session(&self, session: Session) -> Result> { - let serialized = bincode::serialize(&session)?; + let serialized = postcard::to_stdvec(&session)?; Ok(Some(base64::encode(serialized))) } diff --git a/src/lib.rs b/src/lib.rs index 4c1d222..7904af9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,9 @@ //! # Example //! //! ``` -//! use async_session::{Session, SessionStore, MemoryStore}; +//! use saysion::{Session, SessionStore, MemoryStore}; //! -//! # fn main() -> async_session::Result { +//! # fn main() -> saysion::Result { //! # async_std::task::block_on(async { //! # //! // Init a new session store we can persist sessions to. @@ -64,7 +64,6 @@ pub use async_trait::async_trait; pub use base64; pub use blake3; pub use hmac; -pub use log; pub use serde; pub use serde_json; pub use sha2; diff --git a/src/memory_store.rs b/src/memory_store.rs index ce5fd10..56c49b2 100644 --- a/src/memory_store.rs +++ b/src/memory_store.rs @@ -1,4 +1,4 @@ -use crate::{async_trait, log, Result, Session, SessionStore}; +use crate::{Result, Session, SessionStore, async_trait}; use async_lock::RwLock; use std::{collections::HashMap, sync::Arc}; @@ -35,7 +35,7 @@ pub struct MemoryStore { impl SessionStore for MemoryStore { async fn load_session(&self, cookie_value: String) -> Result> { let id = Session::id_from_cookie_value(&cookie_value)?; - log::trace!("loading session by id `{}`", id); + tracing::debug!("loading session by id `{}`", id); Ok(self .inner .read() @@ -46,7 +46,7 @@ impl SessionStore for MemoryStore { } async fn store_session(&self, session: Session) -> Result> { - log::trace!("storing session by id `{}`", session.id()); + tracing::debug!("storing session by id `{}`", session.id()); self.inner .write() .await @@ -57,13 +57,13 @@ impl SessionStore for MemoryStore { } async fn destroy_session(&self, session: Session) -> Result { - log::trace!("destroying session by id `{}`", session.id()); + tracing::debug!("destroying session by id `{}`", session.id()); self.inner.write().await.remove(session.id()); Ok(()) } async fn clear_store(&self) -> Result { - log::trace!("clearing memory store"); + tracing::debug!("clearing memory store"); self.inner.write().await.clear(); Ok(()) } @@ -79,7 +79,7 @@ impl MemoryStore { /// intermittent basis if this store is run for long enough that /// memory accumulation is a concern pub async fn cleanup(&self) -> Result { - log::trace!("cleaning up memory store..."); + tracing::debug!("cleaning up memory store..."); let ids_to_delete: Vec<_> = self .inner .read() @@ -94,7 +94,7 @@ impl MemoryStore { }) .collect(); - log::trace!("found {} expired sessions", ids_to_delete.len()); + tracing::debug!("found {} expired sessions", ids_to_delete.len()); for id in ids_to_delete { self.inner.write().await.remove(&id); } @@ -104,8 +104,8 @@ impl MemoryStore { /// returns the number of elements in the memory store /// # Example /// ```rust - /// # use async_session::{MemoryStore, Session, SessionStore}; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::{MemoryStore, Session, SessionStore}; + /// # fn main() -> saysion::Result { async_std::task::block_on(async { /// let mut store = MemoryStore::new(); /// assert_eq!(store.count().await, 0); /// store.store_session(Session::new()).await?; diff --git a/src/session.rs b/src/session.rs index df4ba3d..75d6b61 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,13 +1,14 @@ -use rand::RngCore; -use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, convert::TryFrom, sync::{ - atomic::{AtomicBool, Ordering}, Arc, RwLock, + atomic::{AtomicBool, Ordering}, }, }; + +use rand::RngCore; +use serde::{Deserialize, Serialize}; use time::OffsetDateTime as DateTime; /// # The main session type. @@ -27,8 +28,8 @@ use time::OffsetDateTime as DateTime; /// /// ### Change tracking example /// ```rust -/// # use async_session::Session; -/// # fn main() -> async_session::Result { async_std::task::block_on(async { +/// # use saysion::Session; +/// # fn main() -> saysion::Result { async_std::task::block_on(async { /// let mut session = Session::new(); /// assert!(!session.data_changed()); /// @@ -54,7 +55,7 @@ use time::OffsetDateTime as DateTime; /// assert!(session.data_changed()); /// # Ok(()) }) } /// ``` -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct Session { id: String, expiry: Option, @@ -101,12 +102,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let session = Session::new(); /// assert_eq!(None, session.expiry()); /// assert!(session.into_cookie_value().is_some()); - /// # Ok(()) }) } + /// # Ok(()) + /// # } + /// ``` pub fn new() -> Self { let cookie_value = generate_cookie(64); let id = Session::id_from_cookie_value(&cookie_value).unwrap(); @@ -129,13 +133,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let session = Session::new(); /// let id = session.id().to_string(); /// let cookie_value = session.into_cookie_value().unwrap(); /// assert_eq!(id, Session::id_from_cookie_value(&cookie_value)?); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn id_from_cookie_value(string: &str) -> Result { let decoded = base64::decode(string)?; @@ -149,13 +155,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(!session.is_destroyed()); /// session.destroy(); /// assert!(session.is_destroyed()); - /// # Ok(()) }) } + /// # Ok(()) } + /// ``` pub fn destroy(&mut self) { self.destroy.store(true, Ordering::SeqCst); } @@ -165,14 +173,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(!session.is_destroyed()); /// session.destroy(); /// assert!(session.is_destroyed()); - /// # Ok(()) }) } - + /// # Ok(()) } + /// ``` pub fn is_destroyed(&self) -> bool { self.destroy.load(Ordering::SeqCst) } @@ -182,13 +191,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let session = Session::new(); /// let id = session.id().to_owned(); /// let cookie_value = session.into_cookie_value().unwrap(); /// assert_eq!(id, Session::id_from_cookie_value(&cookie_value)?); - /// # Ok(()) }) } + /// # Ok(()) } + /// ``` pub fn id(&self) -> &str { &self.id } @@ -200,15 +211,17 @@ impl Session { /// /// ```rust /// # use serde::{Serialize, Deserialize}; - /// # use async_session::Session; + /// # use saysion::Session; /// #[derive(Serialize, Deserialize)] /// struct User { /// name: String, /// legs: u8 /// } + /// # fn main() { /// let mut session = Session::new(); /// session.insert("user", User { name: "chashu".into(), legs: 4 }).expect("serializable"); /// assert_eq!(r#"{"name":"chashu","legs":4}"#, session.get_raw("user").unwrap()); + /// # } /// ``` pub fn insert(&mut self, key: &str, value: impl Serialize) -> Result<(), serde_json::Error> { self.insert_raw(key, serde_json::to_string(&value)?); @@ -220,11 +233,13 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() { /// let mut session = Session::new(); /// session.insert_raw("ten", "10".to_string()); /// let ten: usize = session.get("ten").unwrap(); /// assert_eq!(ten, 10); + /// # } /// ``` pub fn insert_raw(&mut self, key: &str, value: String) { let mut data = self.data.write().unwrap(); @@ -239,11 +254,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); - /// session.insert("key", vec![1, 2, 3]); + /// session.insert("key", vec![1, 2, 3])?; /// let numbers: Vec = session.get("key").unwrap(); /// assert_eq!(vec![1, 2, 3], numbers); + /// # Ok(()) + /// # } /// ``` pub fn get(&self, key: &str) -> Option { let data = self.data.read().unwrap(); @@ -256,10 +274,13 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); - /// session.insert("key", vec![1, 2, 3]); + /// session.insert("key", vec![1, 2, 3])?; /// assert_eq!("[1,2,3]", session.get_raw("key").unwrap()); + /// # Ok(()) + /// # } /// ``` pub fn get_raw(&self, key: &str) -> Option { let data = self.data.read().unwrap(); @@ -271,12 +292,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); - /// session.insert("key", "value"); + /// session.insert("key", "value")?; /// session.remove("key"); /// assert!(session.get_raw("key").is_none()); /// assert_eq!(session.len(), 0); + /// # Ok(()) + /// # } /// ``` pub fn remove(&mut self, key: &str) { let mut data = self.data.write().unwrap(); @@ -290,11 +314,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert_eq!(session.len(), 0); - /// session.insert("key", 0); + /// session.insert("key", 0)?; /// assert_eq!(session.len(), 1); + /// # Ok(()) + /// # } /// ``` pub fn len(&self) -> usize { self.data.read().unwrap().len() @@ -305,11 +332,15 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(session.is_empty()); - /// session.insert("key", 0); + /// session.insert("key", 0)?; /// assert!(!session.is_empty()); + /// # Ok(()) + /// # } + /// ``` pub fn is_empty(&self) -> bool { return self.data.read().unwrap().is_empty(); } @@ -319,8 +350,9 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// let old_id = session.id().to_string(); /// session.regenerate(); @@ -328,7 +360,8 @@ impl Session { /// let new_id = session.id().to_string(); /// let cookie_value = session.into_cookie_value().unwrap(); /// assert_eq!(new_id, Session::id_from_cookie_value(&cookie_value)?); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn regenerate(&mut self) { let cookie_value = generate_cookie(64); @@ -344,13 +377,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// session.set_cookie_value("hello".to_owned()); /// let cookie_value = session.into_cookie_value().unwrap(); /// assert_eq!(cookie_value, "hello".to_owned()); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub fn set_cookie_value(&mut self, cookie_value: String) { self.cookie_value = Some(cookie_value) @@ -361,13 +395,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert_eq!(None, session.expiry()); /// session.expire_in(std::time::Duration::from_secs(1)); /// assert!(session.expiry().is_some()); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub fn expiry(&self) -> Option<&DateTime> { self.expiry.as_ref() @@ -378,13 +413,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert_eq!(None, session.expiry()); /// session.set_expiry(time::OffsetDateTime::now_utc()); /// assert!(session.expiry().is_some()); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub fn set_expiry(&mut self, expiry: DateTime) { self.expiry = Some(expiry); @@ -395,13 +431,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert_eq!(None, session.expiry()); /// session.expire_in(std::time::Duration::from_secs(1)); /// assert!(session.expiry().is_some()); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub fn expire_in(&mut self, ttl: std::time::Duration) { self.expiry = Some(DateTime::now_utc() + ttl); @@ -414,18 +451,19 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; /// # use std::time::Duration; - /// # use async_std::task; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert_eq!(None, session.expiry()); /// assert!(!session.is_expired()); /// session.expire_in(Duration::from_secs(1)); /// assert!(!session.is_expired()); - /// task::sleep(Duration::from_secs(2)).await; + /// tokio::time::sleep(Duration::from_secs(2)).await; /// assert!(session.is_expired()); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn is_expired(&self) -> bool { match self.expiry { @@ -439,24 +477,21 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; /// # use std::time::Duration; - /// # use async_std::task; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let session = Session::new(); /// let mut session = session.validate().unwrap(); /// session.expire_in(Duration::from_secs(1)); /// let session = session.validate().unwrap(); - /// task::sleep(Duration::from_secs(2)).await; + /// tokio::time::sleep(Duration::from_secs(2)).await; /// assert_eq!(None, session.validate()); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn validate(self) -> Option { - if self.is_expired() { - None - } else { - Some(self) - } + if self.is_expired() { None } else { Some(self) } } /// Checks if the data has been modified. This is based on the @@ -465,18 +500,19 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(!session.data_changed(), "new session is not changed"); - /// session.insert("key", 1); + /// session.insert("key", 1)?; /// assert!(session.data_changed()); /// /// session.reset_data_changed(); /// assert!(!session.data_changed()); /// session.remove("key"); /// assert!(session.data_changed()); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn data_changed(&self) -> bool { self.data_changed.load(Ordering::Acquire) @@ -489,39 +525,40 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(!session.data_changed(), "new session is not changed"); - /// session.insert("key", 1); + /// session.insert("key", 1)?; /// assert!(session.data_changed()); /// /// session.reset_data_changed(); /// assert!(!session.data_changed()); /// session.remove("key"); /// assert!(session.data_changed()); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` pub fn reset_data_changed(&self) { self.data_changed.store(false, Ordering::SeqCst); } - /// Ensures that this session is not expired. Returns None if it is expired + /// Duration from now to the expiry time of this session /// /// # Example /// /// ```rust - /// # use async_session::Session; + /// # use saysion::Session; /// # use std::time::Duration; - /// # use async_std::task; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// session.expire_in(Duration::from_secs(123)); /// let expires_in = session.expires_in().unwrap(); /// assert!(123 - expires_in.as_secs() < 2); - /// # Ok(()) }) } + /// # Ok(()) + /// # } /// ``` - /// Duration from now to the expiry time of this session pub fn expires_in(&self) -> Option { let dur = self.expiry? - DateTime::now_utc(); if dur.is_negative() { @@ -537,13 +574,14 @@ impl Session { /// # Example /// /// ```rust - /// # use async_session::Session; - /// # fn main() -> async_session::Result { async_std::task::block_on(async { + /// # use saysion::Session; + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// session.set_cookie_value("hello".to_owned()); /// let cookie_value = session.into_cookie_value().unwrap(); /// assert_eq!(cookie_value, "hello".to_owned()); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub fn into_cookie_value(mut self) -> Option { self.cookie_value.take() diff --git a/tests/test.rs b/tests/test.rs deleted file mode 100644 index 8b13789..0000000 --- a/tests/test.rs +++ /dev/null @@ -1 +0,0 @@ - From bc84c988de3381b6aef4710467cd18c2c617165f Mon Sep 17 00:00:00 2001 From: Chrislearn Young Date: Fri, 2 Jan 2026 18:49:45 +0800 Subject: [PATCH 2/5] w --- Cargo.toml | 14 ++++---------- src/cookie_store.rs | 19 ++++++++++--------- src/lib.rs | 16 ++++------------ src/memory_store.rs | 29 ++++++++++++++++------------- src/session.rs | 14 ++++++++------ src/session_store.rs | 2 +- 6 files changed, 43 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8365fde..5b8bac1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "saysion" -version = "3.0.0" +version = "1.0.0" license = "MIT OR Apache-2.0" repository = "https://github.com/salvo-rs/saysion" documentation = "https://docs.rs/saysion" @@ -21,20 +21,14 @@ rand = "0.9.2" base64 = "0.22.1" sha2 = "0.10.9" hmac = "0.12.1" +serde = { version = "1.0.150", features = ["derive"] } serde_json = "1.0.89" postcard = { version = "1.1.3", default-features = false, features = ["use-std"] } anyhow = "1.0.100" blake3 = "1.8.2" async-lock = "3.4.2" +time = { version = "0.3.17", features = ["serde"] } tracing = "0.1.44" -[dependencies.serde] -version = "1.0.150" -features = ["rc", "derive"] - -[dependencies.time] -version = "0.3.17" -features = ["serde"] - [dev-dependencies] -tokio = { version = "1.36.0", features = ["macros"] } \ No newline at end of file +tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread", "time"] } \ No newline at end of file diff --git a/src/cookie_store.rs b/src/cookie_store.rs index 31b95e3..64dea63 100644 --- a/src/cookie_store.rs +++ b/src/cookie_store.rs @@ -1,4 +1,5 @@ use crate::{Result, Session, SessionStore, async_trait}; +use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; /// A session store that serializes the entire session into a Cookie. /// @@ -32,14 +33,14 @@ impl CookieStore { #[async_trait] impl SessionStore for CookieStore { async fn load_session(&self, cookie_value: String) -> Result> { - let serialized = base64::decode(cookie_value)?; + let serialized = BASE64_STANDARD.decode(cookie_value)?; let session: Session = postcard::from_bytes(&serialized)?; Ok(session.validate()) } async fn store_session(&self, session: Session) -> Result> { let serialized = postcard::to_stdvec(&session)?; - Ok(Some(base64::encode(serialized))) + Ok(Some(BASE64_STANDARD.encode(serialized))) } async fn destroy_session(&self, _session: Session) -> Result { @@ -54,9 +55,9 @@ impl SessionStore for CookieStore { #[cfg(test)] mod tests { use super::*; - use async_std::task; use std::time::Duration; - #[async_std::test] + + #[tokio::test] async fn creating_a_new_session_with_no_expiry() -> Result { let store = CookieStore::new(); let mut session = Session::new(); @@ -71,7 +72,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test] async fn updating_a_session() -> Result { let store = CookieStore::new(); let mut session = Session::new(); @@ -89,7 +90,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test] async fn updating_a_session_extending_expiry() -> Result { let store = CookieStore::new(); let mut session = Session::new(); @@ -107,13 +108,13 @@ mod tests { let session = store.load_session(cookie_value.clone()).await?.unwrap(); assert_eq!(session.expiry().unwrap(), &new_expires); - task::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; assert_eq!(None, store.load_session(cookie_value).await?); Ok(()) } - #[async_std::test] + #[tokio::test] async fn creating_a_new_session_with_expiry() -> Result { let store = CookieStore::new(); let mut session = Session::new(); @@ -129,7 +130,7 @@ mod tests { assert!(!loaded_session.is_expired()); - task::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; assert_eq!(None, store.load_session(cookie_value).await?); Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 7904af9..168fb19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,8 @@ //! ``` //! use saysion::{Session, SessionStore, MemoryStore}; //! -//! # fn main() -> saysion::Result { -//! # async_std::task::block_on(async { +//! # #[tokio::main] +//! # async fn main() -> saysion::Result { //! # //! // Init a new session store we can persist sessions to. //! let mut store = MemoryStore::new(); @@ -29,7 +29,7 @@ //! assert_eq!(session.get::("user_id").unwrap(), 1); //! assert!(!session.data_changed()); //! # -//! # Ok(()) }) } +//! # Ok(()) } //! ``` // #![forbid(unsafe_code, future_incompatible)] @@ -47,6 +47,7 @@ )] pub use anyhow::Error; +pub use async_trait::async_trait; /// An anyhow::Result with default return type of () pub type Result = std::result::Result; @@ -59,12 +60,3 @@ pub use cookie_store::CookieStore; pub use memory_store::MemoryStore; pub use session::Session; pub use session_store::SessionStore; - -pub use async_trait::async_trait; -pub use base64; -pub use blake3; -pub use hmac; -pub use serde; -pub use serde_json; -pub use sha2; -pub use time; diff --git a/src/memory_store.rs b/src/memory_store.rs index 56c49b2..791ba84 100644 --- a/src/memory_store.rs +++ b/src/memory_store.rs @@ -1,7 +1,9 @@ -use crate::{Result, Session, SessionStore, async_trait}; -use async_lock::RwLock; use std::{collections::HashMap, sync::Arc}; +use async_lock::RwLock; + +use crate::{Result, Session, SessionStore, async_trait}; + /// # in-memory session store /// Because there is no external /// persistance, this session store is ephemeral and will be cleared @@ -105,12 +107,13 @@ impl MemoryStore { /// # Example /// ```rust /// # use saysion::{MemoryStore, Session, SessionStore}; - /// # fn main() -> saysion::Result { async_std::task::block_on(async { + /// # #[tokio::main] + /// # async fn main() -> saysion::Result { /// let mut store = MemoryStore::new(); /// assert_eq!(store.count().await, 0); /// store.store_session(Session::new()).await?; /// assert_eq!(store.count().await, 1); - /// # Ok(()) }) } + /// # Ok(()) } /// ``` pub async fn count(&self) -> usize { let data = self.inner.read().await; @@ -121,9 +124,9 @@ impl MemoryStore { #[cfg(test)] mod tests { use super::*; - use async_std::task; use std::time::Duration; - #[async_std::test] + + #[tokio::test] async fn creating_a_new_session_with_no_expiry() -> Result { let store = MemoryStore::new(); let mut session = Session::new(); @@ -138,7 +141,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test] async fn updating_a_session() -> Result { let store = MemoryStore::new(); let mut session = Session::new(); @@ -156,7 +159,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test] async fn updating_a_session_extending_expiry() -> Result { let store = MemoryStore::new(); let mut session = Session::new(); @@ -174,13 +177,13 @@ mod tests { let session = store.load_session(cookie_value.clone()).await?.unwrap(); assert_eq!(session.expiry().unwrap(), &new_expires); - task::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; assert_eq!(None, store.load_session(cookie_value).await?); Ok(()) } - #[async_std::test] + #[tokio::test] async fn creating_a_new_session_with_expiry() -> Result { let store = MemoryStore::new(); let mut session = Session::new(); @@ -196,13 +199,13 @@ mod tests { assert!(!loaded_session.is_expired()); - task::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; assert_eq!(None, store.load_session(cookie_value).await?); Ok(()) } - #[async_std::test] + #[tokio::test] async fn destroying_a_single_session() -> Result { let store = MemoryStore::new(); for _ in 0..3i8 { @@ -221,7 +224,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test] async fn clearing_the_whole_store() -> Result { let store = MemoryStore::new(); for _ in 0..3i8 { diff --git a/src/session.rs b/src/session.rs index 75d6b61..574fa5b 100644 --- a/src/session.rs +++ b/src/session.rs @@ -7,6 +7,7 @@ use std::{ }, }; +use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; use rand::RngCore; use serde::{Deserialize, Serialize}; use time::OffsetDateTime as DateTime; @@ -29,7 +30,8 @@ use time::OffsetDateTime as DateTime; /// ### Change tracking example /// ```rust /// # use saysion::Session; -/// # fn main() -> saysion::Result { async_std::task::block_on(async { +/// # #[tokio::main] +/// # async fn main() -> saysion::Result { /// let mut session = Session::new(); /// assert!(!session.data_changed()); /// @@ -53,7 +55,7 @@ use time::OffsetDateTime as DateTime; /// assert!(!session.data_changed()); /// session.remove("key"); /// assert!(session.data_changed()); -/// # Ok(()) }) } +/// # Ok(()) } /// ``` #[derive(Serialize, Deserialize, Debug)] pub struct Session { @@ -91,8 +93,8 @@ impl Default for Session { /// generates a random cookie value fn generate_cookie(len: usize) -> String { let mut key = vec![0u8; len]; - rand::thread_rng().fill_bytes(&mut key); - base64::encode(key) + rand::rng().fill_bytes(&mut key); + BASE64_STANDARD.encode(key) } impl Session { @@ -144,9 +146,9 @@ impl Session { /// # } /// ``` pub fn id_from_cookie_value(string: &str) -> Result { - let decoded = base64::decode(string)?; + let decoded = BASE64_STANDARD.decode(string)?; let hash = blake3::hash(&decoded); - Ok(base64::encode(hash.as_bytes())) + Ok(BASE64_STANDARD.encode(hash.as_bytes())) } /// mark this session for destruction. the actual session record diff --git a/src/session_store.rs b/src/session_store.rs index 5049dea..6503488 100644 --- a/src/session_store.rs +++ b/src/session_store.rs @@ -1,4 +1,4 @@ -use crate::{async_trait, Result, Session}; +use crate::{Result, Session, async_trait}; /// An async session backend. #[async_trait] From 1e5a1bab82b02ad4d5a5773959e9c96456b5f5b5 Mon Sep 17 00:00:00 2001 From: Chrislearn Young Date: Fri, 2 Jan 2026 18:50:51 +0800 Subject: [PATCH 3/5] w --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 5b8bac1..610df09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ categories = [] authors = [ "Yoshua Wuyts ", "Jacob Rothstein ", + "chrislearn " ] [dependencies] From 272ec264806b756430e51ae9dde83c946fac01ee Mon Sep 17 00:00:00 2001 From: Chrislearn Young Date: Fri, 2 Jan 2026 18:51:41 +0800 Subject: [PATCH 4/5] w --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 610df09..715000a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "saysion" -version = "1.0.0" +version = "0.1.0" license = "MIT OR Apache-2.0" repository = "https://github.com/salvo-rs/saysion" documentation = "https://docs.rs/saysion" From 05e9fdc3444dc5a41f9e1101cbabd3c28778da11 Mon Sep 17 00:00:00 2001 From: Chrislearn Young Date: Fri, 2 Jan 2026 18:55:30 +0800 Subject: [PATCH 5/5] w --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 715000a..a0bcc0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rand = "0.9.2" base64 = "0.22.1" sha2 = "0.10.9" hmac = "0.12.1" -serde = { version = "1.0.150", features = ["derive"] } +serde = { version = "1.0.150", features = ["derive", "rc"] } serde_json = "1.0.89" postcard = { version = "1.1.3", default-features = false, features = ["use-std"] } anyhow = "1.0.100"