From af9d38c534c11eb29b43bc81a0fc7c9f1bd51eaf Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 21 Jan 2018 21:50:56 +0200 Subject: [PATCH] Add Telegram->Matrix presence and typing notifications --- README.md | 4 ++-- mautrix_appservice/intent_api.py | 26 +++++++++++++++++++++++++- mautrix_telegram/portal.py | 3 +++ mautrix_telegram/user.py | 26 ++++++++++++++++++++------ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1e9921d3..023f39e9 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ does not do this automatically. * [ ] Video messages * [ ] Documents * [ ] Message deletions - * [ ] Presence - * [ ] Typing notifications + * [x] Presence + * [x] Typing notifications * [ ] Pinning messages * [ ] Admin status * [ ] Membership actions diff --git a/mautrix_appservice/intent_api.py b/mautrix_appservice/intent_api.py index 5a922bc9..035f8261 100644 --- a/mautrix_appservice/intent_api.py +++ b/mautrix_appservice/intent_api.py @@ -76,6 +76,22 @@ class HTTPAPI(MatrixHttpApi): return self._send("POST", "/createRoom", content) + def set_presence(self, status="online", user=None): + content = { + "presence": status + } + user = user or self.identity + return self._send("PUT", f"/presence/{user}/status", content) + + def set_typing(self, room_id, is_typing=True, timeout=5000, user=None): + content = { + "typing": is_typing + } + if is_typing: + content["timeout"] = timeout + user = user or self.identity + return self._send("PUT", f"/rooms/{room_id}/typing/{user}", content) + class ChildHTTPAPI(HTTPAPI): def __init__(self, user, parent): @@ -137,6 +153,14 @@ class IntentAPI: self._ensure_registered() return self.client.set_display_name(self.mxid, name) + def set_presence(self, status="online"): + self._ensure_registered() + return self.client.set_presence(status) + + def set_typing(self, room_id, is_typing=True, timeout=5000): + self._ensure_joined(room_id) + return self.client.set_typing(room_id, is_typing, timeout) + def create_room(self, alias=None, is_public=False, name=None, topic=None, is_direct=False, invitees=()): self._ensure_registered() @@ -181,7 +205,7 @@ class IntentAPI: membership["content"]["membership"] == "join"] def _ensure_joined(self, room_id, ignore_cache=False): - if ignore_cache and self.memberships.get(room_id, "") == "join": + if not ignore_cache and self.memberships.get(room_id, "") == "join": return self._ensure_registered() try: diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index e37ebd1b..8162c81d 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -85,6 +85,9 @@ class Portal: else: sender.send_message(self.peer, message["body"]) + def handle_telegram_typing(self, user, event): + user.intent.set_typing(self.mxid, is_typing=True) + def handle_telegram_message(self, sender, evt): self.log.debug("Sending %s to %s by %d", evt.message, self.mxid, sender.id) if evt.message: diff --git a/mautrix_telegram/user.py b/mautrix_telegram/user.py index 7c799cea..35e94beb 100644 --- a/mautrix_telegram/user.py +++ b/mautrix_telegram/user.py @@ -15,8 +15,7 @@ # along with this program. If not, see . import traceback from telethon import TelegramClient -from telethon.tl.types import User as UserEntity, Chat as ChatEntity, Channel as ChannelEntity, \ - UpdateShortMessage, UpdateShortChatMessage, Message, UpdateShortSentMessage +from telethon.tl.types import * from telethon.tl.functions.messages import SendMessageRequest from .db import User as DBUser from . import portal as po, puppet as pu @@ -118,9 +117,9 @@ class User: dialogs = self.client.get_dialogs(limit=30) for dialog in dialogs: entity = dialog.entity - if isinstance(entity, UserEntity): + if isinstance(entity, User): continue - elif isinstance(entity, ChatEntity) and entity.deactivated: + elif isinstance(entity, Chat) and entity.deactivated: continue portal = po.Portal.get_by_entity(entity) portal.create_room(self, entity, invites=[self.mxid]) @@ -133,12 +132,27 @@ class User: self.log.exception("Failed to handle Telegram update") def update(self, update): - if isinstance(update, UpdateShortChatMessage): + update_type = type(update) + if update_type == UpdateShortChatMessage: portal = po.Portal.get_by_tgid(update.chat_id, "chat") sender = pu.Puppet.get(update.from_id) - elif isinstance(update, UpdateShortMessage): + elif update_type == UpdateShortMessage: portal = po.Portal.get_by_tgid(update.user_id, "user") sender = pu.Puppet.get(self.tgid if update.out else update.user_id) + elif update_type == UpdateChatUserTyping or update_type == UpdateUserTyping: + if update_type == UpdateUserTyping: + portal = po.Portal.get_by_tgid(update.user_id, "user") + else: + portal = po.Portal.get_by_tgid(update.chat_id, "chat") + sender = pu.Puppet.get(update.user_id) + return portal.handle_telegram_typing(sender, update) + elif update_type == UpdateUserStatus: + puppet = pu.Puppet.get(update.user_id) + if isinstance(update.status, UserStatusOnline): + puppet.intent.set_presence("online") + elif isinstance(update.status, UserStatusOffline): + puppet.intent.set_presence("offline") + return else: self.log.debug("Unhandled update: %s", update) return