session_utils.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import redis
  2. import os
  3. import uuid
  4. from datetime import timedelta
  5. # Redis Configuration (Environment variables for production)
  6. REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
  7. REDIS_PORT = int(os.getenv("REDIS_PORT", 6379))
  8. REDIS_DB = int(os.getenv("REDIS_DB", 0))
  9. r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, decode_responses=True)
  10. def create_session(user_id: int, expires_days: int = 365) -> str:
  11. """Create a unique session ID and track it for the user"""
  12. session_id = str(uuid.uuid4())
  13. expiration = timedelta(days=expires_days)
  14. # Save the session mapping
  15. r.setex(f"session:{session_id}", expiration, str(user_id))
  16. # Add to user's active sessions set
  17. r.sadd(f"user_sessions:{user_id}", session_id)
  18. r.expire(f"user_sessions:{user_id}", expiration)
  19. return session_id
  20. def validate_session(session_id: str) -> bool:
  21. """Check if the session ID exists in Redis"""
  22. return r.exists(f"session:{session_id}") == 1
  23. def delete_session(session_id: str):
  24. """Delete a specific session and remove from user tracking"""
  25. user_id = r.get(f"session:{session_id}")
  26. if user_id:
  27. r.srem(f"user_sessions:{user_id}", session_id)
  28. r.delete(f"session:{session_id}")
  29. def delete_all_user_sessions(user_id: int):
  30. """Invalidate ALL active sessions for a user (e.g. after password reset)"""
  31. sessions = r.smembers(f"user_sessions:{user_id}")
  32. if sessions:
  33. for session_id in sessions:
  34. r.delete(f"session:{session_id}")
  35. r.delete(f"user_sessions:{user_id}")
  36. def get_user_id_from_session(session_id: str):
  37. """Retrieve the user_id associated with a session"""
  38. return r.get(f"session:{session_id}")
  39. import time
  40. def track_user_ping(user_id: int):
  41. """Track user online status with 60s expiration"""
  42. r.setex(f"user_ping:{user_id}", 60, str(int(time.time())))
  43. def is_user_online(user_id: int) -> bool:
  44. """Check if user has pinged within the last 60s"""
  45. return r.exists(f"user_ping:{user_id}") == 1