back-end / funcs /actions /messaging.py
zeegeedee's picture
Upload action handlers.
f75c434 verified
Raw
History Blame Contribute Delete
4.88 kB
# 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