Implement XMPP relaying

This commit is contained in:
2025-02-21 21:34:47 +00:00
parent 018d2f87c7
commit 8d2f28f571
17 changed files with 941 additions and 77 deletions

View File

@@ -6,36 +6,23 @@ from rest_framework import status
from django.http import HttpResponse
from core.models import QueuedMessage, Message
import requests
from requests.exceptions import RequestException
import orjson
from django.conf import settings
from core.messaging import natural
import aiohttp
from asgiref.sync import sync_to_async
from core.clients import signalapi
async def start_typing(uuid):
url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
data = {"recipient": uuid}
async with aiohttp.ClientSession() as session:
async with session.put(url, json=data) as response:
return await response.text() # Optional: Return response content
async def stop_typing(uuid):
url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
data = {"recipient": uuid}
async with aiohttp.ClientSession() as session:
async with session.delete(url, json=data) as response:
return await response.text() # Optional: Return response content
async def send_message(db_obj):
recipient_uuid = db_obj.session.identifier.identifier
text = db_obj.text
send = lambda x: send_message_raw(recipient_uuid, x) # returns ts
start_t = lambda: start_typing(recipient_uuid)
stop_t = lambda: stop_typing(recipient_uuid)
send = lambda x: signalapi.send_message_raw(recipient_uuid, x) # returns ts
start_t = lambda: signalapi.start_typing(recipient_uuid)
stop_t = lambda: signalapi.stop_typing(recipient_uuid)
tss = await natural.natural_send_message(
text,
@@ -56,24 +43,3 @@ async def send_message(db_obj):
ts=ts1, # use that time in db
)
async def send_message_raw(recipient_uuid, text):
url = "http://signal:8080/v2/send"
data = {
"recipients": [recipient_uuid],
"message": text,
"number": settings.SIGNAL_NUMBER,
}
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as response:
response_text = await response.text()
response_status = response.status
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

80
core/clients/signalapi.py Normal file
View File

@@ -0,0 +1,80 @@
from rest_framework import status
import requests
from requests.exceptions import RequestException
import orjson
from django.conf import settings
import aiohttp
async def start_typing(uuid):
url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
data = {"recipient": uuid}
async with aiohttp.ClientSession() as session:
async with session.put(url, json=data) as response:
return await response.text() # Optional: Return response content
async def stop_typing(uuid):
url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
data = {"recipient": uuid}
async with aiohttp.ClientSession() as session:
async with session.delete(url, json=data) as response:
return await response.text() # Optional: Return response content
async def send_message_raw(recipient_uuid, text):
url = "http://signal:8080/v2/send"
data = {
"recipients": [recipient_uuid],
"message": text,
"number": settings.SIGNAL_NUMBER,
}
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as response:
response_text = await response.text()
response_status = response.status
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
def send_message_raw_sync(recipient_uuid, text):
"""
Sends a message using the Signal REST API in a synchronous manner.
Args:
recipient_uuid (str): The UUID of the recipient.
text (str): The message to send.
Returns:
int | bool: Timestamp if successful, False otherwise.
"""
url = "http://signal:8080/v2/send"
data = {
"recipients": [recipient_uuid],
"message": text,
"number": settings.SIGNAL_NUMBER,
}
try:
response = requests.post(url, json=data, timeout=10) # 10s timeout for safety
response.raise_for_status() # Raise an error for non-200 responses
except RequestException as e:
return False # Network or request error
if response.status_code == status.HTTP_201_CREATED: # Signal server returns 201 on success
try:
ts = orjson.loads(response.text).get("timestamp")
return ts if ts else False
except orjson.JSONDecodeError:
return False
return False # If response status is not 201