import time from threading import Thread from django.conf import settings from django.contrib.auth import logout from django.contrib.auth.models import AnonymousUser from rest_framework import generics from rest_framework import status from rest_framework.response import Response from common.sessions.cache import user_session_manager from common.utils import get_logger __all__ = ['UserSessionApi'] logger = get_logger(__name__) class UserSessionManager: def __init__(self, request): self.request = request self.session = request.session def connect(self): user_session_manager.add_or_increment(self.session.session_key) def disconnect(self): user_session_manager.decrement(self.session.session_key) if self.should_delete_session(): thread = Thread(target=self.delay_delete_session) thread.start() def should_delete_session(self): return (self.session.modified or settings.SESSION_SAVE_EVERY_REQUEST) and \ not self.session.is_empty() and \ self.session.get_expire_at_browser_close() and \ not user_session_manager.check_active(self.session.session_key) def delay_delete_session(self): timeout = 6 check_interval = 0.5 start_time = time.time() while time.time() - start_time < timeout: time.sleep(check_interval) if user_session_manager.check_active(self.session.session_key): return logout(self.request) class UserSessionApi(generics.RetrieveDestroyAPIView): permission_classes = () def retrieve(self, request, *args, **kwargs): if isinstance(request.user, AnonymousUser): return Response(status=status.HTTP_403_FORBIDDEN) UserSessionManager(request).connect() return Response(status=status.HTTP_200_OK, data={'ok': True}) def destroy(self, request, *args, **kwargs): if isinstance(request.user, AnonymousUser): return Response(status=status.HTTP_403_FORBIDDEN) UserSessionManager(request).disconnect() return Response(status=status.HTTP_200_OK, data={'ok': True})