transient.chat/models/cleanup.py

84 lines
2.8 KiB
Python

import threading
import time
from datetime import datetime, timedelta, timezone
from models.state import (
messages,
room_users,
room_passwords,
authorized_room_users,
room_owners,
kicked_users,
user_sessions,
user_ips,
video_state,
)
def cleanup_loop() -> None:
"""Background loop that periodically cleans expired messages, inactive users, and empty rooms."""
while True:
now = datetime.now(timezone.utc)
# 1. Remove chat messages older than 1 hour
message_cutoff = now - timedelta(hours=1)
for room, room_messages in list(messages.items()):
messages[room] = [
msg
for msg in room_messages
if datetime.fromisoformat(msg["timestamp"]) > message_cutoff
]
# 2. Remove inactive users from rooms (after 1 min of silence)
inactive_cutoff = now - timedelta(minutes=1)
for room in list(room_users.keys()):
room_users[room] = {
user: ts
for user, ts in room_users[room].items()
if datetime.fromisoformat(ts) > inactive_cutoff
}
# 3. Clean up on-demand rooms that have become empty
# Rooms exist strictly while active; once empty for over 1 minute, everything vanishes.
for room in list(room_users.keys()):
if not room_users[room]:
messages.pop(room, None)
room_users.pop(room, None)
room_passwords.pop(room, None)
authorized_room_users.pop(room, None)
room_owners.pop(room, None)
kicked_users.pop(room, None)
video_state.pop(room, None)
# Also purge any dangling rooms in room_passwords that have no users
for room in list(room_passwords.keys()):
if room not in room_users or not room_users[room]:
messages.pop(room, None)
room_users.pop(room, None)
room_passwords.pop(room, None)
authorized_room_users.pop(room, None)
room_owners.pop(room, None)
kicked_users.pop(room, None)
video_state.pop(room, None)
# 4. Remove stale user sessions (after 3 days)
user_cutoff = now - timedelta(days=3)
for user, session in list(user_sessions.items()):
if datetime.fromisoformat(session["last_active"]) < user_cutoff:
user_sessions.pop(user, None)
user_ips.pop(user, None)
time.sleep(60)
_cleanup_thread_started = False
def start_cleanup_thread() -> None:
"""Starts daemon thread for ephemeral resource cleanup."""
global _cleanup_thread_started
if _cleanup_thread_started:
return
_cleanup_thread_started = True
thread = threading.Thread(target=cleanup_loop, daemon=True)
thread.start()