From 489e520ddd8181632317ee19c146489d1abd3521 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 15 Jun 2020 15:30:57 +0300 Subject: [PATCH] Add option to resend bridge info to all portals --- mautrix_telegram/__main__.py | 20 +++++++++++++++----- mautrix_telegram/config.py | 1 + mautrix_telegram/db/portal.py | 6 +++++- mautrix_telegram/example-config.yaml | 4 ++++ mautrix_telegram/portal/base.py | 12 ++++++++++-- mautrix_telegram/portal/matrix.py | 4 ++-- mautrix_telegram/portal/metadata.py | 6 +++--- mautrix_telegram/portal/telegram.py | 8 ++++---- 8 files changed, 44 insertions(+), 17 deletions(-) diff --git a/mautrix_telegram/__main__.py b/mautrix_telegram/__main__.py index 3d69241d..29d2f91d 100644 --- a/mautrix_telegram/__main__.py +++ b/mautrix_telegram/__main__.py @@ -31,7 +31,7 @@ from .context import Context from .db import init as init_db from .formatter import init as init_formatter from .matrix import MatrixHandler -from .portal import init as init_portal +from .portal import Portal, init as init_portal from .puppet import Puppet, init as init_puppet from .sqlstatestore import SQLStateStore from .user import User, init as init_user @@ -97,10 +97,20 @@ class TelegramBridge(Bridge): init_abstract_user(context) init_formatter(context) init_portal(context) - puppet_startup = init_puppet(context) - user_startup = init_user(context) - bot_startup = [self.bot.start()] if self.bot else [] - self.startup_actions = chain(puppet_startup, user_startup, bot_startup) + self.add_startup_actions(init_puppet(context)) + self.add_startup_actions(init_user(context)) + if self.bot: + self.add_startup_actions(self.bot.start()) + if self.config["bridge.resend_bridge_info"]: + self.add_startup_actions(self.resend_bridge_info()) + + async def resend_bridge_info(self) -> None: + self.config["bridge.resend_bridge_info"] = False + self.config.save() + self.log.info("Re-sending bridge info state event to all portals") + for portal in Portal.all(): + await portal.update_bridge_info() + self.log.info("Finished re-sending bridge info state events") def prepare_stop(self) -> None: for puppet in Puppet.by_custom_mxid.values(): diff --git a/mautrix_telegram/config.py b/mautrix_telegram/config.py index 503f6c92..5e20e9a8 100644 --- a/mautrix_telegram/config.py +++ b/mautrix_telegram/config.py @@ -111,6 +111,7 @@ class Config(BaseBridgeConfig): copy("bridge.private_chat_portal_meta") copy("bridge.delivery_receipts") copy("bridge.delivery_error_reports") + copy("bridge.resend_bridge_info") copy("bridge.initial_power_level_overrides.group") copy("bridge.initial_power_level_overrides.user") diff --git a/mautrix_telegram/db/portal.py b/mautrix_telegram/db/portal.py index 8fbe1a5a..fa0fd9d1 100644 --- a/mautrix_telegram/db/portal.py +++ b/mautrix_telegram/db/portal.py @@ -13,7 +13,7 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from typing import Optional +from typing import Optional, Iterable from sqlalchemy import Column, Integer, String, Boolean, Text, func, sql @@ -56,3 +56,7 @@ class Portal(Base): @classmethod def get_by_username(cls, username: str) -> Optional['Portal']: return cls._select_one_or_none(func.lower(cls.c.username) == username) + + @classmethod + def all(cls) -> Iterable['Portal']: + yield from cls._select_all() diff --git a/mautrix_telegram/example-config.yaml b/mautrix_telegram/example-config.yaml index f9eca855..283c16ed 100644 --- a/mautrix_telegram/example-config.yaml +++ b/mautrix_telegram/example-config.yaml @@ -219,6 +219,10 @@ bridge: delivery_receipts: false # Whether or not delivery errors should be reported as messages in the Matrix room. delivery_error_reports: false + # Set this to true to tell the bridge to re-send m.bridge events to all rooms on the next run. + # This field will automatically be changed back to false after it, + # except if the config file is not writable. + resend_bridge_info: false # Overrides for base power levels. initial_power_level_overrides: diff --git a/mautrix_telegram/portal/base.py b/mautrix_telegram/portal/base.py index 127cf6fa..830ff5ca 100644 --- a/mautrix_telegram/portal/base.py +++ b/mautrix_telegram/portal/base.py @@ -13,7 +13,7 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from typing import Awaitable, Dict, List, Optional, Tuple, Union, Any, Set, TYPE_CHECKING +from typing import Awaitable, Dict, List, Optional, Tuple, Union, Any, Set, Iterable, TYPE_CHECKING from abc import ABC, abstractmethod import asyncio import logging @@ -372,6 +372,14 @@ class BasePortal(ABC): # endregion # region Class instance lookup + @classmethod + def all(cls) -> Iterable['Portal']: + for db_portal in DBPortal.all(): + try: + yield cls.by_tgid[(db_portal.tgid, db_portal.tg_receiver)] + except KeyError: + yield cls.from_db(db_portal) + @classmethod def get_by_mxid(cls, mxid: RoomID) -> Optional['Portal']: try: @@ -515,7 +523,7 @@ class BasePortal(ABC): pass @abstractmethod - async def _update_bridge_info(self) -> None: + async def update_bridge_info(self) -> None: pass @abstractmethod diff --git a/mautrix_telegram/portal/matrix.py b/mautrix_telegram/portal/matrix.py index b0c77cee..118e0ec7 100644 --- a/mautrix_telegram/portal/matrix.py +++ b/mautrix_telegram/portal/matrix.py @@ -500,7 +500,7 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC): self.title = title self.save() await self._send_delivery_receipt(event_id) - await self._update_bridge_info() + await self.update_bridge_info() async def handle_matrix_avatar(self, sender: 'u.User', url: ContentURI, event_id: EventID ) -> None: @@ -533,7 +533,7 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC): self.save() break await self._send_delivery_receipt(event_id) - await self._update_bridge_info() + await self.update_bridge_info() async def handle_matrix_upgrade(self, sender: UserID, new_room: RoomID, event_id: EventID ) -> None: diff --git a/mautrix_telegram/portal/metadata.py b/mautrix_telegram/portal/metadata.py index eced61d9..863d794e 100644 --- a/mautrix_telegram/portal/metadata.py +++ b/mautrix_telegram/portal/metadata.py @@ -229,7 +229,7 @@ class PortalMetadata(BasePortal, ABC): changed = await self._update_avatar(user, entity.photo) or changed if changed: self.save() - await self._update_bridge_info() + await self.update_bridge_info() if self.sync_matrix_state: await self.sync_matrix_members() @@ -286,7 +286,7 @@ class PortalMetadata(BasePortal, ABC): info["channel"]["external_url"] = f"https://t.me/{puppet.username}" return info - async def _update_bridge_info(self) -> None: + async def update_bridge_info(self) -> None: try: self.log.debug("Updating bridge info...") await self.main_intent.send_state_event(self.mxid, StateBridge, @@ -664,7 +664,7 @@ class PortalMetadata(BasePortal, ABC): if changed: self.save() - await self._update_bridge_info() + await self.update_bridge_info() async def _update_username(self, username: str, save: bool = False) -> bool: if self.username == username: diff --git a/mautrix_telegram/portal/telegram.py b/mautrix_telegram/portal/telegram.py index 4da6be75..fe9ed18d 100644 --- a/mautrix_telegram/portal/telegram.py +++ b/mautrix_telegram/portal/telegram.py @@ -555,13 +555,13 @@ class PortalTelegram(BasePortal, ABC): return if isinstance(action, MessageActionChatEditTitle): await self._update_title(action.title, sender=sender, save=True) - await self._update_bridge_info() + await self.update_bridge_info() elif isinstance(action, MessageActionChatEditPhoto): await self._update_avatar(source, action.photo, sender=sender, save=True) - await self._update_bridge_info() + await self.update_bridge_info() elif isinstance(action, MessageActionChatDeletePhoto): await self._update_avatar(source, ChatPhotoEmpty(), sender=sender, save=True) - await self._update_bridge_info() + await self.update_bridge_info() elif isinstance(action, MessageActionChatAddUser): for user_id in action.users: await self._add_telegram_user(TelegramID(user_id), source) @@ -575,7 +575,7 @@ class PortalTelegram(BasePortal, ABC): # TODO encrypt await sender.intent_for(self).send_emote(self.mxid, "upgraded this group to a supergroup.") - await self._update_bridge_info() + await self.update_bridge_info() elif isinstance(action, MessageActionGameScore): # TODO handle game score pass