Spaces:
Running
Running
| # This file includes the handlers for sending messages from user-to-user. | |
| import json # Import the file format library for data. | |
| import uuid # Imports this library to generate unique UUIDs. | |
| import time # Import this library to check the time. | |
| import asyncio # Imports this library to allow running | |
| # multiple tasks simultaneously. | |
| # Define the handler function to send chat messages. | |
| async def send_chat_message(websocket, auth_data, username, USERS_DB, | |
| CONVERSATIONS_DB, RECENTS_DB, ONLINE_USERS, | |
| OFFLINE_QUEUES_DB, file_lock, conversation_key, | |
| save_conversations_sync, save_recents_sync, | |
| update_recent_chat_entry): | |
| # Initializing important variables. | |
| recipient = auth_data.get("target") | |
| text = auth_data.get("message", "") | |
| sender_display = USERS_DB[username].get("display_name", username) | |
| # Checks if the user isn't in the database somehow. | |
| # e.g: Account deletion, database desync. | |
| if recipient not in USERS_DB: | |
| await websocket.send_text("[-] ERROR: Unable to send message; User not found.") # Send an error emssage alert. | |
| return | |
| # Checks for malicious edits if the text is over 10 000 characters long. | |
| if len(text) > 10000: | |
| text = text[:10000] # Cuts off the text if it detects text over 10 000 chars. | |
| is_online = recipient in ONLINE_USERS # Checks if the recipient is online. | |
| msg_id = str(uuid.uuid4()) # Generates a unique message id. | |
| formatted_message = { # Message format | |
| "id": msg_id, | |
| "sender": username, | |
| "senderDisplayname": sender_display, | |
| "target": recipient, | |
| "message": text, | |
| "timestamp": time.time(), | |
| "status": "delivered" if is_online else "sent" | |
| } | |
| conv_key = conversation_key(username, recipient) # Unique convo string w/ usernames. | |
| # Saves the convo to the local database. | |
| async with file_lock: | |
| if conv_key not in CONVERSATIONS_DB: | |
| CONVERSATIONS_DB[conv_key] = [] | |
| CONVERSATIONS_DB[conv_key].append(formatted_message) | |
| update_recent_chat_entry(username, recipient, text, formatted_message["timestamp"], sender_display) | |
| update_recent_chat_entry(recipient, username, text, formatted_message["timestamp"], sender_display) | |
| await asyncio.to_thread(save_recents_sync) # Syncs the local conversation db to the main database. | |
| outgoing_payload = json.dumps({ | |
| "action": "new_message", | |
| "id": msg_id, | |
| "sender": username, | |
| "senderDisplayname": sender_display, | |
| "message": text, | |
| "timestamp": formatted_message["timestamp"], | |
| "status": formatted_message["status"] | |
| }) | |
| if is_online: | |
| await ONLINE_USERS[recipient].send_text(outgoing_payload) | |
| else: | |
| if recipient not in OFFLINE_QUEUES_DB: | |
| OFFLINE_QUEUES_DB[recipient] = [] | |
| OFFLINE_QUEUES_DB[recipient].append(outgoing_payload) | |
| if username in ONLINE_USERS: | |
| await ONLINE_USERS[username].send_text(json.dumps({ | |
| "action": "recent_chats_updated", | |
| "recent_chats": RECENTS_DB.get(username, []) | |
| })) | |
| if recipient in ONLINE_USERS: | |
| await ONLINE_USERS[recipient].send_text(json.dumps({ | |
| "action": "recent_chats_updated", | |
| "recent_chats": RECENTS_DB.get(recipient, []) | |
| })) | |
| await asyncio.to_thread(save_conversations_sync) | |
| return | |
| async def request_chat_history(auth_data, websocket, username, | |
| conversation_key, CONVERSATIONS_DB): | |
| target_partner = auth_data.get("target") | |
| conv_key = conversation_key(username, target_partner) | |
| history = CONVERSATIONS_DB.get(conv_key, []) | |
| sorted_history = sorted(history, key=lambda x: x.get("timestamp", 0)) | |
| await websocket.send_text(json.dumps({ | |
| "action": "load_history_results", | |
| "results": sorted_history | |
| })) | |
| return | |
| async def mark_seen(auth_data, conversation_key, username, | |
| file_lock, CONVERSATIONS_DB, | |
| save_conversations_sync, ONLINE_USERS): | |
| partner = auth_data.get("target") | |
| conv_key = conversation_key(username, partner) | |
| async with file_lock: | |
| if conv_key in CONVERSATIONS_DB: | |
| for msg in CONVERSATIONS_DB[conv_key]: | |
| if msg.get("sender") == partner and msg.get("status") != "seen": | |
| msg["status"] = "seen" | |
| await asyncio.to_thread(save_conversations_sync) | |
| if partner in ONLINE_USERS: | |
| await ONLINE_USERS[partner].send_text(json.dumps({ | |
| "action": "messages_seen", | |
| "by": username, | |
| "conv_key": conv_key | |
| })) | |
| return |