@@ -428,7 +428,8 @@ class AccountBackend {
428428 // try to update old session first
429429 if (oldSession != null ) {
430430 final rs = await withRetryTransaction (_db, (tx) async {
431- final session = await tx.lookupOrNull <UserSession >(oldSession.key);
431+ final session =
432+ await tx.userSessions.lookupOrNull (oldSession.sessionId);
432433 if (session == null ) {
433434 return null ;
434435 }
@@ -462,8 +463,7 @@ class AccountBackend {
462463 throw AuthenticationException .failed ();
463464 }
464465 final data = await withRetryTransaction (_db, (tx) async {
465- final session = await tx.lookupOrNull <UserSession >(
466- _db.emptyKey.append (UserSession , id: sessionId));
466+ final session = await tx.userSessions.lookupOrNull (sessionId);
467467 if (session == null || session.isExpired ()) {
468468 throw AuthenticationException .failed ('Session has been expired.' );
469469 }
@@ -570,36 +570,24 @@ class AccountBackend {
570570 /// Deletes the session entry if it has already expired and
571571 /// clears the related cache too.
572572 Future <UserSession ?> lookupValidUserSession (String sessionId) async {
573- final key = _db.emptyKey.append (UserSession , id: sessionId);
574- final session = await _db.lookupOrNull <UserSession >(key);
573+ final session = await _db.userSessions.lookupOrNull (sessionId);
575574 if (session == null ) {
576575 return null ;
577576 }
578577 if (session.isExpired ()) {
579- await _db.commit (deletes: [key]);
580- await cache.userSessionData (sessionId).purge ();
578+ await _db.userSessions.expire (session.sessionId);
581579 return null ;
582580 }
583581 return session;
584582 }
585583
586- /// Removes the session data from the Datastore and from cache.
587- Future <void > invalidateUserSession (String sessionId) async {
588- final key = _db.emptyKey.append (UserSession , id: sessionId);
589- try {
590- await _db.commit (deletes: [key]);
591- } catch (_) {
592- // ignore if the entity has been already deleted concurrently
584+ /// Deletes sessions associated with a [userId] or [sessionId] .
585+ Future <void > deleteUserSessions ({String ? userId, String ? sessionId}) async {
586+ if (sessionId != null ) {
587+ await _db.userSessions.expire (sessionId);
593588 }
594- await cache.userSessionData (sessionId).purge ();
595- }
596-
597- /// Scans Datastore for all sessions the user has, and invalidates
598- /// them all (by deleting the Datastore entry and purging the cache).
599- Future <void > invalidateAllUserSessions (String userId) async {
600- final query = _db.query <UserSession >()..filter ('userId =' , userId);
601- await for (final session in query.run ()) {
602- await invalidateUserSession (session.sessionId);
589+ if (userId != null ) {
590+ await _db.userSessions.expireAllForUserId (userId);
603591 }
604592 }
605593
@@ -608,9 +596,8 @@ class AccountBackend {
608596 final now = clock.now ().toUtc ();
609597 // account for possible clock skew
610598 final ts = now.subtract (Duration (minutes: 15 ));
611- final query = _db.query <UserSession >()..filter ('expires <' , ts);
612- final count = await _db.deleteWithQuery (query);
613- _logger.info ('Deleted ${count .deleted } UserSession entries.' );
599+ final count = await _db.userSessions.expireAllBeforeTimestamp (ts);
600+ _logger.info ('Deleted $count UserSession entries.' );
614601 }
615602
616603 /// Updates the moderated status of a user.
@@ -644,7 +631,7 @@ class AccountBackend {
644631 tx.insert (mc);
645632 }
646633 });
647- await _expireAllSessions (userId);
634+ await _db.userSessions. expireAllForUserId (userId);
648635 await purgeAccountCache (userId: userId);
649636 }
650637
@@ -661,16 +648,6 @@ class AccountBackend {
661648 }
662649 return query.run ();
663650 }
664-
665- // expire all sessions of a given user from datastore and cache
666- Future <void > _expireAllSessions (String userId) async {
667- final query = _db.query <UserSession >()..filter ('userId =' , userId);
668- final sessionsToDelete = await query.run ().toList ();
669- for (final session in sessionsToDelete) {
670- await _db.commit (deletes: [session.key]);
671- await cache.userSessionData (session.sessionId).purge ();
672- }
673- }
674651}
675652
676653/// Purge [cache] entries for given [userId] .
@@ -682,3 +659,63 @@ Future<void> purgeAccountCache({
682659 cache.publisherPage (userId).purgeAndRepeat (),
683660 ]);
684661}
662+
663+ /// Low-level, narrowly typed data access methods for [UserSession] entity.
664+ extension UserSessionDatastoreDBExt on DatastoreDB {
665+ _UserSessionDataAccess get userSessions => _UserSessionDataAccess (this );
666+ }
667+
668+ extension UserSessionTransactionWrapperExt on TransactionWrapper {
669+ _UserSessionTransactionDataAcccess get userSessions =>
670+ _UserSessionTransactionDataAcccess (this );
671+ }
672+
673+ class _UserSessionDataAccess {
674+ final DatastoreDB _db;
675+
676+ _UserSessionDataAccess (this ._db);
677+
678+ Future <UserSession ?> lookupOrNull (String sessionId) async {
679+ final key = _db.emptyKey.append (UserSession , id: sessionId);
680+ return await _db.lookupOrNull <UserSession >(key);
681+ }
682+
683+ /// Scans Datastore for all sessions the user has, and invalidates
684+ /// them all (by deleting the Datastore entry and purging the cache).
685+ Future <void > expireAllForUserId (String userId) async {
686+ final query = _db.query <UserSession >()..filter ('userId =' , userId);
687+ final sessionsToDelete = await query.run ().toList ();
688+ for (final session in sessionsToDelete) {
689+ await expire (session.sessionId);
690+ }
691+ }
692+
693+ /// Removes the session data from the Datastore and from cache.
694+ Future <void > expire (String sessionId) async {
695+ final key = _db.emptyKey.append (UserSession , id: sessionId);
696+ try {
697+ await _db.commit (deletes: [key]);
698+ } on Exception catch (_) {
699+ // ignore if the entity has been already deleted concurrently
700+ }
701+ await cache.userSessionData (sessionId).purge ();
702+ }
703+
704+ /// Removes the session data that has expiry before [ts] .
705+ Future <int > expireAllBeforeTimestamp (DateTime ts) async {
706+ final query = _db.query <UserSession >()..filter ('expires <' , ts);
707+ final count = await _db.deleteWithQuery (query);
708+ return count.deleted;
709+ }
710+ }
711+
712+ class _UserSessionTransactionDataAcccess {
713+ final TransactionWrapper _tx;
714+
715+ _UserSessionTransactionDataAcccess (this ._tx);
716+
717+ Future <UserSession ?> lookupOrNull (String sessionId) async {
718+ final key = _tx.emptyKey.append (UserSession , id: sessionId);
719+ return await _tx.lookupOrNull <UserSession >(key);
720+ }
721+ }
0 commit comments