From f6b51bf462d8fbfecbe12014591efcdde0672aa6 Mon Sep 17 00:00:00 2001 From: adbenitez Date: Mon, 18 Mar 2024 01:58:21 -0400 Subject: [PATCH] add support for multiple DC groups per gateway and vice versa --- matterdelta/api.py | 66 ++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/matterdelta/api.py b/matterdelta/api.py index 9756877..e82319d 100644 --- a/matterdelta/api.py +++ b/matterdelta/api.py @@ -3,44 +3,43 @@ import base64 import json import logging -import os import tempfile import time +from pathlib import Path from threading import Thread +from typing import Dict, List, Tuple import requests from deltabot_cli import AttrDict, Bot, ViewType mb_config = {} -chat2gateway = {} -gateway2chat = {} +chat2gateway: Dict[Tuple[int, int], List[str]] = {} +gateway2chat: Dict[str, List[Tuple[int, int]]] = {} def init_api(bot: Bot, config_dir: str) -> None: """Load matterbridge API configuration and start listening to the API endpoint.""" - path = os.path.join(config_dir, "config.json") - if os.path.exists(path): - with open(path, encoding="utf-8") as config: + path = Path(config_dir) / "config.json" + if path.exists(): + with path.open(encoding="utf-8") as config: mb_config.update(json.load(config)) + gateways = mb_config.get("gateways", []) - for gateway in mb_config.get("gateways") or []: + for gateway in gateways: chat = (gateway["accountId"], gateway["chatId"]) - gateway2chat[gateway["gateway"]] = chat - chat2gateway[chat] = gateway["gateway"] + gateway2chat.setdefault(gateway["gateway"], []).append(chat) + chat2gateway.setdefault(chat, []).append(gateway["gateway"]) - if len(mb_config.get("gateways") or []): - Thread(target=listen_to_matterbridge, args=(bot,)).start() + if mb_config["api"]["url"] and len(gateways): + Thread(target=listen_to_matterbridge, args=(bot,), daemon=True).start() def dc2mb(bot: Bot, accid: int, msg: AttrDict) -> None: """Send a Delta Chat message to the matterbridge side.""" - gateway = chat2gateway.get((accid, msg.chat_id)) - if gateway: - if not msg.text and not msg.file: # ignore buggy empty messages - return - api_url = mb_config["api"]["url"] - token = mb_config["api"].get("token", "") - headers = {"Authorization": f"Bearer {token}"} if token else None + if not msg.text and not msg.file: # ignore buggy empty messages + return + gateways = chat2gateway.get((accid, msg.chat_id), []) + if gateways: username = ( msg.override_sender_name or bot.rpc.get_contact(accid, msg.sender.id).display_name @@ -60,23 +59,32 @@ def dc2mb(bot: Bot, accid: int, msg: AttrDict) -> None: QUOTENICK=quotenick, QUOTEMESSAGE=" ".join(msg.quote.text.split()), ) - data = {"gateway": gateway, "username": username, "text": text, "event": event} + data = {"username": username, "text": text, "event": event} if msg.file: with open(msg.file, mode="rb") as attachment: enc_data = base64.standard_b64encode(attachment.read()).decode() data["Extra"] = { "file": [{"Name": msg.file_name, "Data": enc_data, "Comment": text}] } - logging.debug("DC->MB %s", data) - requests.post(api_url + "/api/message", json=data, headers=headers, timeout=60) + api_url = mb_config["api"]["url"] + token = mb_config["api"].get("token", "") + headers = {"Authorization": f"Bearer {token}"} if token else None + for gateway in gateways: + data["gateway"] = gateway + logging.debug("DC->MB %s", data) + if api_url: + requests.post( + api_url + "/api/message", json=data, headers=headers, timeout=60 + ) + mb2dc(bot, data, (accid, msg.chat_id)) -def mb2dc(bot: Bot, msg: dict) -> None: +def mb2dc(bot: Bot, msg: dict, exclude: tuple[int, int] = (0, 0)) -> None: """Send a message from matterbridge to the bridged Delta Chat group""" if msg["event"] not in ("", "user_action"): return - accid, chat_id = gateway2chat.get(msg["gateway"]) or (0, 0) - if not accid or not chat_id: + chats = [c for c in gateway2chat.get(msg["gateway"], []) if c != exclude] + if not chats: return text = msg.get("text") or "" if msg["event"] == "user_action": @@ -90,15 +98,17 @@ def mb2dc(bot: Bot, msg: dict) -> None: if text == file["Name"]: text = "" with tempfile.TemporaryDirectory() as tmp_dir: - reply["file"] = os.path.join(tmp_dir, file["Name"]) + reply["file"] = str(Path(tmp_dir, file["Name"])) data = base64.decodebytes(file["Data"].encode()) with open(reply["file"], mode="wb") as attachment: attachment.write(data) if file["Name"].endswith((".tgs", ".webp")): reply["viewtype"] = ViewType.STICKER - bot.rpc.send_msg(accid, chat_id, reply) + for accid, chat_id in chats: + bot.rpc.send_msg(accid, chat_id, reply) elif text: - bot.rpc.send_msg(accid, chat_id, reply) + for accid, chat_id in chats: + bot.rpc.send_msg(accid, chat_id, reply) def listen_to_matterbridge(bot: Bot) -> None: @@ -118,5 +128,5 @@ def listen_to_matterbridge(bot: Bot) -> None: mb2dc(bot, msg) time.sleep(1) except Exception as ex: # pylint: disable=W0703 - time.sleep(5) logging.exception(ex) + time.sleep(15)