Deduplicate service messages, typing notifications and presence

This commit is contained in:
Tulir Asokan
2018-02-18 12:31:07 +02:00
parent 7b0c58aa27
commit 457df435ac
4 changed files with 85 additions and 29 deletions
+5 -3
View File
@@ -144,13 +144,14 @@ class AbstractUser:
await puppet.intent.mark_read(portal.mxid, message.mxid)
async def update_admin(self, update):
# TODO duplication not checked
portal = po.Portal.get_by_tgid(update.chat_id, peer_type="chat")
if isinstance(update, UpdateChatAdmins):
await portal.set_telegram_admins_enabled(update.enabled)
elif isinstance(update, UpdateChatParticipantAdmin):
await portal.set_telegram_admin(update.user_id)
else:
self.log.warninng("Unexpected admin status update: %s", update)
self.log.warning("Unexpected admin status update: %s", update)
async def update_typing(self, update):
if isinstance(update, UpdateUserTyping):
@@ -161,6 +162,7 @@ class AbstractUser:
await portal.handle_telegram_typing(sender, update)
async def update_others_info(self, update):
# TODO duplication not checked
puppet = pu.Puppet.get(update.user_id)
if isinstance(update, UpdateUserName):
if await puppet.update_displayname(self, update):
@@ -169,7 +171,7 @@ class AbstractUser:
if await puppet.update_avatar(self, update.photo.photo_big):
puppet.save()
else:
self.log.warninng("Unexpected other user info update: %s", update)
self.log.warning("Unexpected other user info update: %s", update)
async def update_status(self, update):
puppet = pu.Puppet.get(update.user_id)
@@ -214,7 +216,7 @@ class AbstractUser:
return
self.log.debug("Handling action %s to %s by %d", update.action, portal.tgid_log,
sender.id)
return portal.handle_telegram_action(self, sender, update.action)
return portal.handle_telegram_action(self, sender, update)
user = sender.tgid if sender else "admin"
if isinstance(original_update, (UpdateEditMessage, UpdateEditChannelMessage)):
+37 -21
View File
@@ -64,6 +64,7 @@ class Portal:
self._dedup = deque()
self._dedup_mxid = {}
self._dedup_action = deque()
if save_to_cache:
if tgid:
@@ -95,36 +96,47 @@ class Portal:
print("BOT PRINT", self.bot)
return self.bot and self.bot.is_in_chat(self.tgid)
def _hash_event(self, event):
if self.peer_type == "channel":
# Message IDs are unique per-channel
return event.id
@staticmethod
def _hash_event(event):
# Non-channel messages are unique per-user (wtf telegram), so we have no other choice than
# to deduplicate based on a hash of the message content.
# The timestamp is only accurate to the second, so we can't rely on solely that either.
hash_content = [event.date.timestamp(), event.message]
if event.fwd_from:
hash_content += [event.fwd_from.from_id, event.fwd_from.channel_id]
elif isinstance(event, Message) and event.media:
try:
hash_content += {
MessageMediaContact: lambda media: [media.user_id],
MessageMediaDocument: lambda media: [media.document.id, media.caption],
MessageMediaPhoto: lambda media: [media.photo.id, media.caption],
MessageMediaGeo: lambda media: [media.geo.long, media.geo.lat],
}[type(event.media)](event.media)
except KeyError:
pass
# The timestamp is only accurate to the second, so we can't rely solely on that either.
if isinstance(event, MessageService):
hash_content = [event.date.timestamp(), event.from_id, event.action]
else:
hash_content = [event.date.timestamp(), event.message]
if event.fwd_from:
hash_content += [event.fwd_from.from_id, event.fwd_from.channel_id]
elif isinstance(event, Message) and event.media:
try:
hash_content += {
MessageMediaContact: lambda media: [media.user_id],
MessageMediaDocument: lambda media: [media.document.id, media.caption],
MessageMediaPhoto: lambda media: [media.photo.id, media.caption],
MessageMediaGeo: lambda media: [media.geo.long, media.geo.lat],
}[type(event.media)](event.media)
except KeyError:
pass
return hashlib.md5("-"
.join(str(a) for a in hash_content)
.encode("utf-8")
).hexdigest()
def is_duplicate_action(self, event):
hash = self._hash_event(event) if self.peer_type != "channel" else event.id
if hash in self._dedup_action:
return True
self._dedup_action.append(hash)
if len(self._dedup_action) > 20:
self._dedup_action.popleft()
return False
def is_duplicate(self, event, mxid=None):
hash = self._hash_event(event)
hash = self._hash_event(event) if self.peer_type != "channel" else event.id
if hash in self._dedup:
return self._dedup_mxid[hash]
@@ -901,7 +913,8 @@ class Portal:
self.db.add(DBMessage(tgid=evt.id, mx_room=self.mxid, mxid=mxid, tg_space=tg_space))
self.db.commit()
async def handle_telegram_action(self, source, sender, action):
async def handle_telegram_action(self, source, sender, update):
action = update.action
if not self.mxid:
create_and_exit = (MessageActionChatCreate, MessageActionChannelCreate)
create_and_continue = (MessageActionChatAddUser, MessageActionChatJoinedByLink)
@@ -911,6 +924,9 @@ class Portal:
if not isinstance(action, create_and_continue):
return
if self.is_duplicate_action(update):
return
# TODO figure out how to see changes to about text / channel username
if isinstance(action, MessageActionChatEditTitle):
if await self.update_title(action.title):