Files
videocall-app/backend/apps/rooms/models.py
september 54a81cbdcf init
2025-09-03 06:51:24 -07:00

224 lines
6.9 KiB
Python

# rooms/models.py - Room management models
import uuid
import string
import secrets
from datetime import timedelta
from django.conf import settings
from django.utils import timezone
class RoomManager:
"""
Manager class for room operations using Redis for temporary storage.
Implements all CRUD operations for video call rooms.
"""
@staticmethod
def _get_redis_client():
"""Get Redis client instance"""
from django.core.cache import cache
return cache
@classmethod
def generate_short_code(cls, length=None):
"""Generate a unique short code for room access"""
length = length or getattr(settings, 'SHORT_CODE_LENGTH', 6)
characters = string.ascii_uppercase + string.digits
# Ensure uniqueness by checking existing codes
cache = cls._get_redis_client()
max_attempts = 100
for _ in range(max_attempts):
code = ''.join(secrets.choice(characters) for _ in range(length))
if not cache.get(f'room_code_{code}'):
return code
raise ValueError("Unable to generate unique short code")
@classmethod
def create_room(cls, creator_ip=None):
"""Create a new video call room"""
cache = cls._get_redis_client()
room_data = {
'room_id': str(uuid.uuid4()),
'short_code': cls.generate_short_code(),
'created_at': timezone.now().isoformat(),
'participants': [],
'is_active': True,
'expires_at': (
timezone.now() +
timedelta(hours=getattr(settings, 'ROOM_EXPIRY_HOURS', 24))
).isoformat(),
'creator_ip': creator_ip,
'max_participants': getattr(settings, 'MAX_PARTICIPANTS_PER_ROOM', 2)
}
# Store room data with expiration
cache.set(
f'room_{room_data["room_id"]}',
room_data,
timeout=getattr(settings, 'ROOM_EXPIRY_HOURS', 24) * 3600
)
# Create code mapping for easy lookup
cache.set(
f'room_code_{room_data["short_code"]}',
room_data["room_id"],
timeout=getattr(settings, 'ROOM_EXPIRY_HOURS', 24) * 3600
)
# Log room creation
from apps.core.models import RoomActivityLog
RoomActivityLog.objects.create(
room_id=room_data["room_id"],
action='created',
ip_address=creator_ip
)
return room_data
@classmethod
def get_room_by_id(cls, room_id):
"""Retrieve room data by room ID"""
cache = cls._get_redis_client()
return cache.get(f'room_{room_id}')
@classmethod
def get_room_by_code(cls, short_code):
"""Retrieve room data by short code"""
cache = cls._get_redis_client()
room_id = cache.get(f'room_code_{short_code}')
if room_id:
return cls.get_room_by_id(room_id)
return None
@classmethod
def join_room(cls, room_identifier, participant_id, participant_ip=None):
"""
Add participant to room.
room_identifier can be either room_id or short_code
"""
cache = cls._get_redis_client()
# Try to get room by ID first, then by code
room_data = cls.get_room_by_id(room_identifier)
if not room_data:
room_data = cls.get_room_by_code(room_identifier)
if not room_data:
return None, "Room not found"
# Check if room is active and not expired
if not room_data.get('is_active', False):
return None, "Room is not active"
expires_at = timezone.datetime.fromisoformat(
room_data['expires_at'].replace('Z', '+00:00')
)
if timezone.now() > expires_at:
cls.delete_room(room_data['room_id'])
return None, "Room has expired"
# Check participant limit
current_participants = room_data.get('participants', [])
max_participants = room_data.get('max_participants', 2)
if len(current_participants) >= max_participants:
return None, "Room is full"
# Add participant if not already in room
if participant_id not in current_participants:
current_participants.append(participant_id)
room_data['participants'] = current_participants
# Update room data
cache.set(
f'room_{room_data["room_id"]}',
room_data,
timeout=getattr(settings, 'ROOM_EXPIRY_HOURS', 24) * 3600
)
# Log participant join
from apps.core.models import RoomActivityLog
RoomActivityLog.objects.create(
room_id=room_data["room_id"],
action='joined',
participant_count=len(current_participants),
ip_address=participant_ip
)
return room_data, "Successfully joined room"
@classmethod
def leave_room(cls, room_id, participant_id):
"""Remove participant from room"""
cache = cls._get_redis_client()
room_data = cls.get_room_by_id(room_id)
if not room_data:
return False
participants = room_data.get('participants', [])
if participant_id in participants:
participants.remove(participant_id)
room_data['participants'] = participants
# Update room data
cache.set(
f'room_{room_id}',
room_data,
timeout=getattr(settings, 'ROOM_EXPIRY_HOURS', 24) * 3600
)
# Log participant leave
from apps.core.models import RoomActivityLog
RoomActivityLog.objects.create(
room_id=room_id,
action='left',
participant_count=len(participants)
)
# Delete room if no participants left
if not participants:
cls.delete_room(room_id)
return True
return False
@classmethod
def delete_room(cls, room_id):
"""Delete room and clean up all associated data"""
cache = cls._get_redis_client()
room_data = cls.get_room_by_id(room_id)
if room_data:
# Remove code mapping
short_code = room_data.get('short_code')
if short_code:
cache.delete(f'room_code_{short_code}')
# Remove room data
cache.delete(f'room_{room_id}')
# Log room deletion
from apps.core.models import RoomActivityLog
RoomActivityLog.objects.create(
room_id=room_id,
action='deleted'
)
return True
return False
@classmethod
def cleanup_expired_rooms(cls):
"""Clean up expired rooms (to be called by scheduled task)"""
# This would typically be implemented as a management command
# or scheduled task using Django-Q or Celery
pass