Add Redis support for session storage

- Added Redis as optional session storage backend
- SessionManager automatically detects and uses Redis if available
- Falls back to SQL database storage if Redis is not configured
- Added redis>=4.0.0 to requirements.txt
- Configurable via REDIS_HOST, REDIS_PORT, REDIS_DB, REDIS_PASSWORD environment variables
- Maintains same session timeout and functionality
parent 90d3ef94
...@@ -7,3 +7,4 @@ nvidia-ml-py>=12.535.108 ...@@ -7,3 +7,4 @@ nvidia-ml-py>=12.535.108
flash-attn>=2.0.0 flash-attn>=2.0.0
pyinstaller>=5.0.0 pyinstaller>=5.0.0
PyMySQL>=1.0.0 PyMySQL>=1.0.0
redis>=4.0.0
\ No newline at end of file
...@@ -18,37 +18,112 @@ ...@@ -18,37 +18,112 @@
Authentication and session management for Video AI. Authentication and session management for Video AI.
""" """
import os
import time import time
import secrets import secrets
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
from .database import authenticate_user, validate_api_token, create_persistent_session, get_persistent_session, destroy_persistent_session from .database import authenticate_user, validate_api_token, create_persistent_session, get_persistent_session, destroy_persistent_session
# Redis support
try:
import redis
REDIS_AVAILABLE = True
except ImportError:
REDIS_AVAILABLE = False
redis = None
class SessionManager: class SessionManager:
"""Session manager using persistent database storage.""" """Session manager using Redis (if available) or database storage."""
def __init__(self): def __init__(self):
self.session_timeout = 3600 # 1 hour self.session_timeout = 3600 # 1 hour
self.redis_client = None
# Try to connect to Redis
if REDIS_AVAILABLE:
try:
redis_host = os.environ.get('REDIS_HOST', 'localhost')
redis_port = int(os.environ.get('REDIS_PORT', '6379'))
redis_db = int(os.environ.get('REDIS_DB', '0'))
redis_password = os.environ.get('REDIS_PASSWORD')
self.redis_client = redis.Redis(
host=redis_host,
port=redis_port,
db=redis_db,
password=redis_password,
decode_responses=True
)
# Test connection
self.redis_client.ping()
print("Redis session storage enabled")
except (redis.ConnectionError, redis.AuthenticationError):
print("Redis not available, falling back to database storage")
self.redis_client = None
def _use_redis(self) -> bool:
"""Check if Redis is available and should be used."""
return self.redis_client is not None
def create_session(self, user: Dict[str, Any]) -> str: def create_session(self, user: Dict[str, Any]) -> str:
"""Create a new persistent session for user.""" """Create a new session for user."""
if self._use_redis():
return self._create_redis_session(user)
else:
return create_persistent_session(user['id']) return create_persistent_session(user['id'])
def get_session(self, session_id: str) -> Optional[Dict[str, Any]]: def get_session(self, session_id: str) -> Optional[Dict[str, Any]]:
"""Get session data from database.""" """Get session data."""
if self._use_redis():
return self._get_redis_session(session_id)
else:
return get_persistent_session(session_id) return get_persistent_session(session_id)
def destroy_session(self, session_id: str) -> None: def destroy_session(self, session_id: str) -> None:
"""Destroy persistent session.""" """Destroy session."""
if self._use_redis():
self._destroy_redis_session(session_id)
else:
destroy_persistent_session(session_id) destroy_persistent_session(session_id)
def get_user_from_session(self, session_id: str) -> Optional[Dict[str, Any]]: def get_user_from_session(self, session_id: str) -> Optional[Dict[str, Any]]:
"""Get user from persistent session.""" """Get user from session."""
session = self.get_session(session_id) session = self.get_session(session_id)
if session: if session:
return session['user'] return session['user']
return None return None
# Redis-specific methods
def _create_redis_session(self, user: Dict[str, Any]) -> str:
"""Create a session in Redis."""
import json
session_id = secrets.token_hex(32)
session_data = {
'user': user,
'created_at': time.time()
}
self.redis_client.setex(f"session:{session_id}", self.session_timeout, json.dumps(session_data))
return session_id
def _get_redis_session(self, session_id: str) -> Optional[Dict[str, Any]]:
"""Get session from Redis."""
import json
session_data = self.redis_client.get(f"session:{session_id}")
if session_data:
try:
data = json.loads(session_data)
# Check if session is still valid (extend if accessed)
self.redis_client.expire(f"session:{session_id}", self.session_timeout)
return data
except json.JSONDecodeError:
return None
return None
def _destroy_redis_session(self, session_id: str) -> None:
"""Destroy session in Redis."""
self.redis_client.delete(f"session:{session_id}")
# Global session manager instance # Global session manager instance
session_manager = SessionManager() session_manager = SessionManager()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment