Use deterministic event IDs for backfill on hungryserv

This commit is contained in:
Tulir Asokan
2022-11-18 18:59:37 +02:00
parent 7c8cf3cb50
commit 4ca5bfb1ab
4 changed files with 39 additions and 7 deletions
+1 -1
View File
@@ -672,7 +672,7 @@ class AbstractUser(ABC):
if isinstance(update, MessageService):
if isinstance(update.action, MessageActionChannelMigrateFrom):
self.log.trace(
self.log.debug(
"Received %s in %s by %d, unregistering portal...",
update.action,
portal.tgid_log,
+16 -3
View File
@@ -2580,7 +2580,7 @@ class Portal(DBPortal, BasePortal):
self, source: au.AbstractUser, sender: p.Puppet | None, evt: Message
) -> None:
if not self.mxid:
self.log.trace("Ignoring edit to %d as chat has no Matrix room", evt.id)
self.log.debug("Ignoring edit to %d as chat has no Matrix room", evt.id)
return
elif hasattr(evt, "media") and isinstance(evt.media, MessageMediaGame):
self.log.debug("Ignoring game message edit event")
@@ -2892,7 +2892,14 @@ class Portal(DBPortal, BasePortal):
if sender:
await add_member(intent, sender.displayname, sender.avatar_url)
is_bot = sender.is_bot if sender else False
converted = await self._msg_conv.convert(source, intent, is_bot, msg, client=client)
converted = await self._msg_conv.convert(
source,
intent,
is_bot,
msg,
client=client,
deterministic_reply_id=self.bridge.homeserver_software.is_hungry,
)
return converted, intent
async def _wrap_batch_msg(
@@ -2901,6 +2908,7 @@ class Portal(DBPortal, BasePortal):
msg: Message,
converted: putil.ConvertedMessage,
caption: bool = False,
event_id: EventID | None = None,
) -> BatchSendEvent:
if caption:
content = converted.caption
@@ -2917,6 +2925,7 @@ class Portal(DBPortal, BasePortal):
timestamp=int(msg.date.timestamp() * 1000),
content=content,
type=event_type,
event_id=event_id,
)
async def _backfill_messages(
@@ -2940,6 +2949,7 @@ class Portal(DBPortal, BasePortal):
else set()
)
before_first_msg_timestamp = 0
tg_space = self.tgid if self.peer_type == "channel" else source.tgid
async def add_member(intent: IntentAPI, displayname: str, avatar_url: ContentURI) -> None:
if self.bridge.homeserver_software.is_hungry or intent.mxid in added_members:
@@ -2993,7 +3003,10 @@ class Portal(DBPortal, BasePortal):
converted, intent = await self._convert_batch_msg(source, client, msg, add_member)
if converted is None:
continue
events.append(await self._wrap_batch_msg(intent, msg, converted))
d_event_id = None
if self.bridge.homeserver_software.is_hungry:
d_event_id = self._msg_conv.deterministic_event_id(tg_space, msg.id)
events.append(await self._wrap_batch_msg(intent, msg, converted, event_id=d_event_id))
intents.append(intent)
metas.append(msg)
if converted.caption:
@@ -18,6 +18,7 @@ from __future__ import annotations
from typing import Any, NamedTuple
import base64
import codecs
import hashlib
import html
import mimetypes
import unicodedata
@@ -63,6 +64,7 @@ from telethon.utils import decode_waveform
from mautrix.appservice import IntentAPI
from mautrix.types import (
EventID,
EventType,
Format,
ImageInfo,
@@ -150,6 +152,7 @@ class TelegramMessageConverter:
is_bot: bool,
evt: Message,
no_reply_fallback: bool = False,
deterministic_reply_id: bool = False,
client: MautrixTelegramClient | None = None,
) -> ConvertedMessage | None:
if not client:
@@ -180,7 +183,13 @@ class TelegramMessageConverter:
converted.caption.external_url = converted.content.external_url
if self.portal.get_config("caption_in_message"):
self._caption_to_message(converted)
await self._set_reply(source, evt, converted.content, no_fallback=no_reply_fallback)
await self._set_reply(
source,
evt,
converted.content,
no_fallback=no_reply_fallback,
deterministic_id=deterministic_reply_id,
)
return converted
@staticmethod
@@ -227,12 +236,19 @@ class TelegramMessageConverter:
raise ValueError("Portal has invalid peer type")
return base64.b64encode(play_id).decode("utf-8").rstrip("=")
def deterministic_event_id(self, space: TelegramID, msg_id: TelegramID) -> EventID:
hash_content = f"{self.portal.mxid}/telegram/{space}/{msg_id}"
hashed = hashlib.sha256(hash_content.encode("utf-8")).digest()
b64hash = base64.urlsafe_b64encode(hashed).decode("utf-8").rstrip("=")
return EventID(f"${b64hash}:telegram.org")
async def _set_reply(
self,
source: au.AbstractUser,
evt: Message,
content: MessageEventContent,
no_fallback: bool = False,
deterministic_id: bool = False,
) -> None:
if not evt.reply_to:
return
@@ -241,8 +257,11 @@ class TelegramMessageConverter:
if isinstance(evt, Message) and isinstance(evt.peer_id, PeerChannel)
else source.tgid
)
msg = await DBMessage.get_one_by_tgid(TelegramID(evt.reply_to.reply_to_msg_id), space)
reply_to_id = TelegramID(evt.reply_to.reply_to_msg_id)
msg = await DBMessage.get_one_by_tgid(reply_to_id, space)
if not msg or msg.mx_room != self.portal.mxid:
if deterministic_id:
content.set_reply(self.deterministic_event_id(space, reply_to_id))
return
elif not isinstance(content, TextMessageEventContent) or no_fallback:
# Not a text message, just set the reply metadata and return
+1 -1
View File
@@ -3,7 +3,7 @@ python-magic>=0.4,<0.5
commonmark>=0.8,<0.10
aiohttp>=3,<4
yarl>=1,<2
mautrix>=0.18.6,<0.19
mautrix>=0.18.8,<0.19
#telethon>=1.25.4,<1.26
tulir-telethon==1.26.0a10
asyncpg>=0.20,<0.27