Browse Source

Add bridging for read receipts from Matrix

Tulir Asokan 4 years ago
parent
commit
bc62b69996
4 changed files with 23 additions and 13 deletions
  1. 2 2
      ROADMAP.md
  2. 1 1
      mautrix_signal/__main__.py
  3. 20 9
      mautrix_signal/matrix.py
  4. 0 1
      mautrix_signal/user.py

+ 2 - 2
ROADMAP.md

@@ -15,8 +15,8 @@
   * [ ] Group info changes
   * [ ] Group info changes
     * [ ] Name
     * [ ] Name
     * [ ] Avatar
     * [ ] Avatar
-  * [ ] Typing notifications
-  * [ ] Read receipts
+  * [ ] Typing notifications
+  * [x] Read receipts
 * Signal → Matrix
 * Signal → Matrix
   * [ ] Message content
   * [ ] Message content
     * [x] Text
     * [x] Text

+ 1 - 1
mautrix_signal/__main__.py

@@ -57,11 +57,11 @@ class SignalBridge(Bridge):
         init_db(self.db)
         init_db(self.db)
 
 
     def prepare_bridge(self) -> None:
     def prepare_bridge(self) -> None:
+        self.signal = SignalHandler(self)
         super().prepare_bridge()
         super().prepare_bridge()
         cfg = self.config["appservice.provisioning"]
         cfg = self.config["appservice.provisioning"]
         # self.provisioning_api = ProvisioningAPI(cfg["shared_secret"])
         # self.provisioning_api = ProvisioningAPI(cfg["shared_secret"])
         # self.az.app.add_subapp(cfg["prefix"], self.provisioning_api.app)
         # self.az.app.add_subapp(cfg["prefix"], self.provisioning_api.app)
-        self.signal = SignalHandler(self)
 
 
     async def start(self) -> None:
     async def start(self) -> None:
         await self.db.start()
         await self.db.start()

+ 20 - 9
mautrix_signal/matrix.py

@@ -15,13 +15,15 @@
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 from typing import List, Union, TYPE_CHECKING
 from typing import List, Union, TYPE_CHECKING
 
 
+from mausignald.types import Address
+
 from mautrix.bridge import BaseMatrixHandler
 from mautrix.bridge import BaseMatrixHandler
 from mautrix.types import (Event, ReactionEvent, MessageEvent, StateEvent, EncryptedEvent, RoomID,
 from mautrix.types import (Event, ReactionEvent, MessageEvent, StateEvent, EncryptedEvent, RoomID,
                            EventID, UserID, ReactionEventContent, RelationType, EventType,
                            EventID, UserID, ReactionEventContent, RelationType, EventType,
                            ReceiptEvent, TypingEvent, PresenceEvent, RedactionEvent)
                            ReceiptEvent, TypingEvent, PresenceEvent, RedactionEvent)
 
 
 from .db import Message as DBMessage
 from .db import Message as DBMessage
-from . import commands as com, puppet as pu, portal as po, user as u
+from . import commands as com, puppet as pu, portal as po, user as u, signal as s
 
 
 if TYPE_CHECKING:
 if TYPE_CHECKING:
     from .__main__ import SignalBridge
     from .__main__ import SignalBridge
@@ -29,12 +31,14 @@ if TYPE_CHECKING:
 
 
 class MatrixHandler(BaseMatrixHandler):
 class MatrixHandler(BaseMatrixHandler):
     commands: 'com.CommandProcessor'
     commands: 'com.CommandProcessor'
+    signal: 's.SignalHandler'
 
 
     def __init__(self, bridge: 'SignalBridge') -> None:
     def __init__(self, bridge: 'SignalBridge') -> None:
         prefix, suffix = bridge.config["bridge.username_template"].format(userid=":").split(":")
         prefix, suffix = bridge.config["bridge.username_template"].format(userid=":").split(":")
         homeserver = bridge.config["homeserver.domain"]
         homeserver = bridge.config["homeserver.domain"]
         self.user_id_prefix = f"@{prefix}"
         self.user_id_prefix = f"@{prefix}"
         self.user_id_suffix = f"{suffix}:{homeserver}"
         self.user_id_suffix = f"{suffix}:{homeserver}"
+        self.signal = bridge.signal
 
 
         super().__init__(command_processor=com.CommandProcessor(bridge), bridge=bridge)
         super().__init__(command_processor=com.CommandProcessor(bridge), bridge=bridge)
 
 
@@ -99,15 +103,14 @@ class MatrixHandler(BaseMatrixHandler):
         await portal.handle_matrix_reaction(user, event_id, content.relates_to.event_id,
         await portal.handle_matrix_reaction(user, event_id, content.relates_to.event_id,
                                             content.relates_to.key)
                                             content.relates_to.key)
 
 
-    @staticmethod
-    async def handle_receipt(evt: ReceiptEvent) -> None:
+    async def handle_receipt(self, evt: ReceiptEvent) -> None:
         # These events come from custom puppet syncing, so there's always only one user.
         # These events come from custom puppet syncing, so there's always only one user.
         event_id, receipts = evt.content.popitem()
         event_id, receipts = evt.content.popitem()
         receipt_type, users = receipts.popitem()
         receipt_type, users = receipts.popitem()
         user_id, data = users.popitem()
         user_id, data = users.popitem()
 
 
         user = await u.User.get_by_mxid(user_id, create=False)
         user = await u.User.get_by_mxid(user_id, create=False)
-        if not user or not user.client:
+        if not user or not user.username:
             return
             return
 
 
         portal = await po.Portal.get_by_mxid(evt.room_id)
         portal = await po.Portal.get_by_mxid(evt.room_id)
@@ -118,13 +121,21 @@ class MatrixHandler(BaseMatrixHandler):
         if not message:
         if not message:
             return
             return
 
 
-        # user.log.debug(f"Marking messages in {portal.twid} read up to {message.twid}")
-        # await user.client.conversation(portal.twid).mark_read(message.twid)
+        user.log.trace(f"Sending read receipt for {message.timestamp} to {message.sender}")
+        await self.signal.mark_read(user.username, Address(uuid=message.sender),
+                                    timestamps=[message.timestamp], when=data.ts)
 
 
-    @staticmethod
-    async def handle_typing(room_id: RoomID, typing: List[UserID]) -> None:
-        # TODO implement
+    async def handle_typing(self, room_id: RoomID, typing: List[UserID]) -> None:
         pass
         pass
+        # portal = await po.Portal.get_by_mxid(room_id)
+        # if not portal:
+        #     return
+        #
+        # for user_id in typing:
+        #     user = await u.User.get_by_mxid(user_id, create=False)
+        #     if not user or not user.username:
+        #         continue
+        #     # TODO
 
 
     async def handle_event(self, evt: Event) -> None:
     async def handle_event(self, evt: Event) -> None:
         if evt.type == EventType.ROOM_REDACTION:
         if evt.type == EventType.ROOM_REDACTION:

+ 0 - 1
mautrix_signal/user.py

@@ -50,7 +50,6 @@ class User(DBUser, BaseUser):
         perms = self.config.get_permissions(mxid)
         perms = self.config.get_permissions(mxid)
         self.is_whitelisted, self.is_admin, self.permission_level = perms
         self.is_whitelisted, self.is_admin, self.permission_level = perms
         self.log = self.log.getChild(self.mxid)
         self.log = self.log.getChild(self.mxid)
-        self.client = None
         self.dm_update_lock = asyncio.Lock()
         self.dm_update_lock = asyncio.Lock()
 
 
     @classmethod
     @classmethod