80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""
|
|
rChats bridge — relays LXMF and MeshCore messages to/from rChats.
|
|
Messages arriving over mesh are forwarded to rChats internal API.
|
|
Messages from rChats can be sent out over mesh.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import threading
|
|
import time
|
|
|
|
import httpx
|
|
|
|
from .config import RCHATS_BRIDGE_ENABLED, RCHATS_INTERNAL_URL
|
|
|
|
logger = logging.getLogger("rmesh.rchats_bridge")
|
|
|
|
|
|
def init():
|
|
"""Initialize the rChats bridge."""
|
|
if not RCHATS_BRIDGE_ENABLED:
|
|
logger.info("rChats bridge disabled")
|
|
return
|
|
logger.info("rChats bridge enabled — forwarding to %s", RCHATS_INTERNAL_URL)
|
|
|
|
|
|
def on_lxmf_event(event: dict):
|
|
"""Handle LXMF events and forward relevant ones to rChats."""
|
|
if not RCHATS_BRIDGE_ENABLED:
|
|
return
|
|
|
|
event_type = event.get("type", "")
|
|
|
|
if event_type == "lxmf.delivery":
|
|
msg = event.get("message", {})
|
|
_forward_to_rchats(msg, source="reticulum")
|
|
|
|
elif event_type == "meshcore.message":
|
|
msg = event.get("message", {})
|
|
_forward_to_rchats(msg, source="meshcore")
|
|
|
|
|
|
def _forward_to_rchats(msg: dict, source: str):
|
|
"""Forward a mesh message to rChats internal API."""
|
|
space_slug = msg.get("space_slug")
|
|
if not space_slug:
|
|
return # Only forward space-scoped messages
|
|
|
|
payload = {
|
|
"source": source,
|
|
"sender": msg.get("sender_hash", "") or msg.get("sender", ""),
|
|
"content": msg.get("content", ""),
|
|
"title": msg.get("title", ""),
|
|
"has_image": "image" in msg.get("fields", {}),
|
|
"has_audio": "audio" in msg.get("fields", {}),
|
|
"has_files": "file_attachments" in msg.get("fields", {}),
|
|
"space": space_slug,
|
|
"timestamp": msg.get("timestamp", time.time()),
|
|
}
|
|
|
|
threading.Thread(
|
|
target=_post_to_rchats, args=(space_slug, payload), daemon=True
|
|
).start()
|
|
|
|
|
|
def _post_to_rchats(space_slug: str, payload: dict):
|
|
"""POST message to rChats internal mesh-relay endpoint."""
|
|
try:
|
|
url = f"{RCHATS_INTERNAL_URL}/api/internal/mesh-relay"
|
|
with httpx.Client(timeout=10) as client:
|
|
response = client.post(url, json=payload)
|
|
if response.status_code < 400:
|
|
logger.info("Forwarded mesh message to rChats space '%s'", space_slug)
|
|
else:
|
|
logger.warning("rChats rejected message: %d %s", response.status_code, response.text[:100])
|
|
except httpx.ConnectError:
|
|
logger.debug("rChats not reachable at %s", RCHATS_INTERNAL_URL)
|
|
except Exception as e:
|
|
logger.warning("Failed to forward to rChats: %s", e)
|