@@ -37,29 +37,33 @@ pub enum Error {
3737 Store ( #[ from] session_store:: Error ) ,
3838}
3939
40- /// A session which allows HTTP applications to associate key-value pairs with
41- /// visitors.
42- #[ derive( Debug , Clone ) ]
43- pub struct Session {
40+ #[ derive( Debug ) ]
41+ struct Inner {
4442 // This will be `None` when:
4543 //
4644 // 1. We have not been provided a session cookie or have failed to parse it,
4745 // 2. The store has not found the session.
4846 //
4947 // Sync lock, see: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use
50- session_id : Arc < parking_lot:: Mutex < Option < Id > > > ,
51-
52- store : Arc < dyn SessionStore > ,
48+ session_id : parking_lot:: Mutex < Option < Id > > ,
5349
5450 // A lazy representation of the session's value, hydrated on a just-in-time basis. A
5551 // `None` value indicates we have not tried to access it yet. After access, it will always
5652 // contain `Some(Record)`.
57- record : Arc < Mutex < Option < Record > > > ,
53+ record : Mutex < Option < Record > > ,
5854
5955 // Sync lock, see: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use
60- expiry : Arc < parking_lot:: Mutex < Option < Expiry > > > ,
56+ expiry : parking_lot:: Mutex < Option < Expiry > > ,
6157
62- is_modified : Arc < AtomicBool > ,
58+ is_modified : AtomicBool ,
59+ }
60+
61+ /// A session which allows HTTP applications to associate key-value pairs with
62+ /// visitors.
63+ #[ derive( Debug , Clone ) ]
64+ pub struct Session {
65+ store : Arc < dyn SessionStore > ,
66+ inner : Arc < Inner > ,
6367}
6468
6569impl Session {
@@ -83,12 +87,16 @@ impl Session {
8387 store : Arc < impl SessionStore > ,
8488 expiry : Option < Expiry > ,
8589 ) -> Self {
90+ let inner = Inner {
91+ session_id : parking_lot:: Mutex :: new ( session_id) ,
92+ record : Mutex :: new ( None ) , // `None` indicates we have not loaded from store.
93+ expiry : parking_lot:: Mutex :: new ( expiry) ,
94+ is_modified : AtomicBool :: new ( false ) ,
95+ } ;
96+
8697 Self {
87- session_id : Arc :: new ( parking_lot:: Mutex :: new ( session_id) ) ,
8898 store,
89- record : Arc :: new ( Mutex :: new ( None ) ) , // `None` indicates we have not loaded from store.
90- expiry : Arc :: new ( parking_lot:: Mutex :: new ( expiry) ) ,
91- is_modified : Arc :: new ( AtomicBool :: new ( false ) ) ,
99+ inner : Arc :: new ( inner) ,
92100 }
93101 }
94102
@@ -98,13 +106,13 @@ impl Session {
98106
99107 #[ tracing:: instrument( skip( self ) , err) ]
100108 async fn get_record ( & self ) -> Result < MappedMutexGuard < Record > > {
101- let mut record_guard = self . record . lock ( ) . await ;
109+ let mut record_guard = self . inner . record . lock ( ) . await ;
102110
103111 // Lazily load the record since `None` here indicates we have no yet loaded it.
104112 if record_guard. is_none ( ) {
105113 tracing:: trace!( "record not loaded from store; loading" ) ;
106114
107- let session_id = * self . session_id . lock ( ) ;
115+ let session_id = * self . inner . session_id . lock ( ) ;
108116 * record_guard = Some ( if let Some ( session_id) = session_id {
109117 match self . store . load ( & session_id) . await ? {
110118 Some ( loaded_record) => {
@@ -119,7 +127,7 @@ impl Session {
119127 // be relatively uncommon and as such entering this branch could indicate
120128 // malicious behavior.
121129 tracing:: warn!( "possibly suspicious activity: record not found in store" ) ;
122- * self . session_id . lock ( ) = None ;
130+ * self . inner . session_id . lock ( ) = None ;
123131 self . create_record ( )
124132 }
125133 }
@@ -212,7 +220,9 @@ impl Session {
212220 pub async fn insert_value ( & self , key : & str , value : Value ) -> Result < Option < Value > > {
213221 let mut record_guard = self . get_record ( ) . await ?;
214222 Ok ( if record_guard. data . get ( key) != Some ( & value) {
215- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
223+ self . inner
224+ . is_modified
225+ . store ( true , atomic:: Ordering :: Release ) ;
216226 record_guard. data . insert ( key. to_string ( ) , value)
217227 } else {
218228 None
@@ -346,7 +356,9 @@ impl Session {
346356 /// we fail with [`Error::Store`].
347357 pub async fn remove_value ( & self , key : & str ) -> Result < Option < Value > > {
348358 let mut record_guard = self . get_record ( ) . await ?;
349- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
359+ self . inner
360+ . is_modified
361+ . store ( true , atomic:: Ordering :: Release ) ;
350362 Ok ( record_guard. data . remove ( key) )
351363 }
352364
@@ -386,16 +398,18 @@ impl Session {
386398 /// # });
387399 /// ```
388400 pub async fn clear ( & self ) {
389- let mut record_guard = self . record . lock ( ) . await ;
401+ let mut record_guard = self . inner . record . lock ( ) . await ;
390402 if let Some ( record) = record_guard. as_mut ( ) {
391403 record. data . clear ( ) ;
392- } else if let Some ( session_id) = * self . session_id . lock ( ) {
404+ } else if let Some ( session_id) = * self . inner . session_id . lock ( ) {
393405 let mut new_record = self . create_record ( ) ;
394406 new_record. id = session_id;
395407 * record_guard = Some ( new_record) ;
396408 }
397409
398- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
410+ self . inner
411+ . is_modified
412+ . store ( true , atomic:: Ordering :: Release ) ;
399413 }
400414
401415 /// Returns `true` if there is no session ID and the session is empty.
@@ -450,13 +464,13 @@ impl Session {
450464 /// # });
451465 /// ```
452466 pub async fn is_empty ( & self ) -> bool {
453- let record_guard = self . record . lock ( ) . await ;
467+ let record_guard = self . inner . record . lock ( ) . await ;
454468
455469 // N.B.: Session IDs are `None` if:
456470 //
457471 // 1. The cookie was not provided or otherwise could not be parsed,
458472 // 2. Or the session could not be loaded from the store.
459- let session_id = self . session_id . lock ( ) ;
473+ let session_id = self . inner . session_id . lock ( ) ;
460474
461475 let Some ( record) = record_guard. as_ref ( ) else {
462476 return session_id. is_none ( ) ;
@@ -484,7 +498,7 @@ impl Session {
484498 /// assert_eq!(id, session.id());
485499 /// ```
486500 pub fn id ( & self ) -> Option < Id > {
487- * self . session_id . lock ( )
501+ * self . inner . session_id . lock ( )
488502 }
489503
490504 /// Get the session expiry.
@@ -502,7 +516,7 @@ impl Session {
502516 /// assert_eq!(session.expiry(), None);
503517 /// ```
504518 pub fn expiry ( & self ) -> Option < Expiry > {
505- * self . expiry . lock ( )
519+ * self . inner . expiry . lock ( )
506520 }
507521
508522 /// Set `expiry` to the given value.
@@ -527,8 +541,10 @@ impl Session {
527541 /// assert_eq!(session.expiry(), Some(expiry));
528542 /// ```
529543 pub fn set_expiry ( & self , expiry : Option < Expiry > ) {
530- * self . expiry . lock ( ) = expiry;
531- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
544+ * self . inner . expiry . lock ( ) = expiry;
545+ self . inner
546+ . is_modified
547+ . store ( true , atomic:: Ordering :: Release ) ;
532548 }
533549
534550 /// Get session expiry as `OffsetDateTime`.
@@ -551,7 +567,7 @@ impl Session {
551567 /// assert!(session.expiry_date() < expected_expiry.saturating_add(Duration::seconds(1)));
552568 /// ```
553569 pub fn expiry_date ( & self ) -> OffsetDateTime {
554- let expiry = self . expiry . lock ( ) ;
570+ let expiry = self . inner . expiry . lock ( ) ;
555571 match * expiry {
556572 Some ( Expiry :: OnInactivity ( duration) ) => {
557573 OffsetDateTime :: now_utc ( ) . saturating_add ( duration)
@@ -614,7 +630,7 @@ impl Session {
614630 /// # });
615631 /// ```
616632 pub fn is_modified ( & self ) -> bool {
617- self . is_modified . load ( atomic:: Ordering :: Acquire )
633+ self . inner . is_modified . load ( atomic:: Ordering :: Acquire )
618634 }
619635
620636 /// Saves the session record to the store.
@@ -658,9 +674,9 @@ impl Session {
658674 // In either case, we must create a new session via the store interface.
659675 //
660676 // Potential ID collisions must be handled by session store implementers.
661- if self . session_id . lock ( ) . is_none ( ) {
677+ if self . inner . session_id . lock ( ) . is_none ( ) {
662678 self . store . create ( & mut record_guard) . await ?;
663- * self . session_id . lock ( ) = Some ( record_guard. id ) ;
679+ * self . inner . session_id . lock ( ) = Some ( record_guard. id ) ;
664680 } else {
665681 self . store . save ( & record_guard) . await ?;
666682 }
@@ -699,13 +715,13 @@ impl Session {
699715 /// - If loading from the store fails, we fail with [`Error::Store`].
700716 #[ tracing:: instrument( skip( self ) , err) ]
701717 pub async fn load ( & self ) -> Result < ( ) > {
702- let session_id = * self . session_id . lock ( ) ;
718+ let session_id = * self . inner . session_id . lock ( ) ;
703719 let Some ( ref id) = session_id else {
704720 tracing:: warn!( "called load with no session id" ) ;
705721 return Ok ( ( ) ) ;
706722 } ;
707723 let loaded_record = self . store . load ( id) . await . map_err ( Error :: Store ) ?;
708- let mut record_guard = self . record . lock ( ) . await ;
724+ let mut record_guard = self . inner . record . lock ( ) . await ;
709725 * record_guard = loaded_record;
710726 Ok ( ( ) )
711727 }
@@ -738,7 +754,7 @@ impl Session {
738754 /// - If deleting from the store fails, we fail with [`Error::Store`].
739755 #[ tracing:: instrument( skip( self ) , err) ]
740756 pub async fn delete ( & self ) -> Result < ( ) > {
741- let session_id = * self . session_id . lock ( ) ;
757+ let session_id = * self . inner . session_id . lock ( ) ;
742758 let Some ( ref session_id) = session_id else {
743759 tracing:: warn!( "called delete with no session id" ) ;
744760 return Ok ( ( ) ) ;
@@ -780,7 +796,7 @@ impl Session {
780796 pub async fn flush ( & self ) -> Result < ( ) > {
781797 self . clear ( ) . await ;
782798 self . delete ( ) . await ?;
783- * self . session_id . lock ( ) = None ;
799+ * self . inner . session_id . lock ( ) = None ;
784800 Ok ( ( ) )
785801 }
786802
@@ -829,15 +845,17 @@ impl Session {
829845
830846 let old_session_id = record_guard. id ;
831847 record_guard. id = Id :: default ( ) ;
832- * self . session_id . lock ( ) = None ; // Setting `None` ensures `save` invokes the store's
833- // `create` method.
848+ * self . inner . session_id . lock ( ) = None ; // Setting `None` ensures `save` invokes the store's
849+ // `create` method.
834850
835851 self . store
836852 . delete ( & old_session_id)
837853 . await
838854 . map_err ( Error :: Store ) ?;
839855
840- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
856+ self . inner
857+ . is_modified
858+ . store ( true , atomic:: Ordering :: Release ) ;
841859
842860 Ok ( ( ) )
843861 }
0 commit comments