Fix bridging and refactor

This commit is contained in:
2025-03-13 17:26:26 +00:00
parent f802b96c24
commit 52506f86a3
14 changed files with 1264 additions and 202 deletions

View File

@@ -7,6 +7,7 @@ import orjson
from django.conf import settings
import aiohttp
import base64
import asyncio
async def start_typing(uuid):
@@ -25,16 +26,71 @@ async def stop_typing(uuid):
async with session.delete(url, json=data) as response:
return await response.text() # Optional: Return response content
async def download_and_encode_base64(file_url, filename, content_type):
"""
Downloads a file from a given URL asynchronously, converts it to Base64,
and returns it in Signal's expected format.
async def send_message_raw(recipient_uuid, text):
Args:
file_url (str): The URL of the file to download.
filename (str): The name of the file.
content_type (str): The MIME type of the file.
Returns:
str | None: The Base64 encoded attachment string in Signal's expected format, or None on failure.
"""
try:
async with aiohttp.ClientSession() as session:
async with session.get(file_url, timeout=10) as response:
if response.status != 200:
# log.error(f"Failed to download file: {file_url}, status: {response.status}")
return None
file_data = await response.read()
base64_encoded = base64.b64encode(file_data).decode("utf-8")
# Format according to Signal's expected structure
return f"data:{content_type};filename={filename};base64,{base64_encoded}"
except aiohttp.ClientError as e:
# log.error(f"Failed to download file: {file_url}, error: {e}")
return None
async def send_message_raw(recipient_uuid, text=None, attachments=[]):
"""
Sends a message using the Signal REST API, ensuring attachment links are not included in the text body.
Args:
recipient_uuid (str): The UUID of the recipient.
text (str, optional): The message to send.
attachments (list, optional): A list of attachment dictionaries with URL, filename, and content_type.
Returns:
int | bool: Timestamp if successful, False otherwise.
"""
url = "http://signal:8080/v2/send"
data = {
"recipients": [recipient_uuid],
"message": text,
"number": settings.SIGNAL_NUMBER,
"base64_attachments": []
}
# Asynchronously download and encode all attachments
tasks = [download_and_encode_base64(att["url"], att["filename"], att["content_type"]) for att in attachments]
encoded_attachments = await asyncio.gather(*tasks)
# Filter out failed downloads (None values)
data["base64_attachments"] = [att for att in encoded_attachments if att]
# Remove the message body if it only contains an attachment link
if text and (text.strip() in [att["url"] for att in attachments]):
#log.info("Removing message body since it only contains an attachment link.")
text = None # Don't send the link as text
if text:
data["message"] = text
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as response:
response_text = await response.text()
@@ -42,11 +98,8 @@ async def send_message_raw(recipient_uuid, text):
if response_status == status.HTTP_201_CREATED:
ts = orjson.loads(response_text).get("timestamp", None)
if not ts:
return False
return ts
else:
return False
return ts if ts else False
return False
async def fetch_signal_attachment(attachment_id):
"""
@@ -95,7 +148,7 @@ async def fetch_signal_attachment(attachment_id):
def download_and_encode_base64(file_url, filename, content_type):
def download_and_encode_base64_sync(file_url, filename, content_type):
"""
Downloads a file from a given URL, converts it to Base64, and returns it in Signal's expected format.
@@ -142,7 +195,7 @@ def send_message_raw_sync(recipient_uuid, text=None, attachments=[]):
# Convert attachments to Base64
for att in attachments:
base64_data = download_and_encode_base64(att["url"], att["filename"], att["content_type"])
base64_data = download_and_encode_base64_sync(att["url"], att["filename"], att["content_type"])
if base64_data:
data["base64_attachments"].append(base64_data)
@@ -161,9 +214,9 @@ def send_message_raw_sync(recipient_uuid, text=None, attachments=[]):
#log.error(f"Failed to send Signal message: {e}")
return False
if response.status_code == 201: # Signal server returns 201 on success
if response.status_code == status.HTTP_201_CREATED: # Signal server returns 201 on success
try:
ts = orjson.loads(response.text).get("timestamp")
ts = orjson.loads(response.text).get("timestamp", None)
return ts if ts else False
except orjson.JSONDecodeError:
return False