@@ -37,29 +37,33 @@ pub enum Error {
37
37
Store ( #[ from] session_store:: Error ) ,
38
38
}
39
39
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 {
44
42
// This will be `None` when:
45
43
//
46
44
// 1. We have not been provided a session cookie or have failed to parse it,
47
45
// 2. The store has not found the session.
48
46
//
49
47
// 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 > > ,
53
49
54
50
// A lazy representation of the session's value, hydrated on a just-in-time basis. A
55
51
// `None` value indicates we have not tried to access it yet. After access, it will always
56
52
// contain `Some(Record)`.
57
- record : Arc < Mutex < Option < Record > > > ,
53
+ record : Mutex < Option < Record > > ,
58
54
59
55
// 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 > > ,
61
57
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 > ,
63
67
}
64
68
65
69
impl Session {
@@ -83,12 +87,16 @@ impl Session {
83
87
store : Arc < impl SessionStore > ,
84
88
expiry : Option < Expiry > ,
85
89
) -> 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
+
86
97
Self {
87
- session_id : Arc :: new ( parking_lot:: Mutex :: new ( session_id) ) ,
88
98
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) ,
92
100
}
93
101
}
94
102
@@ -98,13 +106,13 @@ impl Session {
98
106
99
107
#[ tracing:: instrument( skip( self ) , err) ]
100
108
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 ;
102
110
103
111
// Lazily load the record since `None` here indicates we have no yet loaded it.
104
112
if record_guard. is_none ( ) {
105
113
tracing:: trace!( "record not loaded from store; loading" ) ;
106
114
107
- let session_id = * self . session_id . lock ( ) ;
115
+ let session_id = * self . inner . session_id . lock ( ) ;
108
116
* record_guard = Some ( if let Some ( session_id) = session_id {
109
117
match self . store . load ( & session_id) . await ? {
110
118
Some ( loaded_record) => {
@@ -119,7 +127,7 @@ impl Session {
119
127
// be relatively uncommon and as such entering this branch could indicate
120
128
// malicious behavior.
121
129
tracing:: warn!( "possibly suspicious activity: record not found in store" ) ;
122
- * self . session_id . lock ( ) = None ;
130
+ * self . inner . session_id . lock ( ) = None ;
123
131
self . create_record ( )
124
132
}
125
133
}
@@ -212,7 +220,9 @@ impl Session {
212
220
pub async fn insert_value ( & self , key : & str , value : Value ) -> Result < Option < Value > > {
213
221
let mut record_guard = self . get_record ( ) . await ?;
214
222
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 ) ;
216
226
record_guard. data . insert ( key. to_string ( ) , value)
217
227
} else {
218
228
None
@@ -346,7 +356,9 @@ impl Session {
346
356
/// we fail with [`Error::Store`].
347
357
pub async fn remove_value ( & self , key : & str ) -> Result < Option < Value > > {
348
358
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 ) ;
350
362
Ok ( record_guard. data . remove ( key) )
351
363
}
352
364
@@ -386,16 +398,18 @@ impl Session {
386
398
/// # });
387
399
/// ```
388
400
pub async fn clear ( & self ) {
389
- let mut record_guard = self . record . lock ( ) . await ;
401
+ let mut record_guard = self . inner . record . lock ( ) . await ;
390
402
if let Some ( record) = record_guard. as_mut ( ) {
391
403
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 ( ) {
393
405
let mut new_record = self . create_record ( ) ;
394
406
new_record. id = session_id;
395
407
* record_guard = Some ( new_record) ;
396
408
}
397
409
398
- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
410
+ self . inner
411
+ . is_modified
412
+ . store ( true , atomic:: Ordering :: Release ) ;
399
413
}
400
414
401
415
/// Returns `true` if there is no session ID and the session is empty.
@@ -450,13 +464,13 @@ impl Session {
450
464
/// # });
451
465
/// ```
452
466
pub async fn is_empty ( & self ) -> bool {
453
- let record_guard = self . record . lock ( ) . await ;
467
+ let record_guard = self . inner . record . lock ( ) . await ;
454
468
455
469
// N.B.: Session IDs are `None` if:
456
470
//
457
471
// 1. The cookie was not provided or otherwise could not be parsed,
458
472
// 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 ( ) ;
460
474
461
475
let Some ( record) = record_guard. as_ref ( ) else {
462
476
return session_id. is_none ( ) ;
@@ -484,7 +498,7 @@ impl Session {
484
498
/// assert_eq!(id, session.id());
485
499
/// ```
486
500
pub fn id ( & self ) -> Option < Id > {
487
- * self . session_id . lock ( )
501
+ * self . inner . session_id . lock ( )
488
502
}
489
503
490
504
/// Get the session expiry.
@@ -502,7 +516,7 @@ impl Session {
502
516
/// assert_eq!(session.expiry(), None);
503
517
/// ```
504
518
pub fn expiry ( & self ) -> Option < Expiry > {
505
- * self . expiry . lock ( )
519
+ * self . inner . expiry . lock ( )
506
520
}
507
521
508
522
/// Set `expiry` to the given value.
@@ -527,8 +541,10 @@ impl Session {
527
541
/// assert_eq!(session.expiry(), Some(expiry));
528
542
/// ```
529
543
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 ) ;
532
548
}
533
549
534
550
/// Get session expiry as `OffsetDateTime`.
@@ -551,7 +567,7 @@ impl Session {
551
567
/// assert!(session.expiry_date() < expected_expiry.saturating_add(Duration::seconds(1)));
552
568
/// ```
553
569
pub fn expiry_date ( & self ) -> OffsetDateTime {
554
- let expiry = self . expiry . lock ( ) ;
570
+ let expiry = self . inner . expiry . lock ( ) ;
555
571
match * expiry {
556
572
Some ( Expiry :: OnInactivity ( duration) ) => {
557
573
OffsetDateTime :: now_utc ( ) . saturating_add ( duration)
@@ -614,7 +630,7 @@ impl Session {
614
630
/// # });
615
631
/// ```
616
632
pub fn is_modified ( & self ) -> bool {
617
- self . is_modified . load ( atomic:: Ordering :: Acquire )
633
+ self . inner . is_modified . load ( atomic:: Ordering :: Acquire )
618
634
}
619
635
620
636
/// Saves the session record to the store.
@@ -658,9 +674,9 @@ impl Session {
658
674
// In either case, we must create a new session via the store interface.
659
675
//
660
676
// 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 ( ) {
662
678
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 ) ;
664
680
} else {
665
681
self . store . save ( & record_guard) . await ?;
666
682
}
@@ -699,13 +715,13 @@ impl Session {
699
715
/// - If loading from the store fails, we fail with [`Error::Store`].
700
716
#[ tracing:: instrument( skip( self ) , err) ]
701
717
pub async fn load ( & self ) -> Result < ( ) > {
702
- let session_id = * self . session_id . lock ( ) ;
718
+ let session_id = * self . inner . session_id . lock ( ) ;
703
719
let Some ( ref id) = session_id else {
704
720
tracing:: warn!( "called load with no session id" ) ;
705
721
return Ok ( ( ) ) ;
706
722
} ;
707
723
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 ;
709
725
* record_guard = loaded_record;
710
726
Ok ( ( ) )
711
727
}
@@ -738,7 +754,7 @@ impl Session {
738
754
/// - If deleting from the store fails, we fail with [`Error::Store`].
739
755
#[ tracing:: instrument( skip( self ) , err) ]
740
756
pub async fn delete ( & self ) -> Result < ( ) > {
741
- let session_id = * self . session_id . lock ( ) ;
757
+ let session_id = * self . inner . session_id . lock ( ) ;
742
758
let Some ( ref session_id) = session_id else {
743
759
tracing:: warn!( "called delete with no session id" ) ;
744
760
return Ok ( ( ) ) ;
@@ -780,7 +796,7 @@ impl Session {
780
796
pub async fn flush ( & self ) -> Result < ( ) > {
781
797
self . clear ( ) . await ;
782
798
self . delete ( ) . await ?;
783
- * self . session_id . lock ( ) = None ;
799
+ * self . inner . session_id . lock ( ) = None ;
784
800
Ok ( ( ) )
785
801
}
786
802
@@ -829,15 +845,17 @@ impl Session {
829
845
830
846
let old_session_id = record_guard. id ;
831
847
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.
834
850
835
851
self . store
836
852
. delete ( & old_session_id)
837
853
. await
838
854
. map_err ( Error :: Store ) ?;
839
855
840
- self . is_modified . store ( true , atomic:: Ordering :: Release ) ;
856
+ self . inner
857
+ . is_modified
858
+ . store ( true , atomic:: Ordering :: Release ) ;
841
859
842
860
Ok ( ( ) )
843
861
}
0 commit comments